如何用 C 创建一个简单的代理来访问 Web 服务器
我正在尝试用 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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,您没有检查 有多少字节
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 theread(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 fromread(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 likelibevent
. 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 :)由于您没有发布
GetIP
例程,我不确定您的主机名查找是否正确,因为从外观上看,我不确定您是否使用inet_addr
功能正常。尼古拉指出了一些非常好的观点(我完全同意)。事实上,您的 GET 请求实际上已损坏,当我在我的系统上的本地 Apache Web 服务器上测试它时,它不起作用。
应替换为
您还应该在退出程序之前
close
套接字。启用编译器的标准 C89/90 或 C99 模式(例如 gcc 的-std=c99
)并启用警告(例如 gcc 的-Wall
),并阅读它们。以及函数原型的#include
必要的头文件(假设是Linux):关于指针和
struct
有一些转换主机名/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 usinginet_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.should be replaced with
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:There is some casting of pointers and
struct
s 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.实际上,我一直在使用我的名为 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
tofalse
.