在socket中,read,write函数不同于一般的文件IO操作
下面开始分析这两个函数在socket中的行为
write
1 |
|
从函数声明我们可以看到,第一个是一个文件描述符,第二个是一个指向缓存区的指针,第三个则是要写入的数据量
write函数把buf的count字节内容写入文件描述符
成功,就返回写的字节数。失败,返回-1,并设置errno变量
那么就会有两种情况
a)返回值大于0,表示写入了部分或者全部数据,由于有可能一次无法将所有数据写入,因此需要通过返回值来确定剩余数据量
b)返回值小于0,表示出现了错误,我们要根据errno的值进行处理
- EINTR:写的时候出现了中断错误
- EPIPE:网络连接出现了问题
因此,普通的write函数无法满足我们的需求,我们需要写一个能够将数据完全写入以及能够处理错误的加强版write函数
1 | ssize_t writen(int fd, const void *buf, size_t n) { |
read
1 |
|
read函数是负责从fd中读取内容.当读成功时,read返回实际所读的字节数
当读成功时,read返回实际所读的字节数
如果返回的值是0,表示已经读到文件的结束了
小于0表示出现了错误.并改写errno
- EINTR:中断错误
- ECONNREST:网络连接出了问题
1 | ssize_t readn(int fd, void *buf, size_t count) { |
socket中的缓冲区与blocking
每个socket被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区
read,write函数都是和缓冲区进行IO互动
然而,缓冲区的大小是有限制的,其大小可以通过getsockopt
获取,因此,当缓冲区满了,也就有了中断错误EINTR
缓冲区有以下特性
- I/O缓冲区在每个TCP套接字中单独存在;
- I/O缓冲区在创建套接字时自动生成;
- 即使关闭套接字也会继续传送输出缓冲区中遗留的数据;
- 关闭套接字将丢失输入缓冲区中的数据
因为read和write的操作都是在缓冲区上进行,因而也有了所谓的阻塞模式(blocking)
试想,当缓冲区中没有数据的时候,read就会阻塞
那么当缓冲区的数据满了,那么write就会阻塞