コンピュータを楽しもう!!

今、自分が面白くていろいろやってみたことを書き綴りたいと思います。連絡先はtarosa.yでgmail.comです。

WiFi経由のhttpの改善

WiFi経由で画像を取り込むプログラムを作っているときに、httpプロトコルのプログラムを改善して、もう少し応用がきくようにしてみました。

httpプログラム改造版

改造版を下記に示します。

//**************************************************
//  HttpFileGet構造体の初期化
//**************************************************
void  HttpFileGetIni( void )
{
  HttpHeader.RecvTime = 2000000L;
  HttpHeader.Portnum = 80;
  HttpHeader.Get = NULL;
  HttpHeader.Host = NULL;
  HttpHeader.UserAgent = NULL;
  HttpHeader.Referer = NULL;
}

初期化では、待ちタイム2秒とポートを80に設定しています。下記のHttpFileGet()を呼ぶ前に変更すれば、そのポートにアクセスします。
HttpFileGet()は、取得したデータを保存するファイルのファイルポインタ以外に、引数として、ヘッダファイルと接続ホスト名を持たせました。ホスト名がNULLのときは、HttpHeader.Hostを参照します。
また、headerファイルポインタがNULLで無いときには、このファイルをhttpプロトコルとして転送します。この機能を利用すると、汎用的にHttpFileGet()が使えます。これらは、昨日、NDS Program RoomにアップしたDS時計プログラムにソースが含まれています。

//**************************************************
//  指定httpサーバから指定ファイルを取得します
//  false:取得失敗 true:成功
//**************************************************
bool  HttpFileGet( FILE *fpd, FILE *header, char *host )
{
char  toptext[512];
int    i, j;
long  recvd_len;
int    ret = false;

  if( host==NULL ){  host = HttpHeader.Host;  }  //header使用の場合は、HttpHeader.Host==NULLもありえます

  if( header==NULL ){
    //********** http GET コマンド生成 **********
    strcpy( toptext, "GET " );
    strcat( toptext, HttpHeader.Get );
    strcat( toptext, " HTTP/1.1\r\n" );
    strcat( toptext, "Host: " );
    strcat( toptext, HttpHeader.Host );
    strcat( toptext, "\r\n" );
    strcat( toptext, "User-Agent: " );
    strcat( toptext, HttpHeader.UserAgent );
    strcat( toptext, "\r\n" );
    strcat( toptext, "Referer: " );
    strcat( toptext, HttpHeader.Referer );
    strcat( toptext, "\r\n" );
    strcat( toptext, "\r\n" );
    //*******************************************
  }
  else{
    fseek( header, 0, SEEK_END );
    recvd_len = ftell( header );
    rewind( header );
    if( recvd_len>511 ){  recvd_len = 511;  }
    fread( toptext, recvd_len, sizeof(char), header );
    toptext[recvd_len] = 0;
  }
  
  //ShinoUpPrintBox( SubScreenA, (u8 *)toptext, 42, RGB(31,31,31), RGB(0,0,0), 1, RGB(0,0,0) );
  
  //メモリの確保
  char *incoming_buffer = (char*)malloc( sizeof(char*) * HTTPGETDATASIZE );
  if(incoming_buffer==NULL ){
    ShinoUpPrint( SubScreenA, (u8 *)"Malloc Error", RGB(31,0,0),RGB(0,0,0), 1,RGB(0,0,0) );
    return( false );
  }

    // サーバのIPアドレスを検索します
    struct hostent * myhost = gethostbyname( host );

    //TCPソケットの生成
    int my_socket = socket( AF_INET, SOCK_STREAM, 0 );

    //ホストに接続するため、指定IPアドレスの指定ポートに接続します。
    struct sockaddr_in sain;
    sain.sin_family = AF_INET;
    sain.sin_port = htons( HttpHeader.Portnum );              //ポート指定
    sain.sin_addr.s_addr= *( (unsigned long *)(myhost->h_addr_list[0]) );  //IP指定
    connect( my_socket,(struct sockaddr *)&sain, sizeof(sain) );

    //接続先にファイル取得リクエストを飛ばします
    send( my_socket, toptext, strlen(toptext), 0 );

  //データ取得
  recvd_len = getRecvData( my_socket, incoming_buffer, HTTPGETDATASIZE, 0, HttpHeader.RecvTime );

  //recvd_lenが-1だったり、返事が 200 OK であるかどうか調べる
  if( strexist( incoming_buffer, (char *)"200", 20)==true && strexist( incoming_buffer, (char *)"OK", 20)==true
    && recvd_len>0 ){
    //*** メッセージの送受信成功 ***
    //最初のパケットが"HTTP/1.x 200 OK"のみかどうか調べます
    if( recvd_len<=15 ){
      //15バイト以下だったら再読み込みする
      recvd_len = getRecvData( my_socket, incoming_buffer, HTTPGETDATASIZE, 0, HttpHeader.RecvTime );
    }
    //[0x0D][0x0A][0x0D][0x0A]の4バイトを探す
    for( j=0; j<recvd_len-3; j++ ){
      if( incoming_buffer[j]==0x0d && incoming_buffer[j+1]==0x0a 
        && incoming_buffer[j+2]==0x0d && incoming_buffer[j+3]==0x0a ){
        //見つかった
        for( i=j+4; i<recvd_len; i++ ){
          incoming_buffer[i-(j+4)] = incoming_buffer[i];
        }
        recvd_len -= (j+4);
        break;
      }
    }
    ret = true;
  }

  //*** 受信データを保存 ***
  fwrite( incoming_buffer, recvd_len, sizeof(char), fpd );
    
  //データサイズが0になるまで、データを取得します
  while( ( recvd_len = getRecvData( my_socket, incoming_buffer, HTTPGETDATASIZE, 0, HttpHeader.RecvTime ) ) != 0 ){
    if( recvd_len>0 ){
      swiWaitForVBlank();  
      fwrite( incoming_buffer, recvd_len, sizeof(char), fpd );
    }
  }

  //メモリの開放
  free( incoming_buffer );
  
  //ソケットをシャットダウンします
  shutdown(my_socket,0);

  //少し間をおく(こうしないとソケットが切れない・・・)
  for( i=0; i<20; i++ ){  swiWaitForVBlank();  }
  
  //ソケットを閉じます
  closesocket( my_socket );

  return( ret );
}

HttpFileGet応用例

先ほど、下記のようなヘッダを作り、DSからtwitterのIDに発言してみました。

POST /statuses/update.xml?status=TEST HTTP/1.1
Host: twitter.com
User-Agent: Nintendo DS
Referer: http://twitter.com/
Authorization: Basic =======秘=密=======

このヘッダをHttpFileGet()で送信してやると、OKとxmlファイルが戻ってきて、無事、twitterにTESTと発言できました。
興味のある方は、色々と試してみてください。DSボットを作ろうかな・・・。

今日はこの辺で・・・。

本当にやりたいことリスト

(ブログの終わりにやりたいことを書いておきたいと思います)

  • 求職活動・・・このブログで興味を持った人一声かけてください。m(_ _)m
  • Androidプログラム
  • Web系のプログラム