php socket_recv() msg_waitall,Socket recv()挂在带有MSG_WAITALL的大消息上

在升级到RHEL6.1后,一个从服务器读取大文件的应用程序开始频繁挂起。问题表现为使用环回地址时挂起,而通过以太网接口则正常。挂起时,服务器发送TCP窗口完整消息,客户端响应TCP零窗口,之后挂起。移除recv()的MSG_WAITALL标志可使程序正常运行。挂起可能与时间依赖有关,且仅在特定机器的环回接口出现。建议检查网络设置、TCP窗口大小及超时配置进行调试。
摘要由CSDN通过智能技术生成

我有一个从服务器读取大文件并在特定机器上频繁挂起的应用程序.它已经在RHEL5.2下成功工作了很长时间.我们最近升级到RHEL6.1,现在它定期挂起.

我已经创建了一个重现问题的测试应用程序.它挂起了大约98次100.

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

int mFD = 0;

void open_socket()

{

struct addrinfo hints, *res;

memset(&hints, 0, sizeof(hints));

hints.ai_socktype = SOCK_STREAM;

hints.ai_family = AF_INET;

if (getaddrinfo("localhost", "60000", &hints, &res) != 0)

{

fprintf(stderr, "Exit %d\n", __LINE__);

exit(1);

}

mFD = socket(res->ai_family, res->ai_socktype, res->ai_protocol);

if (mFD == -1)

{

fprintf(stderr, "Exit %d\n", __LINE__);

exit(1);

}

if (connect(mFD, res->ai_addr, res->ai_addrlen) < 0)

{

fprintf(stderr, "Exit %d\n", __LINE__);

exit(1);

}

freeaddrinfo(res);

}

void read_message(int size, void* data)

{

int bytesLeft = size;

int numRd = 0;

while (bytesLeft != 0)

{

fprintf(stderr, "reading %d bytes\n", bytesLeft);

/* Replacing MSG_WAITALL with 0 works fine */

int num = recv(mFD, data, bytesLeft, MSG_WAITALL);

if (num == 0)

{

break;

}

else if (num < 0 && errno != EINTR)

{

fprintf(stderr, "Exit %d\n", __LINE__);

exit(1);

}

else if (num > 0)

{

numRd += num;

data += num;

bytesLeft -= num;

fprintf(stderr, "read %d bytes - remaining = %d\n", num, bytesLeft);

}

}

fprintf(stderr, "read total of %d bytes\n", numRd);

}

int main(int argc, char **argv)

{

open_socket();

uint32_t raw_len = atoi(argv[1]);

char raw[raw_len];

read_message(raw_len, raw);

return 0;

}

一些笔记从我的测试:

>如果“localhost”映射到环回地址127.0.0.1,应用程序将挂在对recv()和NEVER返回的调用上.

>如果“localhost”映射到机器的ip,则通过以太网接口路由数据包,该应用程序成功完成.

>当我遇到一个挂起,服务器发送一个“TCP窗口完整”消息,客户端回应一个“TCP ZeroWindow”消息(见图像和附加的tcpdump捕获).从这一点上,它永远挂起服务器发送keep-alives,客户端发送ZeroWindow消息.客户端似乎没有扩大窗口,允许传输完成.

>在挂起期间,如果我检查“netstat -a”的输出,服务器发送队列中的数据,但客户端接收队列为空.

>如果我从recv()调用中删除MSG_WAITALL标志,该应用程序将成功完成.

>挂起的问题只出现在1个特定机器上的环回接口.我怀疑这可能与时间依赖有关.

>当我丢弃“文件”的大小时,挂起发生的可能性就会降低

测试应用程序的来源可以在这里找到:

从loopback接口捕获的tcpdump可以在这里找到:

我通过发出以下命令来重现问题:

> gcc socket_test.c -o socket_test

> perl -e 'for (1..6000000){ print "a" }' | nc -l 60000

> ./socket_test 6000000

这会发送到测试应用程序的6000000字节,该测试应用程序尝试使用对recv()的单个调用来读取数据.

我很乐意听到有关我可能做错了什么的任何建议或任何进一步调试问题的方法.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值