版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Function_Dou/article/details/89949820
在实现网络通信前, 先来了解一下socket
套接字什么时候就绪(可读可写). 第一次学习socket
只需要明白我用红色标记的条件就行.
缓冲区
每个套接字接收区缓存 (用于读) 和发送区缓存 (用于写) :
- 接收区缓存: 接收数据, 从内核缓冲复制到用户应用程序数据缓冲区.
- 发送去缓存: 用户应用程序数据缓冲区复制到内核缓冲区, 等待发送.
每个套接字都有接收缓存区低水位标记(用于读)和发送缓存区低水位标记(用于写):
- 接收低水位: 可读时套接字接收缓冲区中所需的最少数据量. 对于TCP, 其默认值为1.
- 发送低水位: 可写时套接字发送缓冲区中所需的最少可用空间. 对于TCP, 其默认值常为2048.
可以修改接收缓冲区的低水位来保证不用频繁的调用读, 等累计到一定的量在一次性读. 这样就可以减少读的次数. 像libevent
就设置了用户的低水位, 高水位.
socket可读
- 监听socket上有新的连接请求. 因为套接字收到了对方的connect请求, 执行了三次握手的第一步: 对方发送SYN请求过来, 使该方监听套接字处于可读状态; 通常情况下, 对这样的套接字执行accept操作不会阻塞.
- 已连接socket. socket内核接收缓存区中的字节数大于或等于其低水位标记
SO_RCVLOWAT
, 此时可以无阻塞地读该socket, 并且读操作返回的字节数大于0. 对于TCP和UDP套接字而言, 其缺省值为1, 默认情况下, 只要缓冲区中有数据, 那就是可读的. - socket通信对端关闭连接[1], 此时对该socket读操作将返回0.
- socket上有未处理的错误[2]. 对这样的套接字的读操作将不会阻塞并返回-1(即返回一个错误), 同时把errno设置成确切的错误条件. 此时我们可以使用
getsockopt
来读取和清除该错误. select能处理的异常情况只有一种: socket上接收到带外数据
socket可写:
-
已连接socket. socket内核发送缓冲区中的可用字节数大于或等于其低水位标记
SO_SNDLOWAT
. 此时我们可以无阻塞写该socket, 并且写操作返回的字节数大于0. 对于TCP和UDP套接字而言, 低水位默认值为2048, 发送缓冲区默认大小为8K. 默认情况下, 一个套接字连接成功后,总是可写的. -
socket写操作被关闭. 对写操作被关闭的socket执行写操作将触发一个
SIGPIPE
信号, 该信号的缺省行为是终止进程. -
socket使用非阻塞connect连接成功或者失败(超时)[3]. 使用非阻塞式connect的套接字已建立连接, 或者connect已经以失败告终, 即connect已经完成.
-
socket上有未处理的错误[2]. 对这样的套接字的写操作将不会阻塞并且返回-1(即返回一个错误), 同时把errno设置成确切的错误条件. 此时我们可以使用
getsockopt
来读取和清除该错误. select能处理的异常情况只有一种: socket上接收到带外数据.
注意 : 当socket错误时, 此时既可读也可写.
小结
- 了解缓冲区
- socket读写时期