UNIX网络编程 高级IO函数

套接字超时

在设计套接字的IO操作上设置超时的方法有以下三种

1)调用alarm,它在指定超时期慢时产生SIGALRM信号。这个方法设计信号处理,而信号处理在不同实现上

    存在差异,而且可能干扰进程中现有的alram调用

2)在select中阻塞等待I/O(select有内置的时间限制),以此代替直接阻塞在read或者write调用上

3)使用交心的SO_RCVTIMEO和SO_SNDTIMEO套接字选项。这个方法的问题在于并发所有实现都支持这

    两个套接字选项

以上三个技术都适用于输入和输出操作(如read,write以及recvfrom,sendto之类的变体)

recv和send函数

#include <sys/socket.h>
ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);
ssize_t send(int sockfd, const void * buff, size_t nbytes, int flags);

I/O函数的flag参数

flag 说明 recv send
MSG_DONTROUTE

绕过路由表查找

本标志高速内核目的主机在某个直接连接的本地网络上,因为无需

执行路由表查找

 
MSG_DONTWAIT

仅本操作非阻塞

本标志在无需打开响应套接字的非阻塞标志的前提下,把单个IO

操作临时定位非阻塞,接着执行IO操作,然后关闭非阻塞标志

MSG_OOB

发送或接收带外数据

对于send,本标志指明即将发送带外数据。TCP连接上只有一个

字节可以作为带外数据发送。对于recv本标志指明即将读入的是

带外数据而不是普通数据

MSG_PEEK

窥看外来消息

本标志适用于recv和recvfrom,它允许我们查看已可读取的数据,

而且系统不再recv或recvfrom返回后丢弃这些数据

 
MSG_WAITALL

等待所有数据

它告知内核不要在尚未读入请求数目的字节之前让一个读操作返回。

 

其他的还有MSG_EOR指示逻辑记录的结束

flags参数设计上存在一个基本问题,它是按值传递的而不是值--结果参数。因此它只用于进程向内核传递,而

内核无法向进程传回标志

readv和writev函数

#include <sys/uio.h>
ssize_t readv(int filedes, const struct iovec * iov, int iovcnt);
ssize_t writev(int filedes, const struct iovec * iov, int iovcnt);
//返回: 读到或写出的字节数,出错时为-1

//iovec结构体如下
struct iovec {
    void *iov_base;   //buffer的起始地址
    size_t iov_len;    //buffer数量
};

recvmsg和sendmsg函数

#include <sys/socket.h>
ssize_t recvmsg(int sockfd, struct msghdr * msg, int flags); 
ssize_t sendmsg(int sockfd, struct msghdr * msg, int flags);
 //返回: 成功时为读入或写出的字节数,出错时为-1

//这两个函数把大部分参数封装到一个msghdr结构体中
struct msghdr {
  void         *msg_name;        /* protocol address */
  socklen_t     msg_namelen;     /* size of protocol address */
  struct iovec *msg_iov;         /* scatter/gather array */
  int           msg_iovlen;      /* # elements in msg_iov */
  void         *msg_control;     /* ancillary data (cmsghdr struct) */
  socklen_t     msg_controllen;  /* length of ancillary data */
  int           msg_flags;       /* flags returned by recvmsg() */
};

 

 

假设从198.6.38.100端口2000达到一个170字节的UDP数据报,它的目标IP地址为206.168.112.96

下图是recvmsg返回时msghdr结构体重的所有信息

1)msg_那么成员指向的缓冲区被填以一个套接字地址结构,其中所有受到数据报的源IP地址和源UDP端口

2)msg_namelen成员(值--结构参数)被更新为存放在msg_name所指缓冲区中的数据量

3)所收取数据报的前100字节数据放在第一个缓冲区中,中间60字节放在第二个缓存区中,最后10个字节数据

   放在第三个缓冲区

4)msg_control成员指向的缓冲区被填以一个cmsghdr结构,该cmsghdr结构中,cmsg_len成员值为16,

    cmsg_level成员值为IPPROTO_IP,cmsg_type成员值为IP_RECVDSTADDR,随后4个字节存放所有

    收到UDP数据报的目的IP地址

5)msg_controllen成员被更新为所存放辅助数据的实际数据量,也是一个值--结果参数

6)msg_flags成员同样被recfmsg更新,不过没有标志返回给进程

 

五组I/O函数对比

函数 任何描述符 仅套接字描述符 单个读/写缓冲区 分散/集中读写 可选标志 可选对端地址 可选控制信息

read

write

         

readv

writev

         

recv

send

       

recvfrom

sendto

     

recvmsg

sendmsg

   

猜你喜欢

转载自xxniao.iteye.com/blog/2261123