【发布时间】:2011-08-30 21:51:27
【问题描述】:
我是一个涉足 C 的新手,我的小项目是编写一个简单的 SOCKS4 代理。多亏了这里的帮助,我才得以在日常工作中使用非阻塞套接字和 poll()。但是在这一点上我似乎有两个问题:
如果传入的 Socket rcvSocket 关闭,则传出的 Socket dstSocket 不会关闭,反之亦然。我不在循环中检查这个,但我不知道如何。我尝试将 POLLHUP 作为 revents,但这似乎不起作用。正常检查似乎是 recv() 是否返回 0,但这对非阻塞套接字也有效吗?如果是这样,它如何与 revents 一起工作,我似乎无法弄清楚我会把它放在哪里,因为如果 POLLIN | POLLPRI 已设置,在我看来,recv() 永远不应该返回 0?另外我不明白 POLLIN 和 POLLPRI 之间的确切区别是什么,在我看来,这两种情况都只是检查“数据可供阅读”?
代理似乎适用于我用 netcat 测试过的连接。但是,如果我使用浏览器,它会说(当我定位一个网站时)我是否要保存“二进制数据”。我检查了wireshark中的数据,从服务器接收到的数据似乎被正确地逐字节转发给客户端。如果有人可能知道为什么这个程序会发生这种情况,那就太好了:)
附上相关代码(小心编程新手):
fds[1].fd = dstSocket;
fds[0].fd = rcvSocket;
fds[1].events = POLLIN | POLLPRI | POLLHUP;
fds[0].events = POLLIN | POLLPRI | POLLHUP;
timer = poll(fds, 2, timeout_msecs); /* i dont use this yet */
fcntl(rcvSocket, F_SETFL, O_NONBLOCK);
fcntl(dstSocket, F_SETFL, O_NONBLOCK);
while (1 == 1)
{
if (fds[0].revents & POLLIN | POLLPRI)
{
recvMsgSize = recv(rcvSocket, rcvBuffer, RCVBUFSIZE, 0);
if (recvMsgSize > 0) {send(dstSocket, rcvBuffer, recvMsgSize, 0);}
}
if (fds[1].revents & POLLIN | POLLPRI)
{
sndMsgSize = recv(dstSocket, sndBuffer, RCVBUFSIZE, 0);
if (sndMsgSize > 0) { send(rcvSocket, sndBuffer, sndMsgSize, 0);}
}
if ((fds[0].revents & POLLHUP) || (fds[1].revents & POLLHUP))
{
close(rcvSocket);
close(dstSocket);
}
}
【问题讨论】:
-
虽然这可能不是真正的问题,但您最终需要处理它:使用非阻塞套接字 send() 可能不会发送您请求它发送的所有字节。另外,您是否已将浏览器配置为将您的程序用作 SOCKS 代理?如果是这样,您需要实现 SOCKS 协议才能使浏览器正常工作。
-
2.笔记。注意|和 & 运算符运算符优先级
fds[1].revents & POLLIN | POLLPRI与(fds[1].revents & POLLIN) | POLLPRI相同,您需要fds[1].revents & (POLLIN | POLLPRI)(或者按照 caf 的建议删除 POLLPRI -
显然是firefox的一个bug,chrome和其他socks应用都能正常工作。关于优先级的好点不知道,谢谢。
标签: c sockets nonblocking