2

我正在 ubuntu linux 机器上用 c 编写一个客户端服务器套接字程序。服务器端需要处理许多连接,并且服务器和客户端都有一个本地套接字,可以在对其进行一些操作后将接收到的数据发送到本地进程,并且发送和接收的数据数量巨大。(数据量不是很大,最大1500)如下图:
【客户端本地进程】<->数据<->客户端<--------->服务器<->数据<- > [服务器本地进程]

所以所有的套接字(client_local_socket、client_remote_socket、server_remote_socket、server_local_socket)都需要是非阻塞的。

当我在局域网中的两台计算机上运行客户端和服务器时,它可以正常工作,但是当将服务器程序移动到互联网中的 linux 服务器时(客户端连接到 nat 后面的服务器)客户端开始与服务器成功通信(两个客户端并且服务器得到一些 EAGAIN 错误,但在下一次尝试后恢复它,因为我知道它对于非阻塞非常正常)但过了一段时间(超过 1000 个发送和接收数据包),client_remote_socket 无法写入错误代码 EAGAIN 并且不能在接下来的尝试中恢复它,在那之后,它总是得到这个该死的 EAGAIN 写作。BTW client_remote_socket 读取没有问题,总是从服务器获取数据包。服务器完全没有问题,client_local_socket 在写入和读取方面都工作得很好。

我已经使用此代码使套接字非阻塞:

int flags;
if ((flags = fcntl(client_remote_socket, F_GETFL, 0)) < 0)
    flags = 0;
flags = flags | O_NONBLOCK;
fcntl(client_remote_socket, F_SETFL, flags);

我也尝试过:

fcntl(client_remote_socket, F_SETFL, O_NONBLOCK);

但结果是一样的。

我使用的唯一setsockopt是服务器端的SO_REUSEADDR,客户端没有setsockopt。

值得一提的是,我总是检查 write 返回的值,当它 <0 时,我检查 errno 并查看它的 EAGAIN。据我所知,当内核没有可用于写缓冲区的空间并且内核在具有 4 GB 内存的笔记本电脑中没有内存供我使用时,写返回 EAGAIN。顺便说一句,当我在局域网中同时运行客户端和服务器时,它可以正常工作。当这发生在客户端时,服务器不会显示任何客户端套接字损坏的迹象,这是正确的,因为与此同时,它可以从服务器接收数据。我一遍又一遍地检查代码并尝试多次调试它,但没有发现任何问题。我还使用 select 系统调用来检查套接字是否可用于写入,并且在时间到来时它总是返回 0。现在我不知道如何解决这个问题,任何想法对我来说都会非常棒。谢谢。

4

1 回答 1

2

上周我遇到了同样的问题,经过研究我发现这是因为同行的缓冲区已满。我测试了这个案例。

当远程缓冲区已满时,它会告诉您的本地堆栈停止发送。当数据从远程缓冲区中清除(被远程应用程序读取)时,远程系统将通知本地系统发送更多数据。

这是 Brian White 的答案 https://stackoverflow.com/a/14244450/3728361

于 2014-07-04T04:11:17.557 回答