gpt4 book ai didi

c - 代理中的非阻塞套接字和 poll() 怪癖 - 新手

转载 作者:行者123 更新时间:2023-11-30 16:01:00 27 4
gpt4 key购买 nike

我是一个涉足 C 的新手,我的小项目是编写一个简单的 SOCKS4 代理。感谢这里的帮助,到目前为止我已经在我的例程中使用非阻塞套接字和 poll() 了。然而此时我似乎有两个问题:

  1. 如果传入 Socket rcvSocket 关闭,则传出 Socket dstSocket 不会关闭,反之亦然。我不在循环中检查这一点,但我不知道如何。我尝试使用 POLLHUP 作为 revents,但这似乎不起作用。正常的检查似乎是 recv() 是否返回 0,但这对于非阻塞套接字也有效吗?如果是这样,那它如何与 revents 一起工作,我似乎不知道该把它放在哪里,因为如果 POLLIN | POLLPRI 已设置,在我看来,recv() 永远不应该返回 0?另外,我不明白 POLLIN 和 POLLPRI 之间的确切区别是什么,在我看来,这两种情况都只是检查“数据可供读取”?

  2. 代理似乎适用于我使用 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);
}
}

最佳答案

recv() 在干净的远程关闭时返回 0 - 即使对于非阻塞套接字也是如此。在这种情况下,将返回POLLIN - 远程端已关闭套接字的通知被视为“可读”事件。

您不需要对 SOCKS/HTTP 连接使用 POLLPRI - 它表示 TCP“紧急数据”,这些协议(protocol)不使用该数据(或者实际上根本不使用)。

<小时/>

除了您的直接问题之外,您还需要做更多的事情来实现可靠的代理:

  1. 您需要在每个循环上调用 poll(),而不仅仅是一次。您编写的方式是忙循环,这通常不被认为是可接受的做法。
  2. 您应该使用 signal(SIGPIPE, SIG_IGN);SIGPIPE 的处置设置为忽略。这使您可以优雅地处理写入失败。
  3. 您应该检查 send() 的结果。请注意,它可以写入少于您请求的数量 - 在这种情况下,您必须保留未发送的数据缓冲,返回到 poll() 并尝试再次发送剩余数据,如果 POLLOUT 在套接字上引发。如果还有未发送的数据,您只想请求POLLOUT,因此您需要确保在每个之前正确设置.events poll() 调用。
  4. 如果 recv()send() 返回小于 0 的值,您应该检查 errnoEINTR code> 和 EWOULDBLOCK 应被忽略;任何其他错误都应被视为连接失败。
  5. 当一个套接字关闭时,您不应该立即关闭两个方向 - 您必须支持非对称关闭。这意味着当您看到fds[0]已被远程端关闭时,您应该调用shutdown(fds[1], SHUT_WR);,反之亦然反之亦然;仅当两者都已关闭(或发生连接失败)时,您才应在两个文件描述符上调用close()并完成。

关于c - 代理中的非阻塞套接字和 poll() 怪癖 - 新手,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7250236/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com