如何创建一个简单的代理以访问C中的Web服务器
题
我正在尝试在C中创建一个小的Web代理。首先,我正在尝试获取一个网页,并将Get Frame发送到服务器。我不知道我错过了什么,但是我没有收到任何回应。如果您可以帮助我找到此代码中缺少的内容,我将非常感谢。
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;
}
谢谢!
解决方案
由于您没有发布 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模式(例如 -std=c99
对于GCC)并启用警告(例如 -Wall
对于GCC),并阅读它们。和 #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地址解决方案的s,这可能会令人困惑且容易犯错,因此请验证您按照您的期望工作的工作。
in_addr_t ip;
...
GetIP(google, &ip); /* I changed the parameters */
printf("IP address = %x (%s)\n",
ip,
inet_ntoa(*((struct in_addr*)&ip)));
其他提示
首先,您没有检查多少个字节 write(2)
呼叫实际写信给插座。呼叫的返回值告诉您。也是如此 read(2)
. 。 TCP插座是双向流,因此通常在循环中始终执行两者,直到转移预期的字节数, EOF
读取(从 read(2)
),或发生错误(阅读时您都没有检查)。
那么HTTP是相当复杂的协议。让自己熟悉 RFC 2616, ,特别是应用程序级别连接管理和传输编码。
编辑0:
嗯,没有“简单”代理。您需要管理多个连接(至少客户到proxy和proxy-to-server),因此最好研究 select(2)
/poll(2)
/epoll(4)
/kqueue(2)
系统呼叫家庭,这使您可以 多路复用 我/o。这通常与 非障碍 插座。查看辅助图书馆 libevent
. 。查看在良好的网络服务器/代理中如何完成此操作 nginx. 。听起来您可以发现很多东西,但是请放心,这很有趣:)
实际上,我一直在使用名为RZSocket的库实现一个小型网络代理 链接到它.
我在实施Web代理时发现的最困难的事情之一,也许这也许也是您的问题,是为了使代理工作正常工作,我不得不设置“远景”设置错误。在Firefox中这样做的一种方法是访问 关于:config 地址,并设置 network.http.proxy.keep-alive
至 false
.