这部分是高级插座 I/O 。

设置套接字超时报警,使用更方便的数据传输功能。

套接字 I/O 设置操作超时有三种方法:

  1. 转让 alarm 性能,制作时,它指定超时 SIGALRM 信号;
  2. 在 select 函数中设置超时堵塞等待 I/O,以替代直接堵塞在 read 或write 调用上;
  3. 使用 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_set rset;
struct timeval tv; /* 初始化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 */ int
Read_timeo(int fd, int sec)
{
int n; 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 标志的功能:

  1. MSG_DONTROUTE:本标志告知内核。目的主机在某个直接连接的本地网络上,因而无需运行路由表查找。
  2. MSG_DONTWAIT:本标志在无需打开对应套接字的非堵塞标志的前提下,把单个 I/O 操作暂时指定为非堵塞,接着运行 I/O 操作,然后关闭非堵塞标志;
  3. MSG_OOB:若协议支持,则可发送带外数据;
  4. MSG_PEEK :本标志适用于 recv 和 recvfrom 函数,它同意查看已可读取的数据,并且系统不在 recv 或 recvfrom 返回后丢弃这些数据。
  5. 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 网络编程》

版权声明:本文博主原创文章,博客,未经同意不得转载。

《网络编程》先进 I/O的更多相关文章

  1. 从零开始学Python第八周:网络编程基础(socket)

    Socket网络编程 一,Socket编程 (1)Socket方法介绍 Socket是网络编程的一个抽象概念.通常我们用一个Socket表示"打开了一个网络链接",而打开一个Soc ...

  2. python之网络编程

    本地的进程间通信(IPC)有很多种方式,但可以总结为下面4类: 消息传递(管道.FIFO.消息队列) 同步(互斥量.条件变量.读写锁.文件和写记录锁.信号量) 共享内存(匿名的和具名的) 远程过程调用 ...

  3. Python 网络编程(一)

    Python 网络编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. ...

  4. JAVA基础知识之网络编程——-网络通信模型(IO模型)

    <Unix网络编程:卷1>中介绍了5中I/O模型,JAVA作为运行在宿主机上的程序,底层也遵循这5中I/O模型规则.这5中I/O模型分别是: 阻塞式IO 非阻塞式IO I/O复用 信号驱动 ...

  5. Python3 网络编程

    虽然大家现在对互联网很熟悉,但是计算机网络的出现比互联网要早很多. 计算机为了联网,就必须规定通信协议,早期的计算机网络,都是由各厂商自己规定一套协议,IBM.Apple和Microsoft都有各自的 ...

  6. 完毕port(CompletionPort)具体解释 - 手把手教你玩转网络编程系列之三

       手把手叫你玩转网络编程系列之三    完毕port(Completion Port)具体解释                                                    ...

  7. Winpcap网络编程十之Winpcap实战,两台主机通过中间主机通信

    注:源码等等的我不会全然公开的,此篇文章写出来为大家的网络编程或者课程设计提供一定的思路.. 好,本次我们须要完毕的任务是: 完毕两台主机通过中间主机的数据通信(网络层) 添加基于IP地址的转发功能 ...

  8. Socket网络编程详解

    一,socket的起源 socket一词的起源 在组网领域的首次使用是在1970年2月12日发布的文献IETF RFC33中发现的, 撰写者为Stephen Carr.Steve Crocker和Vi ...

  9. Netty与网络编程

    Netty什么? Netty项目是一个提供异步事件驱动网络应用框架和快速开发可维护的高性能高扩展性服务端和客户端协议工具集的成果.换句话说,Netty是一个NIO客户端服务端框架,它使得快速而简单的开 ...

随机推荐

  1. target,currentTarget,delegateTarget,srcElement

    第一种情况:就是IE9+和其他现代浏览器,支持addEventListener方法.其结果是: this总是等于currentTarget currentTarget总是事件监听者 target总是事 ...

  2. Cocos2d-x3.2总结---使用物理引擎进行碰撞检测

    [转自]: http://blog.csdn.net/cbbbc/article/details/38541099 通常在游戏简单逻辑判断和模拟真实的物理世界时,我们只需要在定时器中判断游戏中各个精灵 ...

  3. 花非花-记一次linux上运行时报找不到库函数错误

    简介: --->:表示依赖 exe ---> a.so ---> utility.so 问题描述: exe运行起来报a.so中的函数f未定义. 解决过程: 一·nm a.so nm ...

  4. css3之box-sizing

    css盒子模型中包括几种重要的属性,包括margin.border.padding以及content.但浏览器对其盒子模型的解释则有所不痛,启用标准模式还是IE(怪)模式是与当前页面的文档声明相关的. ...

  5. HexColorPicker 让选色变得更简单[for Mac]

    开发iOS的筒子看过来,走过路过,一不小心就错过~ Xcode里的颜色选择器,不能让你随意制定十六进制的颜色,让选色变成了一种折磨,然而作为开发者和设计师又得经常要用到. 现在有了HexColorPi ...

  6. centos账户的uid和gid

    修改/etc/passwd和/etc/group文件的UID和GID为0,可以获得root权限,不过不推荐~ UID和GID Linux系统如何区别不同的用户呢?可以很自然地想到,使用不同的用户名应该 ...

  7. JQUERY1.9学习笔记 之内容过滤器(一) 包含选择器

    描述:选择包含指定文本的所有元素.jQuery( ":contains(text)" ) text:一串大小写敏感的文本. 例:找出所有包含"john"的div ...

  8. 深入理解javascript闭包(一)

    原文转自脚本之家(http://www.jb51.net/article/24101.htm) 闭包(closure)是Javascript语言的一个难点,也是它的特色,很多高级应用都要依靠闭包实现. ...

  9. Raspberry PI Model B+ (LCD显示CPU温度)

    Title:Raspberry PI Model B+ (LCD显示CPU温度)  --2015-01-29 17:44 买了块连接Raspberry PI Model B+的LCD显示器,上面没写C ...

  10. 读取pdf文件 .选择了itextsharp 库

    此库还是比较成熟.看博客园很多文章都介绍了此库 用法 如果项目用到读取pdf.  我这只是提供个思路.或者提供个方法.用itextsharp 能方便实现 StringBuilder text = ne ...