2013-11-03 41 views
1

我正在写一个客户端服务器套接字程序在c上的一个Ubuntu的Linux机器上。 服务器端需要处理多个连接,并且服务器和客户端都有一个本地套接字,用于在接收到的数据经过处理后发送到本地进程,并且发送和接收的数据量很大。 (数据的大小也不是很巨大的,最大1500) 这里是图:
[客户端的本地进程] < - >数据< - >客户端< --------->服务器< - >数据<→[本地进程服务器]一段时间后写入总是返回EAGAIN连接的非阻塞套接字

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

当我在LAN网络中的两台计算机上运行客户端和服务器时,它工作得很快,但是当将服务器程序移动到互联网上的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。

它不错,我总是检查写回报的价值,当它是< 0我检查errno,看看它的EAGAIN。 据我所知,当内核没有可用空间用于写入缓冲区时,写入将返回EAGAIN,并且在4 GB RAM的笔记本电脑中内核对我而言没有任何意义。并顺便说一句,当我在LAN网络中运行客户端和服务器时,它工作得很顺利。 当客户端发生这种情况时,服务器不会显示任何损坏的客户端套接字及其正确的标志,因为与此同时,它可以从服务器接收数据。我再次检查了一遍又一遍的代码,并尝试多次调试,并且看不到任何错误。我还使用select系统调用来检查套接字是否可用于写入,并在时间到时始终返回0。 现在我不知道解决这个问题,任何想法都会对我非常感兴趣。 谢谢。

+0

我没有看到你有很多选择,但张贴相关的代码的答案。 – Duck

+0

套接字无法使用所有内存,套接字缓冲区有限制,通常高达几MB。获得EAGAIN是100%正常的,通常意味着网络无法处理更多流量,或者接收应用程序接收速度不够快。 – nos

+1

令我感到棘手的感觉是,在第一段中,你说“服务器端需要处理多个连接”,最后是“我也使用了选择系统调用”,显然作为调试机制而不是处理许多连接的必要条件。如果你只是在一个循环中冲击'send',那么获得大量的EGAIN并不奇怪。 – Duck

回答

2

上周我得到了同样的问题,在做了一项研究之后,我发现这是因为对方的缓冲区已满。我测试了这个案例。

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

这是布莱恩·怀特 https://stackoverflow.com/a/14244450/3728361

+0

好的,谢谢你的答案。你对tcp的行为完全正确,我相信答案会帮助某人。但在我的情况下,这是由于TCP黑洞导致的互联网路径中的isp路由器故障。我已经发布了一个关于该答案的答案,但声音没有填充计算器的规则并被删除 – madz