《网络编程》高级 I/O
来源:互联网 发布:linux打开终端快捷键 编辑:程序博客网 时间:2024/05/22 14:41
本节是套接字的高级 I/O 。为套接字设置超时闹钟,使用更加方便的数据传输函数。套接字的 I/O 操作上设置超时有三种方法:
- 调用 alarm 函数,在它指定超时到期时产生 SIGALRM 信号;
- 在 select 函数中设置超时阻塞等待 I/O,以替代直接阻塞在 read 或write 调用上;
- 使用 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项(这两个选项只是一部分实现支持);
下面使用 alarm 产生的 SIGALRM 信号为 connect 函数设置超时,当然系统会为 connect 函数设置超时限制,这里我们只是表示 SIGALRM 信号在设置超时的作用。
#include <signal.h>#include <errno.h>#include <stdio.h>#include <unistd.h>#include <sys/socket.h>typedef void Sigfunc(int);extern void err_sys(const char *,...);static Sigfunc *M_signal(int signo, Sigfunc *func);static Sigfunc *MySignal(int signo, Sigfunc *func);static void connect_alarm(int);int Myconnect_timo(int sockfd, const struct sockaddr *saptr, socklen_t salen, int nsec){ Sigfunc *sigfunc; int n; /* SIGALRM 信号处理函数,并保存现有信号处理函数 */ sigfunc = MySignal(SIGALRM, connect_alarm); /* 设置alarm超时 */ if(alarm(nsec) != 0)/* 若已经设置了超时,则alarm返回的是当前剩余秒数,否则返回0 */ printf("alarm was already set\n");/* 提示:已经设置过alarm超时 */ if( (n = connect(sockfd, saptr, salen)) < 0) {/* 由超时处理函数调用中断导致连接失败,则关闭套接字,并设置是由超时导致的失败 */ close(sockfd); if(errno == EINTR) errno = ETIMEDOUT; } /* 关闭 alarm */ alarm(0); /* 恢复原来的处理函数 */ MySignal(SIGALRM, sigfunc); return(n);}static void connect_alarm(int signo){ printf("flag: %d\n", signo); return;/* just interrupt the connect */}static Sigfunc *MySignal(int signo, Sigfunc *func){ Sigfunc *sigfunc; if( (sigfunc = M_signal(signo, func)) == SIG_ERR) err_sys("signal error"); return (sigfunc);}static Sigfunc *M_signal(int signo, Sigfunc *func){ struct sigaction act, oact; /* 设置信号处理函数 */ act.sa_handler = func; /* 初始化信号集 */ sigemptyset(&act.sa_mask); act.sa_flags = 0; if(signo == SIGALRM) {/* 若是SIGALRM信号,则系统不会自动重启 */#ifdef SA_INTERRUPT act.sa_flags |= SA_INTERRUPT;#endif } else {/* 其余信号设置为系统会自动重启 */#ifdef SA_RESTART act.sa_flags |= SA_RESTART;#endif } /* 调用 sigaction 函数 */ if(sigaction(signo, &act, &oact) < 0) return(SIG_ERR); return(oact.sa_handler);}
使用 select 函数为 recvfrom 设置超时,有关select 函数的讲解可以参考文章《I/O 多路复用》。
#include <sys/select.h>#include <stdlib.h>extern void err_sys(const char *,...);/* 在指定的时间内等待描述符变为可读 */int readable_timeo(int fd, int sec){fd_setrset;struct timevaltv; /* 初始化fd_set 结构,并添加描述符 */FD_ZERO(&rset);FD_SET(fd, &rset); /* 设置超时的时间 */tv.tv_sec = sec;/* 秒数 */tv.tv_usec = 0;/* 微秒 */ /* 调用select函数,使进程阻塞于select的超时等待描述符变为可读 */return(select(fd+1, &rset, NULL, NULL, &tv));/* 4> 0 if descriptor is readable */}/* end readable_timeo */intRead_timeo(int fd, int sec){intn;if ( (n = readable_timeo(fd, sec)) < 0)err_sys("readable_timeo error");return(n);}
使用 使用 SO_RCVTIMEO 和 SO_SNDTIMEO 套接字选项,使用这两个套接字选项设置描述符时,其超时设置将应用于该描述符的所有读或写操作上,SO_RCVTIMEO 套接字选项只能应用于读操作,而 SO_SNDTIMEO 套接字选项只能应用于写操作。这两者仅支持一部分实现,例如在 connect 函数不能使用这两个套接字选项。
recv 和 send 函数
/* 数据传输 *//* * 函数功能:发送数据; * 返回值:若成功则返回发送的字节数,若出错则返回-1; * 函数原型: */#include <sys/socket.h>ssize_t send(int sockfd, void *buff, size_t nbytes, int flags);/* * 说明 * 该函数的功能类似与write函数,除了有标识符flags之外,其他的相同; * flags标识符的取值如下: * (1)MSG_DONTROUTE 勿将数据路由出本地网络 * (2)MSG_DONTWAIT 允许非阻塞操作 * (3)MSG_EOR 如果协议支持,此为记录结束 * (4)MSG_OOB 如果协议支持,发送带外数据 * * 若send成功返回,并不必然表示连接另一端的进程接收数据,只能说数据已经无错误地发送到网络; * * 对于支持为报文设限的协议,若报文超过协议所支持的最大尺寸,send失败并将errno设为EMSGSIZE; * 对于字节流协议,send会阻塞直到整个数据被传输; *//* * 函数功能:接收数据; * 返回值:以字节计数的消息长度,若无可用消息或对方已经按序结束则返回0,若出错则返回-1; * 函数原型: */#include <sys/socket.h>ssize_t recv(int sockfd, void *buff, size_t nbytes, int flags);/* * 说明 * 该函数的功能类似与read函数,除了有标识符flags之外,其他的相同; * flags标识符的取值如下: * (1)MSG_PEEK 返回报文内容而不真正取走报文,即查看可读取数据 * (2)MSG_TRUNC 即使报文被截断,要求返回的是报文的实际长度 * (3)MSG_WAITALL 等待直到所有数据可用 * (4)MSG_OOB 如果协议支持,发送带外数据 * (5)MSG_DONTWAIT 允许非阻塞操作 * */下面是 flags 标志的功能:
- MSG_DONTROUTE:本标志告知内核,目的主机在某个直接连接的本地网络上,因而无需执行路由表查找;
- MSG_DONTWAIT:本标志在无需打开相应套接字的非阻塞标志的前提下,把单个 I/O 操作临时指定为非阻塞,接着执行 I/O 操作,然后关闭非阻塞标志;
- MSG_OOB:若协议支持,则可发送带外数据;
- MSG_PEEK :本标志适用于 recv 和 recvfrom 函数,它允许查看已可读取的数据,而且系统不在 recv 或 recvfrom 返回后丢弃这些数据;
- MSG_WAITALL:等待所有数据可用;
readv 和 writev 函数
这两个函数类似于 read 和 write 函数,但是它们支持多个缓冲区操作。其定义如下:
/* 读、写多个非连续的缓冲区 *//* * 函数功能:读取数据到多个非连续的缓冲区,或从多个非连续缓冲区写数据到文件; * 返回值:若成功则返回已读、写的字节数,若出错则返回-1; * 函数原型: */#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);/* * 说明: * iovec的指针结构如下: */struct iovec{ void *iov_base; /* starting address of buffer */ size_t iov_len; /* size of buffer */};
recvmsg 和 sendmsg 函数
这两个函数是通用的 I/O 函数,前面介绍的 I/O 函数都可以使用这两个函数替换。其定义如下:
ssize_t recvmsg(int sockfd, struct msghdr *msg, int flags);ssize_t sendmsg(int sockfd, const struct msghdr *msg, int flags);/* * 说明 * 该函数可以使用不止一个的选择来通过套接字发送数据,可以指定多重缓冲区传输数据,类似与readv函数; * msghdr结构至少包含以下成员: */struct msghdr{ void *msg_name; /* optional address */ socklen_t msg_namelen; /* address size in bytes */ struct iovec *msg_iov; /* array of IO buffers */ int msg_iovlen; /* number of elements in array */ void *msg_control; /* ancillary data */ socklen_t msg_controllen; /* number of ancillary bytes */ int msg_flags; /* flags for recevied message */};
参考资料:
《Unix 网络编程》
2 0
- 《网络编程》高级 I/O
- 网络编程联系-高级I/O
- UNIX网络编程------高级I/O函数(十四)
- Linux网络编程(八) 高级I/O函数
- 网络编程API-中 (高级I/O函数)
- UNIX网络编程卷一:第十四章 高级I/O
- 《UNIX网络编程 卷1》 笔记: 高级I/O函数
- UNIX高级编程-高级I/O
- UNIX高级编程-高级I/O
- 《网络编程》I/O 模型
- 《网络编程》I/O 多路复用
- 网络编程 I/O模型
- 网络编程:I/O复用
- 网络编程:I/O复用
- UNIX环境高级编程----文件I/O
- UNIX环境高级编程----标准I/O
- 《unix高级环境编程》文件I/O
- 《unix高级环境编程》文件I/O
- GridReport 排序
- c语言--数组&排序
- Webots入门(一)-build up a world
- c#生成注册码的两种方法(mac地址与IP地址)
- httpClient模拟浏览器登陆之谜
- 《网络编程》高级 I/O
- Weblogic 10.3.0 在 AIX6.1、JDK1.6 下挂起解决方法
- 在excel中如何用VLOOKUP进行模糊查找
- 工业水处理:化工行业高纯水设备
- 一个表单中多个按钮实现不同功能
- [Elasticsearch] 邻近匹配 (二) - 多值字段,邻近程度与相关度
- C#生成注册码
- c语言--字符串
- HTML5+Ajax+Jquery调用Google搜索API实现搜索引擎,支持web,image,news,vedio4种模式!