TCP高级应用
文件I/O方式
阻塞式
应用程序对驱动文件在进行IO操作的时候,一般分为阻塞和非阻塞两种模式,针对阻塞IO模式来说,如果APP不能操作对应的文件,那么对文件的访问进程就会被挂起来,一直等到可以获取到设备资源后才能执行。Linux驱动程序中,通过一个叫做等待队列(wait queue)的机制来唤醒被的阻塞操作。
非阻塞式
非阻塞IO是不会将文件操作进程挂起来进入休眠状态,而是不停的轮训等待直到资源可以被使用或者放弃。
多路复用I/O
依旧是阻塞方式等待文件IO,但可以同时等待多个文件描述符。
让一个进程同时监视多个socket,一旦有socket数据准备完成,便可以直接进行数据拷贝过程。
select
int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout);
/*maxfdp——传入参数,集合中所有文件描述符的范围,即最大文件描述符值+1
readfds——传入传出参数,select调用时传入要监听的可读文件描述符集合,select返回时传出发生可读事件的文件描述符集合
writefds——传入传出参数,select调用时传入要监听的可写文件描述符集合,select返回时传出发生可写事件的文件描述符集合
errorfds——传出参数,select返回时传出发生事件(包括可读和可写)中异常事件的文件描述符集合
timeout——传入参数,设置select阻塞的时间。若设置为NULL,则select一直阻塞直到有事件发生;
若设置为0,则select为非阻塞模式,执行后立即返回;
若设置为一个大于0的数,即select的阻塞时间,若阻塞时间内有事件发生就返回,否则时间到了立即返回*/
//fd_set是自定义的一个数据结构,可看作一个集合,存放可读、可写或异常事件的文件描述符。
//fd_set集合通常有以下四个宏来操作:
void FD_ZERO(fd_set *fdset); //清空fdset中所有文件描述符
void FD_SET(int fd,fd_set *fdset); //添加文件描述符fd到集合fdset中
void FD_CLR(int fd,fd_set *fdset); //将文件描述符fd从集合fdset中去除
int FD_ISSET(int fd,fd_set *fdset); //判断文件描述符fd是否在集合fdset中
struct timeval
{
long tv_sec;
long tv_usec;
};
pselect
int pselect(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, const struct timespec *timeout, const sigset_t *sigmask);
//pselect 使用 timespec 结构,而不使用 timeval 结构
struct timespec
{
time_t tv_sec; //秒
long tv_nsec; //纳秒
}; //timespec的成员 tv_nsec 指定纳秒数,而 timeval 的该成员 tv_usec 指定微秒数。
//第6个参数:一个指向信号掩码的指针。该参数允许程序先禁止递交某些信号,再测试由这些当前被禁止的信号处理函数设置的全局变量,然后调用 pselect,告诉它重新设置信号掩码。
poll
int poll(struct poll *fds, unsigned int nfds, int timeout);
struct pollfd{
int fd;
short events;
short revents;
};
//poll使用一个pollfd的指针实现。pollfd结构包含了要监视的event和发生的event,不在使用select参数传值的方式。同时pollfd并没有最大数量的限制(但数量过大性能也会下降)。和select一样,poll返回后,需要轮询pollfd来或许就绪的描述符。
poll()函数监视在fds数组指明的一组文件描述符上发生的动作,当满足条件或超时的时候会退出。
fds:指向结构pollfd数组的指针,监视的文件描述符和条件放在里面。
nfds:比监视的最大描述符的值大1
timeout:超时时间,单位毫秒,负值表示永远等待。
pollfd结构中events和revents的值及含义如下:
- POLLIN 普通或优先级带数据可读
- POLLRDNORM 普通数据可读
- POLLRDBAND 优先级带数据可读
- POLLPRI 高优先级数据可读
- POLLOUT 普通数据可写
- POLLWRNORM 普通数据可写
- POLLWRBAND 优先级带数据可写
- POLLERR 发生错误
- POLLHUP 发生挂起
- POLLNVAL 描述字不是一个打开的文件
ppoll
int ppoll(pollfd* fds,nfds_t nfds,
const timespec* timeout,const sigset_t* sigmask);
//与poll()区别:
// 超时时间采用了纳米级的变量
// 可以在ppoll函数的处理过程中挂接临时的信号掩码。
信号驱动I/O
异步处理。
信号驱动式I/O是指进程预先告知内核,使得当某个描述符上发生某事时,内核使用信号通知相关进程。
异步I/O是进程执行I/O系统调用(读或写)告知内核启动某个I/O操作,内核启动I/O操作后立刻返回到进程,进程在I/O操作发生期间继续执行,当操作完成或遭遇错误时,内核以进程在I/O系统调用中指定的某种方式通知进程,
socket文件描述符属性
get/setsockopt
int getsockopt(int socket, int level, int option_name,
void *restrict option_value, socklen_t *restrict option_len);
int setsockopt( int socket, int level, int option_name,const void *option_value, size_t ,ption_len);
功能: 获取一个套接字的选项
参数:
-
socket:文件描述符
-
level:协议层次
- SOL_SOCKET 套接字层次
- IPPROTO_IP ip层次
- IPPROTO_TCP TCP层次
-
option_name:选项的名称(套接字层次)
-
SO_BROADCAST 允许发送广播数据 int
-
SO_DEBUG 允许调试 int
-
SO_DONTROUTE 不查找路由 int
-
SO_ERROR 获得套接字错误 int
-
SO_KEEPALIVE 保持连接 int
-
SO_LINGER 延迟关闭连接 struct linger
-
SO_OOBINLINE 带外数据放入正常数据流 int
-
SO_RCVBUF 接收缓冲区大小 int
-
SO_SNDBUF 发送缓冲区大小 int
-
SO_RCVLOWAT 接收缓冲区下限 int
-
SO_SNDLOWAT 发送缓冲区下限 int
-
SO_RCVTIMEO 接收超时 struct timeval
-
SO_SNDTIMEO 发送超时 struct timeval
-
SO_REUSERADDR 允许重用本地地址和端口 int
-
SO_TYPE 获得套接字类型 int
-
SO_BSDCOMPAT 与BSD系统兼容 int
-
IP_HDRINCL 在数据包中包含IP首部 int
-
IP_OPTINOS IP首部选项 int
-
IP_TOS 服务类型
-
IP_TTL 生存时间 int
-
TCP_MAXSEG TCP最大数据段的大小 int
-
TCP_NODELAY 不使用Nagle算法 int
-
-
option_value:获取/设置的选项的值
-
option_len:value的长度
返回值:
成功:0
失败:-1
fcntl
fcntl系统调用可以用来对已打开的文件描述符进行各种控制操作以改变已打开文件的的各种属性
int fcntl(int filedes,int cmd, ... /*int arg*/);
//返回值:成功依赖cmd的值,失败返回-1;
四个命令有特有的返回值:
F_DUPFD:返回一个新的文件描述符;
F_GETFD、F_GETFL:返回相应的标志;
F_GETOWN: 返回一个正的或者负的进程组ID;
fcntl函数有5种功能:
- 复制一个现有的描述符(cmd=F_DUPFD);
- 获得/设置文件描述符标记(cmd=F_GETFD或F_SETFD);
- 获得/设置文件状态标记(cmd=F_GETFL或F_SETFL);
- 获得/设置异步I/O所有权(cmd=F_GETOWN或F_SETOWN);
- 获得/设置记录锁(cmd=F_GETLK , F_SETLK或F_SETLKW);
- F_DUPFD:复制文件描述符filedes。新文件描述符作为函数的返回。类似于pud,pud2;
- F_GETFD:对应于filedes的文件描述符标志作为函数的值返回。当前只定义了一个文件描述符标志FD_CLOEXEC。
- F_SETFD:对于filedes设置文件描述符标志。新标志值按第三个参数(取为整型值)设置。
- F_GETFL:对应于文件状态标志作为函数值返回。
-
- O_RDONLY 只读打开
- O_WRONLY 只写打开
- O_RDWR 为读、写打开
- O_APPEND 每次写时追加
- O_NONBLOCK 非阻塞模式
- O_SYNC 等待写完成(数据和属性)
- O_DSYNC 等待写完成(数据)
- O_RSYNC 同步读、写
- O_FSYNC 等待写完成(进FreeBSD和Mac OS X)
- O_ASYNC 异步I/O(进FreeBSD和Mac OS X)
- F_SETFL:将文件状态标志设置成为第三个参数的值(取整形值)。
- F_GETOWN:取当前接受SIGIO和SIGURG信号的进程ID和进程组ID.正的arg指定一个进程ID,负的arg表示等于arg绝对值的一个进程中ID。
ioctl
ioctl是设备驱动程序中对设备的I/O通道进行管理的函数 。所谓对I/O通道进行管理,就是对设备的一些特性进行控制,例如串口的传输波特率、马达的转速等等
int ioctl(int fd, int cmd, ...) ;
参数: fd是用户程序打开设备时使用open函数返回的文件标示符,cmd是用户程序对设备的控制命令,后面是一些补充参数,一般最多一个,这个参数的有无和cmd的意义相关。