我正在尝试在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;
}
谢谢!
答案 0 :(得分:2)
首先,您没有检查write(2)
调用实际写入套接字的字节数。调用的返回值告诉您。 read(2)
也是如此。 TCP套接字是一个双向流,因此规则总是在循环中执行,直到传输预期的字节数,读取EOF
(从read(2)
返回零)或发生错误(在阅读时你没有检查。)
然后HTTP是相当复杂的协议。熟悉RFC 2616,尤其是应用程序级别的连接管理和传输编码。
select(2)
/ poll(2)
/ epoll(4)
/ {{3系统调用系列,允许您kqueue(2)
I / O.这通常与非阻塞套接字结合使用。查看辅助库,如multiplex。看看在libevent
这样的优秀网络服务器/代理中如何做到这一点。听起来很像你发现的很多,但不要担心,这很有趣:)
答案 1 :(得分:1)
由于您没有发布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() */
对于主机名/ IP地址解析,有一些强制转换指针和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)));
答案 2 :(得分:1)
实际上,我一直在使用名为rzsocket link to it的库实现一个小型Web代理。
我在实现Web代理时发现的最困难的事情之一,也许这可能也是您的问题,是的,为了使代理正常工作,我不得不将keep-alive设置为false。在FireFox中执行此操作的一种方法是访问 about:config 地址,并将network.http.proxy.keep-alive
的值设置为false
。