泡沫制品技术支持东莞网站建设,创网址,桔子建站官网,宝塔怎么安装wordpress对于socket#xff0c;最基本的输入输出函数就是#xff0c;read和write。它们最基本#xff0c;同样功能也是最少的。Unix中有几个函数是read/write的变种#xff0c;在基本的输入输出功能上#xff0c;还增加了一些非常使用的功能和特性#xff0c;它们是#xff1a;r…对于socket最基本的输入输出函数就是read和write。它们最基本同样功能也是最少的。Unix中有几个函数是read/write的变种在基本的输入输出功能上还增加了一些非常使用的功能和特性它们是recv/send、readv/writev和recvmsg/sendmsg。1、socket超时的实现一般来说要在对socket的I/O操作实现超时有3种方式·注册SIGALRM信号的处理函数然后调用alrm则若对socket的I/O操作阻塞时间大于alrm注册的时间则在alrm时间到时会阻塞会被SIGALRM打断。这样做有个缺点就是alrm的调用会影响到同一进程的其他alrm调用。某些系统中系统调用被信号打断后会自动重新调用在这种系统中可以使用setlongjmp/siglongjmp来跳出。·使用SO_RCVTIMEO/SO_SNDTIMEO选项。注意并不是所有的系统都支持这两个选项。·用select代替read/write。前面两种方式只对socket进行输入/输出有效而最后一种除了输入/输出以外还对connect有效(socket必须处于nonblocking模式下)。2、recv/send函数原型#include 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);Both return: number of bytes read or written if OK, –1 on error可以看到前3个参数和read/write是一样的很好理解。最后一个flag参数的值可以是一下几个常量中的一个或多个的或·MSG_DONTROUTE 适用于send表示此次发送的数据包不经过系统的路由过程直接发送。·MSG_DOWAIT 适用于recv/send表示此次操作采用非阻塞方式(不一定所有的系统都支持此项)。·MSG_OOB 适用于recv/send表示发送或接收“out-of-band data”(只能发送1个字节的out-of-band data)。·MSG_PEEK 适用于recv表示此次读取的是缓存中数据的副本。·MSG_WAITALL 适用于recv表示调用将直接阻塞知道指定的指定的字节数被读出(若中途遇到EOF或出错则也会少于指定字节数)。2、readv/writev原型#include ssize_t readv(int filedes, const struct iovec *iov, int iovcnt);ssize_t writev(int filedes, const struct iovec *iov, int iovcnt);Both return: number of bytes read or written, –1 on error这两个函数名字和read/write只多一个字母v功能更强大。readv可以将数据读入到多个buffer中而writev可以将多个buffer的数据输出。iov指向一个iovec的数组iovcnt为数组大小(linux中最大为1024)。iovec结构如下struct iovec {void *iov_base; /* starting address of buffer */size_t iov_len; /* size of buffer */};iov_base指向buffer的起始地址iov_len为buffer的大小。3、recvmsg/sendmsg这对函数可以说是socket输入/输出的“万金油”它们可以替代之前提到过的输入/输出函数。原型如下#include ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);ssize_t sendmsg(int sockfd, struct msghdr *msg, int flags);Both return: number of bytes read or written if OK, –1 on error大部分重要的都放在msg指向的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() */};msg_name指向相应的socket地址msg_namelen为地址大小这两个成员仅在socket未连接的情况下使用(需设置IP_RECVDSTADDR)对于已连接的socket(如TCP和已连接的UDP)msg_name应置为NULLmsg_namelen为0。在使用recvmsg时msg_namelen是值-结果类型。msg_iov与msg_iovlen和readv/writev表示的意义一样。msg_flags仅对recvmsg有用当recvmsg调用时将flags赋值给msg_flags然后内核按照msg_flags进行操作返回时将更新(有可能)后的flags通过这个值返回sendmsg仅使用flags。附表flag总结msg_control成员很重要下一节将详细分析msg_controllen为msg_control大小。4、辅助数据辅助数据是指msghdr中的msg_control和msg_controllen成员它们又称谓“控制信息”。在某些情况下这些信息是非常有用的。附表辅助数据总结(直接截图凑活着看)辅助数据可以包含多条信息每条信息存放在cmsghdr的结构中struct cmsghdr {socklen_t cmsg_len; /* length in bytes, including this structure */int cmsg_level; /* originating protocol */int cmsg_type; /* protocol-specific type *//* followed by unsigned char cmsg_data[] */};注意数据区cmsg_data是可变的按需求分配。在处理cmsghdr时有5个实用的宏#include #include /* for ALIGN macro on many implementations */struct cmsghdr *CMSG_FIRSTHDR(struct msghdr *mhdrptr) ;#Returns: pointer to first cmsghdr structure or NULL if no ancillary datastruct cmsghdr *CMSG_NXTHDR(struct msghdr *mhdrptr, struct cmsghdr *cmsgptr) ;#Returns: pointer to next cmsghdr structure or NULL if no more ancillary data objectsunsigned char *CMSG_DATA(struct cmsghdr *cmsgptr) ;#Returns: pointer to first byte of data associated with cmsghdr structureunsigned int CMSG_LEN(unsigned int length) ;#Returns: value to store in cmsg_len given the amount of dataunsigned int CMSG_SPACE(unsigned int length) ;#Returns: total size of an ancillary data object given the amount of data图例代码片段struct msghdr msg;struct cmsghdr *cmsgptr;/* fill in msg structure *//* call recvmsg() */for (cmsgptr CMSG_FIRSTHDR(msg); cmsgptr ! NULL;cmsgptr CMSG_NXTHDR(msg, cmsgptr)) {if (cmsgptr-cmsg_level ... cmsgptr-cmsg_type ... ) {u_char *ptr;ptr CMSG_DATA(cmsgptr);/* process data pointed to by ptr */}}5、如何得知当前缓冲区中有多少数据使用MSG_PEEK即可这样可以获取缓冲区数据的副本而不是“消耗”副本的大小即为当前缓冲区中的数据量。需注意的是网卡每时每刻都有可能收到数据因此缓冲区的数据量是一直在变化的。6、socket I/O与标准I/O之前提到的函数(read/write、recv/send等)都是系统调用除了系统调用之外还可以使用标准I/O库操作socket。标准I/O库自带缓冲机制同时考虑了一些细节这给使用者带来一定的方便。但是方便的同时它带来了新的问题这些问题的根源就是缓冲机制避免一些“奇怪”问题的建议就是不要使用标准I/O库来处理socket。(见unpv13e 14.8)