###########################################################
套接字的IO函數
IO函数都涉及到阻塞问题,所以要考虑超时问题.
推荐使用sendmsg和recvmsg函数。
对socket的操作:
#include<sys/types.h>
#include <sys/socket.h>
ssize_t recv(int sockfd, void*buff, size_t len, int flags);
ssize_t send(int sockfd, constvoid *buff, size_t len, int flags);
ssize_t recvfrom(int sockfd,void *buff, size_t len, int flags, struct sockaddr *servaddr, socklen_t*addrlen);
ssize_t sendto(int sockfd,const void *buff, size_t len, int flags, const struct sockaddr *servaddr,socklen_t addrlen);
ssize_t recvmsg(int sockfd,struct msghdr *msg, int flags);
ssize_t sendmsg(int sockfd,const struct msghdr *msg, int flags);
flags:
MSG_DONTROUTE:发送绕过路由表查找
MSG_DONTWAIT:接收操作非阻塞
MSG_OOB:发送或接收带外数据
MSG_WAITALL:接收等待所有数据
MSG_PEEK:接收窥看外来消息
struct msghdr
{
void *msg_name; // 未连接对端套接字地址
socklen_t msg_namelen; //对端地址长度
struct iovec *msg_iov; // 缓冲区的地址信息
size_t msg_iovlen; // 缓冲区个数
void *msg_control; //指向辅助数据
size_t msg_controllen; //辅助数据长度
int msg_flags; // recvmsg返回的标志
};
辅助数据的组成:cmsghdr + 填充字节 + 数据
struct cmsghdr
{
socklen_t cmsg_len;// 填充字节+数据+cmsghdr的长度
int cmsg_level;//原始协议IPPROTO_XXX
int cmsg_type;//协议专用类型SCM_XXX
__extension__ unsigned char _cmsg_data __flexarr;//数据
};
可用的宏:
#include <sys/socket.h>
#include <sys/param.h>
struct cmsghdr *CMSG_FIRSTHDR(structmsghdr *mhdrptr);
返回第一个cmsghdr结构的指针;
struct cmsghdr *CMSG_NXTHDR(structmsghdr *mhdrptr, struct cmsghdr *cmsgptr);
返回下一个cmsghdr结构的指针;
unsigned char *CMSG_DATA(structcmsghdr *cmsgptr);
返回第一个cmsghdr结构的数据的指针;
unsigned int CMSG_LEN(unsignedint legth);
unsigned int CMSG_SPACE(unsignedint length);
对复合缓冲区的操作:
#include <sys/uio.h>
ssize_t readv(int fd, conststruct iovec *iov, int iovcnt);
将fd中的数据读到散布的缓冲区iov中。
ssize_t writev(int fd, conststruct iovec *iov, int iovcnt);
从散布的缓冲区iov中将数据聚集写到fd中。
ssize_t preadv(int fd, conststruct iovec *iov, int iovcnt, off_t offset);
ssize_t pwritev(int fd, conststruct iovec *iov, int iovcnt, off_t offset);
struct iovec
{
void *iov_base; //buffer address
size_t iov_len; //buffer length
};
iovcnt表示结构数组iov中的结构个数,不能超过IOV_MAX。
对文件描述符的操作:
#include <unistd.h>
ssize_t read(int fd, void*buff, size_t count);
ssize_t write(int fd, constvoid *buf, size_t count);
###########################################################
IO复用(使用select函数或poll函数):
在网络编程时有标准IO和套接字IO等多个IO时,进程需要一种预先告知内核的能力,使得内核进程指定的一个或多个IO条件就绪就通知进程,这就是IO复用。
一个输入操作通常需要两个阶段:
1. 等待数据准备好
2. 从内核向进程复制数据
等待的三种条件:
一 怎样判断一个套接字准备好读:
3. 套接字接受缓冲区的数据字节数大于等于套接字接收缓冲区低水位标记的当前值。SO_RCVLOWAT设置这个值,unix默认为1,linux默认为18
2.该连接的读半部关闭(对端发送一个FIN)
3.该套接字是一个监听套接字,且已完成的连接数不为0
4.该套接字有一个套接字错误待处理。
二 怎样判断一个套接字准备好写:
1. 套接字发送缓冲区中的可用空间字节数大于等于套接字发送缓冲区低水位值,
SO_SNDLOWAT设置这个值,unix默认值为2048,linux默认为19.
2.该连接的写半部关闭
3.使用非阻塞的connect套接字已建立连接,或connect已经以失败告终。
4.该套接字有一个套接字错误待处理。
三 异常条件:
1.带外数据