linux socket 阻塞 socket.receive阻塞处理

各位老铁们,大家好,今天由我来为大家分享linux socket 阻塞,以及socket.receive阻塞处理的相关问题知识,希望对大家有所帮助。如果可以帮助到大家,还望关注收藏下本站,您的支持是我们最大的动力,谢谢大家了哈,下面我们开始吧!

linuxsocket阻塞如何退出

设置套接字为非阻塞模式。

1、通过设置套接字的属性,把其从阻塞模式改为非阻塞模式,即使没有数据到来或者连接建立,程序也不会一直等待,而是立刻返回。

2、超时机制:在代码中设置超时机制,即如果套接字在指定时间内依然处于阻塞状态,则退出程序。

3、信号处理:使用信号处理机制,在另一个线程中发送一个指定的信号,如SIGINT信号,当程序接收到该信号时,可以退出当前的阻塞状态。

linux网络编程中阻塞和非阻塞socket的区别

阻塞socket和非阻塞socket的区别:

1、读操作

对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲区中的数据大于期望读取的字节数时,读取期望读取的字节数,返回实际读取的长度。

对于非阻塞socket而言,socket的接收缓冲区中有没有数据,read调用都会立刻返回。接收缓冲区中有数据时,与阻塞socket有数据的情况是一样的,如果接收缓冲区中没有数据,则返回错误号为EWOULDBLOCK,表示该操作本来应该阻塞的,但是由于本socket为非阻塞的socket,因此立刻返回,遇到这样的情况,可以在下次接着去尝试读取。如果返回值是其它负值,则表明读取错误。

因此,非阻塞的rea调用一般这样写:

if((nread= read(sock_fd, buffer, len))< 0)

{

if(errno== EWOULDBLOCK)

{

return 0;//表示没有读到数据

}else return-1;//表示读取失败

}else return nread;读到数据长度

2、写操作

对于写操作write,原理是类似的,非阻塞socket在发送缓冲区没有空间时会直接返回错误号EWOULDBLOCK,表示没有空间可写数据,如果错误号是别的值,则表明发送失败。如果发送缓冲区中有足够空间或者是不足以拷贝所有待发送数据的空间的话,则拷贝前面N个能够容纳的数据,返回实际拷贝的字节数。

而对于阻塞Socket而言,如果发送缓冲区没有空间或者空间不足的话,write操作会直接阻塞住,如果有足够空间,则拷贝所有数据到发送缓冲区,然后返回.

非阻塞的write操作一般写法是:

int write_pos= 0;

int nLeft= nLen;

while(nLeft> 0)

{

int nWrite= 0;

if((nWrite= write(sock_fd, data+ write_pos, nLeft))<= 0)

{

if(errno== EWOULDBLOCK)

{

nWrite= 0;

}else return-1;//表示写失败

}

nLeft-= nWrite;

write_pos+= nWrite;

}

return nLen;

3、建立连接

阻塞方式下,connect首先发送SYN请求道服务器,当客户端收到服务器返回的SYN的确认时,则connect返回.否则的话一直阻塞.

非阻塞方式,connect将启用TCP协议的三次握手,但是connect函数并不等待连接建立好才返回,而是立即返回。返回的错误码为EINPROGRESS,表示正在进行某种过程.

4、接收连接

对于阻塞方式的倾听socket,accept在连接队列中没有建立好的连接时将阻塞,直到有可用的连接,才返回。

非阻塞倾听socket,在有没有连接时都立即返回,没有连接时,返回的错误码为EWOULDBLOCK,表示本来应该阻塞。

无阻塞的设置方法

方法一:fcntl

int flag;

if(flag= fcntl(fd, F_GETFL, 0)<0) perror("get flag");

flag|= O_NONBLOCK;

if(fcntl(fd, F_SETFL, flag)< 0)

perror("set flag");

方法二:ioctl

int b_on= 1;

ioctl(fd, FIONBIO,&b_on);

linux socket阻塞recv怎么返回

recv是socket编程中最常用的函数之一,在阻塞状态的recv有时候会返回不同的值,而对于错误值也有相应的错误码,分别对应不同的状态,下面是我针对常见的几种网络状态的简单总结。

首先阻塞接收的recv有时候会返回0,这仅在对端已经关闭TCP连接时才会发生。

而当拔掉设备网线的时候,recv并不会发生变化,仍然阻塞,如果在这个拔网线阶段,socket被关掉了,后果可能就是recv永久的阻塞了。

所以一般对于阻塞的socket都会用setsockopt来设置recv超时。

当超时时间到达后,recv会返回错误,也就是-1,而此时的错误码是EAGAIN或者EWOULDBLOCK,POSIX.1-2001上允许两个任意一个出现都行,所以建议在判断错误码上两个都写上。

如果socket是被对方用linger为0的形式关掉,也就是直接发RST的方式关闭的时候,recv也会返回错误,错误码是ENOENT

还有一种经常在代码中常见的错误码,那就是EINTER,意思是系统在接收的时候因为收到其他中断信号而被迫返回,不算socket故障,应该继续接收。但是这种情况非常难再现,我尝试过一边一直在不停的发信号,一边用recv接收数据,也没有出现过。这种异常错误我附近只有一个朋友在用write的时候见到过一次,但是总是会有概率出现的,所以作为完善的程序必须对此错误进行特殊处理。

一般设置超时的阻塞recv常用的方法都如下:

while(1)

{

cnt=(int)recv(m_socket, pBuf,RECVSIZE, 0);

if( cnt>0)

{

//正常处理数据

}

else

{

if((cnt<0)&&(errno== EAGAIN||errno== EWOULDBLOCK||errno== EINTR))//这几种错误码,认为连接是正常的,继续接收

{

continue;//继续接收数据

}

break;//跳出接收循环

}

}

阻塞与非阻塞recv返回值没有区分,都是<0出错=0连接关闭>0接收到数据大小。

Linux环境下,须如下定义:struct timeval timeout={3,0};

//设置发送超时

setsockopt(socket,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(struct timeval));

//设置接收超时

setsockopt(socket,SOL_SOCKET,SO_RCVTIMEO,(char*)&timeout,sizeof(struct timeval));

阅读剩余
THE END