socket非阻塞读写

读操作

对于阻塞的socket,当socket的接收缓冲区中没有数据时,read调用会一直阻塞住,直到有数据到来才返回。当socket缓冲区中的数据量小于期望读取的数据量时,返回实际读取的字节数。当sockt的接收缓冲区中的数据大于期望读取的字节数时,读取期望读取的字节数,返回实际读取的长度。对于非阻塞socket而言,socket的接收缓冲区中有没有数据,read调用都会立刻返回。接收缓冲区中有数据时,与阻塞socket有数据的情况是一样的,如果接收缓冲区中没有数据,则返回-1,错误号为EWOULDBLOCK或EAGAIN,表示该操作本来应该阻塞的,但是由于本socket为非阻塞的socket,因此立刻返回,遇到这样的情况,可以在下次接着去尝试读取。如果返回值是其它负值,则表明读取错误。因此,非阻塞的read调用一般这样写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
if(read(sock_fd, buffer, len) < 0)
{
if(errno == EWOULDBLOCK || errno == EAGAIN)
{
//没有读到数据

}
else
{
//读取失败

}
}
else
{
//读到数据

}

写操作

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
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 || errno == EAGAIN)
{
nWrite = 0;
}
else
{
//写失败
}
}
else
{
nLeft -= nWrite;
wirte_pos += nWrite;
}
}

以上内容转自这里