linux 下调用recv函数,死循环在recv函数里面,什么原因?
linux服务器,在连接只有1000个时候,一切正常,到连接到2000以上的时候,就死循环在recv函数里面,cpu占用率很高,因为recv是系统函数,也不知道他在里面干什么。程序是epoll实现的。 有谁碰到过类似问题么?或者是能指导一个努力的方向? 回1楼:不是建立连接的时候死循环,而是跑了一段时间后,在调用recv函数的时候。 我这里是服务器,接受连接, 是一个进程多个线程。每个线程管理多个连接。每个线程使用epoll方式响应网络事件,当网络可读的时候,就去调用recv函数读取数据。 在进行测试的时候,发现1000个连接是好了,如果是3000个连接,跑一个晚上后,就有好几个线程死循环在系统的recv函数了。 回2楼:调试出问题的程序后,发现几个线程都停留在recv函数里面,n单步执行后,直接跳出这个线程。 之所以说是死循环,因为在这种情况下这几个相关线程的cpu占用都很高。 如果是因为socket已经非法,那么我该怎么提前规避处理? 回3楼:socket都是非阻塞的。
更新时间:2019-05-19 19:50
最满意答案
建议你用strace看那几个线程确切是卡在哪里
而且你描述的是,死循环。 recv函数怎么会死循环?
还有,当你的系统压力变大的时候, 会出现epoll提示某socket可用,但是等你去读的时候该socket已经被关闭的情况,你看看这种情况会不会对你的程序造成影响。
----------------------------
man recv
RETURN VALUE
These calls return the number of bytes received, or -1 if an error occurred. The return value will be 0 when the peer has performed an
orderly shutdown.
你可以看到,当对端关闭socket的时候recv返回值是0。 那么作为你的程序,你又没有判断这种情况呢? 你默认的如果是使用EPOLLET模式, 你肯定不停的读socket直到EAGAIN出现,但是如果返回值0的话,并不会出现EAGAIN。
建议你还是多用strace来查询问题所在,有时候比gdb更能直接找出原因。
、
还有再纠正一点,recv是一个linux系统调用,要么是阻塞要么是返回,不存在死循环的问题的, 死循环肯定是出在你的程序代码中。 如果你觉得recv本身不退出又占用大量cpu,那就是linux库出bug或者是内核bug了。
2009-12-30 回答
其他回答
send后,操作系统会决定是不是马山发包还是继续等待看看还有别的send,然后把他们一起打成一个包来发送。所以你recv是不知道要接收几个包的。
2009-12-31 回答
给recv() 设个timeout, 过了这个时间就返回超时的错误,不要RECV一直阻塞在那里.
timeout 可以自己做一个。
下面是 google 弄得一段例子。
struct timeval tv; /* timeval and timeout stuff added by davekw7x */
int timeouts = 0;
tv.tv_sec = 3;
tv.tv_usec = 0;
if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
{
perror("setsockopt");
return -1;
}
if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof their_addr) == -1) {
perror("connect");
exit(1);
}
while (((numbytes=recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) && (++timeouts < 1000)) { /* loop to retry in case it timed out; added by davekw7x */
perror("recv");
printf("After timeout #%d, trying again:\n", timeouts);
}
printf("numbytes = %d\n", numbytes);
buf[numbytes] = '\0';
printf("Received: %s",buf);
2009-12-31 回答
相关问答
建议你用strace看那几个线程确切是卡在哪里 而且你描述的是,死循环。 recv函数怎么会死循环? 还有,当你的系统压力变大的时候, 会出现epoll提示某socket可用,但是等你去读的时候该socket已经被关闭的情况,你看看这种情况会不会对你的程序造成影响。 ---------------------------- man recv RETURN VALUE These calls return the number of bytes received, or -1 if an error
...
recv是socket编程中最常用的函数之一,在阻塞状态的recv有时候会返回不同的值,而对于错误值也有相应的错误码,分别对应不同的状态,下面是我针对常见的几种网络状态的简单总结。 首先阻塞接收的recv有时候会返回0,这仅在对端已经关闭TCP连接时才会发生。 而当拔掉设备网线的时候,recv并不会发生变化,仍然阻塞,如果在这个拔网线阶段,socket被关掉了,后果可能就是recv永久的阻塞了。 所以一般对于阻塞的socket都会用setsockopt来设置recv超时。 当超时时间到达后,rec
...
建议你用strace看那几个线程确切是卡在哪里 而且你描述的是,死循环。 recv函数怎么会死循环? 还有,当你的系统压力变大的时候, 会出现epoll提示某socket可用,但是等你去读的时候该socket已经被关闭的情况,你看看这种情况会不会对你的程序造成影响。 ---------------------------- man recv RETURN VALUE These calls return the number of bytes received, or -1 if an error
...
您可以使用setsockopt函数在接收操作上设置超时: SO_RCVTIMEO 设置超时值,指定输入函数等待直到完成的最大时间量。 它接受时间结构,秒数和微秒数指定等待输入操作完成的时间限制。 如果接收操作在没有接收到附加数据的情况下阻塞了这么多时间,则如果没有接收到数据,则它将返回部分计数或errno设置为[EAGAIN]或[EWOULDBLOCK]。 该选项的默认值为零,表示接收操作不会超时。 此选项需要一个时间结构。 请注意,并非所有实现都允许设置此选项。 // LINUX
struct
...
recv()在流的末尾返回零,这在对等体关闭连接时发生。 关于它没有任何“随机”。 recv() returns zero at end of stream, which in turn occurs when the peer closes the connection. There is nothing 'random' about it.
你有多确定segfault是在recv() ? 您对recv()调用看起来很好,但是,之前的一行是写入未分配的内存,这将导致段错误: std::cin >> tempString;
尝试像这样声明tempString : #define INPUT_BUF_SIZE 100
char tempString[INPUT_BUF_SIZE + 1];
此外,这段代码似乎不寻常: echoStringLen = strlen(echoString); /* Determine in
...
忘了将此标记为已解决。 所有套接字实例都从套接字基类继承其文件描述符变量。 TCPSocket类有一个重载的fd var,它被设置而不是基本的fd。 Forgot to mark this as solved. All socket instances inherit their file descriptor vars from a socket base class. The TCPSocket class had an overloaded fd var that was getting s
...
您希望shutdown(fd, SHUT_WR)仅关闭写入但仍能够读取。 close(fd)将使文件描述符无效,就像关闭了本地文件的开放路径一样。 http://man7.org/linux/man-pages/man2/shutdown.2.html You want shutdown(fd, SHUT_WR) to close only for writes but still be able to read. close(fd) will invalidate the file descri
...
C ++代码中的许多错误 - 比如if (bytesSent = 0) ,这是一个结果转换为boolean的赋值,所以总是返回false 。 您不注意从TCP套接字读取的字节数,假设您在发送时收到一条完整的消息 - 这是错误的,因为您可能正在阅读部分消息,多于一条消息或介于两者之间的任何内容 - 它是一个原始字节流 。 检查-1显式返回系统调用,然后检查errno(3)的值,比如说strerror(3)函数来找出出错的地方。 编辑0: 您正在尝试使用侦听套接字sSock进行数据传输 - 错误 -
...
如果通信中发生错误,则会在套接字上设置错误,并与下一个与套接字相关的系统调用一起传递。 EHOSTUNREACH错误可以(通过其他方式)通过向目标发送UDP数据包并使ICMP无法访问来触发。 由于此ICMP消息仅在send调用完成后才返回,因此它不会返回send而只返回到套接字上的下一个系统调用,也可能是一个recv 。 因此我建议在Linux中也可以返回此错误,但我可能错了。 通常Linux不是UNIX,系统发展和文档通常是有缺陷的。 如果你在各种平台上查看recv的文档,你会发现OpenBSD
...