0

C で小さな Web プロキシを作成しようとしています。まず、サーバーに GET フレームを送信して、Web ページを取得しようとしています。何を見逃したのかわかりませんが、応答がありません。このコードに欠けているものを見つけるのを手伝っていただければ幸いです。

int main (int argc, char** argv) {
   int cache_size,     //size of the cache in KiB
       port,
       port_google = 80,
       dir,
       mySocket,
       socket_google;

   char google[] = "www.google.es", ip[16];
   struct sockaddr_in socketAddr;
   char buffer[10000000];

   if (GetParameters(argc,argv,&cache_size,&port) != 0)
       return -1;

   GetIP (google, ip);
   printf("ip2 = %s\n",ip);

   dir = inet_addr (ip);
   printf("ip3 = %i\n",dir);

   /* Creation of a socket with Google */
   socket_google = conectClient (port_google, dir, &socketAddr);
   if (socket_google < 0) return -1;
   else printf("Socket created\n");

   sprintf(buffer,"GET /index.html HTTP/1.1\r\n\r\n");
   if (write(socket_google, (void*)buffer, MESSAGE_LENGTH+1) < 0 )
       return 1;
   else printf("GET frame sent\n");

   strcpy(buffer,"\n");
   read(socket_google, buffer, sizeof(buffer));

   // strcpy(message,buffer);
   printf("%s\n", buffer);

   return 0;
}

これは、ソケットを作成するために使用するコードです。この部分は大丈夫だと思いますが、念のためコピペしておきます。

int conectClient (int puerto, int direccion, struct sockaddr_in *socketAddr) {
   int mySocket;
   char error[1000];

   if ( (mySocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
       printf("Error when creating the socket\n");
       return -2;
   }

   socketAddr->sin_family = AF_INET;
   socketAddr->sin_addr.s_addr = direccion;
   socketAddr->sin_port = htons(puerto);

   if (connect (mySocket, (struct sockaddr *)socketAddr,sizeof (*socketAddr)) == -1) {
       snprintf(error, sizeof(error), "Error in %s:%d\n", __FILE__, __LINE__);
       perror(error);
       printf("%s\n",error);
       printf ("-- Error when stablishing a connection\n");
       return -1;
   }
   return mySocket;
}

ありがとう!

4

3 に答える 3

2

write(2)まず、呼び出しが実際にソケットに書き込んだバイト数をチェックしていません。呼び出しの戻り値がそれを示しています。についても同じですread(2)。TCP ソケットは双方向ストリームであるため、原則として、予想されるバイト数が転送されるか、EOF読み取られる ( からのゼロ リターンread(2))、またはエラーが発生する (いずれかを読み取るときにチェックしていない)まで、常にループ内で両方を実行します。 .

次に、HTTP はかなり複雑なプロトコルです。RFC 2616、特にアプリケーション レベルの接続管理と転送エンコーディングに精通してください。

編集 0:

うーん、「単純な」プロキシなどというものはありません。複数の接続 (少なくともクライアントからプロキシへ、およびプロキシからサーバーへ) を管理する必要があるため、select(2)/ poll(2)/ epoll(4)/ I/Oを多重化kqueue(2)できるシステム コールのファミリーを検討するのが最善です。これは通常、ノンブロッキングソケットと組み合わされます。のようなヘルパー ライブラリを調べます。これがnginxのような優れた Web サーバー/プロキシでどのように行われるかを見てください。発見することがたくさんあるように聞こえますが、心配しないでください。楽しいです :)libevent

于 2010-12-30T20:16:10.867 に答える
1

ルーチンを投稿していないためGetIP、ホスト名のルックアップが正しいかどうかはわかりません。見た目からすると、inet_addr関数を正しく使用しているかどうかわかりません。

Nikolai はいくつかの非常に良い点を指摘してくれました (そして私も完全に同意します)。実際、あなたGETの要求は実際には壊れており、自分のシステムのローカル Apache Web サーバーでテストしていましたが、機能しませんでした。

sprintf(buffer,"GET /index.html HTTP/1.1\r\n\r\n");
if (write(socket_google, (void*)buffer, LONGITUD_MSJ+1) < 0 )
    return 1;
else printf("GET frame sent\n");
...

strcpy(buffer,"\n");
read(socket_google, buffer, sizeof(buffer));

に置き換える必要があります

  snprintf(buffer, sizeof(buffer), 
      "GET / HTTP/1.1\r\nHost: %s\r\nUser-Agent: TEST 0.1\r\n\r\n", 
      google);

  if (write(socket_google, buffer, strlen(buffer)+1) < 0 ) {
      close(socket_google);
      return 1;
  } else 
      printf("GET frame sent\n");
  ...

  buffer[0] = '\0';
  /* Read message from socket */
  bytes_recv = read(socket_google, buffer, sizeof(buffer));
  if (bytes_recv < 0) {
       fprintf(stderr, "socket read error: %s\n", strerror(errno));
       close(socket_google);
       exit(10);
  }

  buffer[bytes_recv] = '\0';    /* NUL character */

  /* strcpy(message,buffer); */
  printf("%s\n", buffer);

  ...

closeプログラムを終了する前にソケットも必要です。コンパイラの標準 C89/90 または C99 モード ( -std=c99gcc など) を有効にし、警告 (gcc など) を有効-Wallにして、それらを読み取ります。そして#include、関数プロトタイプに必要なヘッダー ファイル (私の場合は Linux を想定):

 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <errno.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>      /* for gethostbyname() */

ホスト名/IP アドレスの解決に関して、ポインターとs のキャストがいくつかあります。これは、混乱を招き、間違いを犯しやすい場所になる可能性があるため、期待どおりに機能していることを確認してください。struct

 in_addr_t ip;
 ...

 GetIP(google, &ip);   /* I changed the parameters */
 printf("IP address = %x (%s)\n", 
     ip, 
     inet_ntoa(*((struct in_addr*)&ip)));
于 2010-12-30T22:37:02.283 に答える
1

実際、rzsocket link というライブラリを使用して、小さな Web プロキシを実装しています。

Web プロキシを実装するときに私が見つけた最も難しいことの 1 つは、おそらくこれもあなたの問題かもしれませんが、プロキシを適切に機能させるために、キープアライブ設定を false に設定する必要があったことです。FireFox でこれを行う 1 つの方法は、about:configアドレスにアクセスし、値をnetwork.http.proxy.keep-aliveto に設定することfalseです。

于 2011-06-25T03:06:57.670 に答える