如何用 C 创建一个简单的代理来访问 Web 服务器

发布于 2024-10-10 09:43:58 字数 1906 浏览 8 评论 0原文

我正在尝试用 C 创建一个小型 Web 代理。首先,我尝试获取一个网页,将 GET 帧发送到服务器。 我不知道我错过了什么,但我没有收到任何回复。如果您能帮助我找到这段代码中缺少的内容,我将非常感激。

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;
}

谢谢!

I’m trying to create an small Web Proxy in C. First, I’m trying to get a webpage, sending a GET frame to the server.
I don’t know what I have missed, but I am not receiving any response. I would really appreciate if you can help me to find what is missing in this code.

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;
}

And this is the code I use to create the socket. I think this part is OK, but I copy it just in case.

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;
}

Thanks!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

十秒萌定你 2024-10-17 09:43:58

首先,您没有检查 有多少字节write(2) 调用实际上写入了套接字。调用的返回值告诉您这一点。与 read(2)< 相同/代码>。 TCP 套接字是双向流,因此通常总是在循环中执行这两项操作,直到传输预期数量的字节,读取 EOF(从 read(2) 返回零) code>),或者发生错误(您在阅读时也没有检查)。

那么HTTP是一个相当复杂的协议。让自己熟悉 RFC 2616,特别是应用程序级连接管理和传输编码。

编辑 0:

嗯,不存在“简单”代理这样的东西。您需要管理多个连接(至少是客户端到代理和代理到服务器),因此最好查看 select(2)/poll(2)/epoll(4)/kqueue(2) 系列系统调用,其中允许您多路传输输入/输出。这通常与非阻塞套接字结合使用。查看 libevent 等帮助程序库。看看在良好的网络服务器/代理(如 nginx)中这是如何完成的。听起来好像有很多东西需要你去发现,但别担心,这很有趣:)

First, you're not checking how many bytes the write(2) call actually wrote to the socket. The return value of the call tells you that. Same for the read(2). TCP socket is a bi-directional stream, so as a rule always do both in a loop until expected number of bytes is transferred, EOF is read (zero return from read(2)), or an error occurred (which you are not checking for when reading either).

Then HTTP is rather complex protocol. Make yourself familiar with RFC 2616, especially application level connection management and transfer encodings.

Edit 0:

Hmm, there's no such thing as "simple" proxy. You need to manage multiple connections (at least client-to-proxy and proxy-to-server), so it's probably best to look into select(2)/poll(2)/epoll(4)/kqueue(2) family of system call, which allow you to multiplex I/O. This is usually combined with non-blocking sockets. Look into helper libraries like libevent. Look at how this is done in good web-servers/proxies like nginx. Sound like it's a lot for you to discover, but don't worry, it's fun :)

江南月 2024-10-17 09:43:58

由于您没有发布 GetIP 例程,我不确定您的主机名查找是否正确,因为从外观上看,我不确定您是否使用 inet_addr 功能正常。

尼古拉指出了一些非常好的观点(我完全同意)。事实上,您的 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 模式(例如 gcc 的 -std=c99)并启用警告(例如 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() */

关于指针和struct有一些转换主机名/IP 地址解析,这可能会令人困惑且容易出错,因此请验证其是否按您的预期工作。

 in_addr_t ip;
 ...

 GetIP(google, &ip);   /* I changed the parameters */
 printf("IP address = %x (%s)\n", 
     ip, 
     inet_ntoa(*((struct in_addr*)&ip)));

Since you didn't post the GetIP routine, I am not certain that your hostname lookup is correct, as from the looks of it, I am not sure that you are using inet_addr function correctly.

Nikolai has pointed out some very good points (and I fully agree). In fact you GET request is actually broken, and while I was testing it on my own local Apache web server on my system, it didn't work.

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));

should be replaced with

  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);

  ...

You should also close the socket before exiting the program. Enable standard C89/90 or C99 mode of your compiler (e.g. -std=c99 for gcc) and enable warnings (e.g. -Wall for gcc), and read them. And #include the necessary header files (assuming Linux in my case) for function prototypes:

 #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() */

There is some casting of pointers and structs in regards to the hostname / IP address resolving, which can be confusing and easy place to make a mistake, so verify that is working as you expect it is.

 in_addr_t ip;
 ...

 GetIP(google, &ip);   /* I changed the parameters */
 printf("IP address = %x (%s)\n", 
     ip, 
     inet_ntoa(*((struct in_addr*)&ip)));
旧城空念 2024-10-17 09:43:58

实际上,我一直在使用我的名为 rzsocket 的库链接到它来实现一个小型网络代理。

我在实现 Web 代理时发现的最困难的事情之一(也许这也可能是您的问题)是,为了使代理正常工作,我必须将 keep-alive 设置设置为 false。在 FireFox 中执行此操作的一种方法是访问 about:config 地址,并将 network.http.proxy.keep-alive 的值设置为 false代码>.

Actually, I've been implementing a small web proxy using my library called rzsocket link to it.

One of the most difficult things I've found when implementing the web proxy, perhaps this might also be your problem, was that, in order to make the proxy work properly, I had to set keep-alive settings false. One way of doing this in FireFox, is accessing about:config address, and setting the value of network.http.proxy.keep-alive to false.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文