C 代理中的非阻塞套接字和poll()怪癖-新手
我是一个涉足C语言的新手,我的小项目是编写一个简单的SOCKS4代理。多亏了这里的帮助,我才得以在例程中使用非阻塞套接字和poll()。然而,在这一点上,我似乎有两个问题:C 代理中的非阻塞套接字和poll()怪癖-新手,c,sockets,nonblocking,C,Sockets,Nonblocking,我是一个涉足C语言的新手,我的小项目是编写一个简单的SOCKS4代理。多亏了这里的帮助,我才得以在例程中使用非阻塞套接字和poll()。然而,在这一点上,我似乎有两个问题: 如果传入套接字rcvSocket关闭,则传出套接字dstSocket不会关闭,反之亦然。我没有在循环中检查这个,但我不知道如何检查。我试着用波尔胡普作为复仇者,但这似乎不起作用。正常的检查似乎是recv()是否返回0,但这对非阻塞套接字也有效吗?如果是这样的话,这对revents是如何起作用的,我似乎不知道该放在哪里,因为如
recv()。在这种情况下,将返回POLLIN
——远程端已关闭套接字的通知被视为“可读”事件
SOCKS/HTTP连接不需要使用POLLPRI
,它表示TCP“紧急数据”,这些协议不使用它(或者实际上使用得太多)
除了直接的问题,您还需要做更多的工作来实现可靠的代理:
poll()
,而不是只调用一次。您编写它的方式是忙于循环,这通常被认为是不可接受的SIGPIPE
的配置设置为与signal(SIGPIPE,SIG_IGN)一起忽略代码>。这允许您优雅地处理写入失败
send()
的结果。请注意,它的写入量可能小于您请求的量—在这种情况下,您必须保留未发送的数据缓冲区,返回poll()
,并在套接字上引发POLLOUT
时再次尝试发送剩余的数据。如果还有未发送的数据,您只需要请求POLLOUT
,因此您需要确保在每次poll()
调用之前正确设置.events
recv()
或send()
返回的值小于0,则应检查errno
EINTR
和EWOLDBLOCK
应忽略;任何其他错误都应视为连接失败fds[0]
时,应调用shutdown(fds[1],shutw)代码>,反之亦然;只有在两个文件描述符都已关闭(或发生连接故障)时,才应在两个文件描述符上调用close()
,然后完成
感谢您提供的信息,我添加了if(recvMsgSize==0)break;对于sndMsgSize也是一样,现在就像连接关闭的魅力一样。非常感谢您的投入,我显然意识到我的“代理”并不是真正的生产价值,它只是一个让我在学习C时无所事事的项目。我将尝试实现您所说的,但我想我必须先阅读一下。好的一面是,浏览器不使用socks代理似乎是firefox的一个缺陷,因为chrome和任何其他支持socks的应用程序都可以正常工作。@user912877:我认为firefox很有可能不使用它,因为第5点。firefox在代理版本中根本没有关闭套接字。我检查了wireshark中的数据,它得到了1:1的副本。当然你是对的,我现在做close()的方式非常糟糕。我认为我现在这样做可能会让服务器发送一些东西,关闭连接,我的代理也会在交付数据之前终止客户端连接。(除了我应该做的事情:-)虽然这里可能不是真正的问题,但最终您需要处理它:使用非阻塞套接字send()可能不会发送您请求它发送的所有字节。另外,您是否已将浏览器配置为将您的程序用作SOCKS代理?如果是这样,您需要实现SOCKS协议,浏览器才能正常工作。注意。注意| and&运算符优先级
fds[1]。revents&POLLIN | POLLPRI
与(fds[1]。revents&POLLIN)| POLLPRI
,您需要fds[1]。revents&POLLIN | POLLPRI
(或者就像Caff所建议的那样,删除POLLPRI显然是一个firefox bug,chrome和其他socks应用程序可以工作。好的一点是,我不知道,谢谢。
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);
}
}