高级I/O函数
给套接口上的I/O设置超时
1.调用alarm,在调用超过指定时间时产生SIGALARM信号,这涉及到信号处理,而且可能和进程中其他的alarm冲突
2.使用select阻塞在等待I/O上,select内部有时间限制,一次代替在read和write上阻塞超时
3.使用新的SO_RCVTIMEO和SO_SNDTIMEO套接字选项,这种方法存在一个问题,即不是所有的系统都支持这两个选项。
这三种技术都可以用作输入和输出操作,但我们还想要一种支持connect超时的技术,因为TCP中的默认超时时间很长(75s),只有套接口为非阻塞方式时,才可以调用select为connect设置超时,connect并不支持SO_RCVTIMEO和SO_SNDTIMEO。前两种技术可以应用于任何描述符,第三种技术只能应用于套接字。
alarm的原理
alarm基于信号将中断阻塞的socekt操作,如果alarm产生信号之时connect仍未返回,EINTR错误即表示connect超时。
这种技术只能提前完成超时,而不能延长超时,比如connect的默认超时时长是75s,alarm可以提前为50s超时,却不能设置成80s超时。
用信号处理一个应答时没有问题,处理多个应答的时候就必须解决可能的冲突。
recv和send
recv和send的前三个参数和read、write相同,第四个参数由以下的一个或者多个flag或组成
MSG_DONTWAIT
将单个I/O操作设置为非阻塞,而不需要在套接口上设置非阻塞标记,执行I/O操作,然后关闭非阻塞。
MSG_WAITALL
告诉内核,没有读到请求的字节数之前不要返回,即使设定了这个标记,如果发生下列问题,返回的字节数仍然会比请求的要少
1.捕获一个信号
2.连接被终止
3.套接口上发生错误。
readv和writev
类似于read和write,但让我们可以在一个函数调用中操作多个缓冲区,这些操作被成为分散读和集中写。
readv和writev可用于任何描述字,而且writev是一个原子操作。
recvmsg和sendmsg
这两个函数是最通用的I/O函数,可以用recvmsg替代read、readv、recv、recvfrom,sendmsg也可以替代其他的write函数。
在不读出数据的时候,怎么知道套接口中有多少数据可读?
1.如果没有其他数据可读还有其他事情要做,可以使用非阻塞I/O。
2.如果想检查一下数据,而使数据扔保存在接收队列中,可以使用MSG_PEEK,如果想这么做,又不确定一定有数据可读,可以把MSG_PEEK和非阻塞套接口一起使用,或者和MSGDONTWAIT一起使用。
3.一些支持ioctl的FIONREAD命令,
标准I/O库用于套接口
对于任何文件描述符,调用fdopen可以返回一个标准I/O流,对于一个标准I/O流,调用fileno可以获得文件描述符。多路复用只能用于描述字,所以需要把标准I/O转为文件描述符。
TCP和UDP是全双工的,标准I/O流也可以是全双工的,只要以r+方式打开即可,但是对这样的流不能在一个输出函数后紧接着一个输入函数,必须插入一个fflush、fseek、fsetpos、或rewind调用,同样,不能在一个输入函数后紧接一个输出函数,必须插入一个fseek、fsetpos或rewind。除非输入函数遇到一个文件描述符,后三个函数的问题是他们都会调用lseek,可lseek会在套接口上失败。
解决这个问题的最简单方法是:为一个套接字打开两个标准I/O流,一个读、一个写。
问题是标准I/O库自动进行缓冲,标准I/O库执行三种缓冲
1.完全缓冲,意味着只有在以下情况才进行I/O:缓冲区满;进程调用fflush或者进程调用exit退出。标准I/O缓冲区大小通常为8192.
2.行缓冲:遇到一个换行符;进程调用fflush或者进程调用exit退出。
3.不缓冲,意味着每次调用标准I/O函数都进行I/O。
大部分UNIX的标准I/O遵循了以下原则
1.标准错误输出总是不缓冲
2。标准输入和标准输出是全缓冲的,除非它们是一个终端设备,那样它们是行缓冲的。
3.其他的流逗是全缓冲的,除非他们是一个终端设备,那样它们是行缓冲的。
套接口不是终端设备;有一些标准I/O库对大于255的文件描述符处理有问题。
事务TCP
在TCP基础上做了少量修改,以避免在最近通信过的主机之间进行三次握手(客户和服务器首次通信还是需要握手的,以后只要高速缓存的信息还没有过时就不需要握手)。
T/TCP把SYN、FIN和数据合并到单个分节中,前提是数据的长度小于MSS。T/TCP保持了TCP的可靠性。