Linux 网络编程详解十一
/**
* read_timeout - 读超时检测函数,不含读操作
* @fd:文件描述符
* @wait_seconds:等待超时秒数,如果为0表示不检测超时
* 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
* */
int read_timeout(int fd, unsigned int wait_seconds)
{
int ret = ;
if (wait_seconds > )
{
//定义文件描述符集合
fd_set readfds;
//清空文件描述符
FD_ZERO(&readfds);
//将当前文件描述符添加集合中
FD_SET(fd, &readfds);
//定义时间变量
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , &readfds, NULL, NULL, &timeout);
} while (ret == - && errno == EINTR);
//ret==-1时,返回的ret正好就是-1
if (ret == )
{
errno = ETIMEDOUT;
ret = -;
} else if (ret == )
{
ret = ;
}
}
return ret;
}
/**
* write_timeout - 写超时检测函数,不含写操作
* @fd:文件描述符
* @wait_seconds:等待超时秒数,如果为0表示不检测超时
* 成功返回0,失败返回-1,超时返回-1并且errno = ETIMEDOUT
* */
int write_timeout(int fd, unsigned int wait_seconds)
{
int ret = ;
if (wait_seconds > )
{
//定义文件描述符集合
fd_set writefds;
//清空集合
FD_ZERO(&writefds);
//添加文件描述符
FD_SET(fd, &writefds);
//定义时间变量
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , NULL, &writefds, NULL, &timeout);
} while (ret == - && errno == EINTR);
if (ret == )
{
errno = ETIMEDOUT;
ret = -;
} else if (ret == )
{
ret = ;
}
}
return ret;
}
/**
* accept_timeout - 带超时accept (方法中已执行accept)
* @fd:文件描述符
* @addr:地址结构体指针
* @wait_seconds:等待超时秒数,如果为0表示不检测超时
* 成功返回已连接的套接字,失败返回-1,超时返回-1并且errno = ETIMEDOUT
* */
int accept_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
{
int ret = ;
if (wait_seconds > )
{
/*
* 说明:accept和connect都会阻塞进程,accept的本质是从listen的队列中读一个连接,是一个读事件
* 三次握手机制是由TCP/IP协议实现的,并不是由connect函数实现的,connect函数只是发起一个连接,
* connect并非读写事件,所以只能设置connect非阻塞,而用select监测写事件(读事件必须由对方先发送报文,时间太长了)
* 所以accept可以由select管理
* 强调:服务端套接字是被动套接字,实际上只有读事件
* */
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(fd, &readfds);
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , &readfds, NULL, NULL, &timeout);
} while (ret == - && errno == EINTR);
if (ret == -)
{
return ret;
} else if (ret == )
{
ret = -;
errno = ETIMEDOUT;
return ret;
}
//成功无需处理,直接往下执行
}
//一旦检测出select有事件发生,表示有三次握手成功的客户端连接到来了
//此时调用accept不会被阻塞
if (addr != NULL)
{
socklen_t len = sizeof(struct sockaddr_in);
ret = accept(fd, (struct sockaddr *) addr, &len);
} else
{
ret = accept(fd, NULL, NULL);
}
return ret;
}
/**
* activate_nonblock - 设置套接字非阻塞
* @fd:文件描述符
* 成功返回0,失败返回-1
* */
int activate_nonblock(int fd)
{
int ret = ;
int flags = fcntl(fd, F_GETFL);
if (flags == -)
return -;
flags = flags | O_NONBLOCK;
ret = fcntl(fd, F_SETFL, flags);
if (ret == -)
return -;
return ret;
} /**
* deactivate_nonblock - 设置套接字阻塞
* @fd:文件描述符
* 成功返回0,失败返回-1
* */
int deactivate_nonblock(int fd)
{
int ret = ;
int flags = fcntl(fd, F_GETFL);
if (flags == -)
return -;
flags = flags & (~O_NONBLOCK);
ret = fcntl(fd, F_SETFL, flags);
if (ret == -)
return -;
return ret;
} /**
* connect_timeout - 带超时的connect(方法中已执行connect)
* @fd:文件描述符
* @addr:地址结构体指针
* @wait_seconds:等待超时秒数,如果为0表示不检测超时
* 成功返回0.失败返回-1,超时返回-1并且errno = ETIMEDOUT
* */
int connect_timeout(int fd, struct sockaddr_in *addr, unsigned int wait_seconds)
{
int ret = ;
//connect()函数是连接服务器,本来connect会阻塞,但是设置未阻塞之后,
//客户端仍然会三次握手机制,如果三次握手失败,那么客户端一定无法向文件描述符中写入数据
//如果连接成功,那么客户端就可以向文件描述符写入数据了,
//所以交给select监管的文件描述符如果可以写,说明连接成功,不可以写说明连接失败 //设置当前文件描述符未阻塞--设置非阻塞之后,
//connect在网络中非常耗时,所以需要设置成非阻塞,如果有读事件,说明可能连接成功
//这样有利于做超时限制
if (wait_seconds > )
{
if (activate_nonblock(fd) == -)
return -;
}
ret = connect(fd, (struct sockaddr *) addr, sizeof(struct sockaddr));
if (ret == - && errno == EINPROGRESS)
{
fd_set writefds;
FD_ZERO(&writefds);
FD_SET(fd, &writefds);
struct timeval timeout;
timeout.tv_sec = wait_seconds;
timeout.tv_usec = ;
do
{
ret = select(fd + , NULL, &writefds, NULL, &timeout);
} while (ret == - && errno == EINTR);
//ret==-1 不需要处理,正好给ret赋值
//select()报错,但是此时不能退出当前connect_timeout()函数
//因为还需要取消文件描述符的非阻塞
if (ret == )
{
errno = ETIMEDOUT;
ret = -;
} else if (ret == )
{
//ret返回为1(表示套接字可写),可能有两种情况,一种是连接建立成功,一种是套接字产生错误,
//此时错误信息不会保存至errno变量中,因此,需要调用getsockopt来获取。
int err = ;
socklen_t len = sizeof(err);
ret = getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &len);
if (ret == && err != )
{
errno = err;
ret = -;
}
//说明套接字没有发生错误,成功
}
}
if (wait_seconds > )
{
if (deactivate_nonblock(fd) == -)
return -;
}
return ret;
}
Linux 网络编程详解十一的更多相关文章
- TCP/UDP Linux网络编程详解
本文主要记录TCP/UDP网络编程的基础知识,采用TCP/UDP实现宿主机和目标机之间的网络通信. 内容目录 1. 目标2.Linux网络编程基础2.1 嵌套字2.2 端口2.3 网络地址2.3.1 ...
- Linux 网络编程详解九
TCP/IP协议中SIGPIPE信号产生原因 .假设客户端socket套接字close(),会给服务器发送字节段FIN: .服务器接收到FIN,但是没有调用close(),因为socket有缓存区,所 ...
- Linux 网络编程详解二(socket创建流程、多进程版)
netstat -na | grep " --查看TCP/IP协议连接状态 //socket编程提高版--服务器 #include <stdio.h> #include < ...
- Linux 网络编程详解一(IP套接字结构体、网络字节序,地址转换函数)
IPv4套接字地址结构 struct sockaddr_in { uint8_t sinlen;(4个字节) sa_family_t sin_family;(4个字节) in_port_t sin_p ...
- Linux 网络编程详解十
select int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *tim ...
- Linux 网络编程详解五(TCP/IP协议粘包解决方案二)
ssize_t recv(int s, void *buf, size_t len, int flags); --与read相比,只能用于网络套接字文件描述符 --当flags参数的值设置为MSG_P ...
- Linux 网络编程详解四(流协议与粘包)
TCP/IP协议是一种流协议,流协议是字节流,只有开始和结束,包与包之间没有边界,所以容易产生粘包,但是不会丢包. UDP/IP协议是数据报,有边界,不存在粘包,但是可能丢包. 产生粘包问题的原因 . ...
- Linux 网络编程详解十二
UDP的特点 --无连接 --基于消息的数据传输服务 --不可靠 --UDP更加高效 UDP注意点 --UDP报文可能会丢失,重复 --UDP报文可能会乱序 --UDP缺乏流量控制(UDP缓冲区写满之 ...
- Linux 网络编程详解八
TCP/IP协议三次握手机制 TCP/IP是全双工通道,两端都可以读写,三次握手机制就是验证TCP/IP是否是全双工通道 1.客户端调用connect()函数,阻塞客户端进程,客户端向服务器发送数据包 ...
随机推荐
- 接口测试中三种传参请求(Map、request、Integer)解析
注册企业接口传入的是一个request,查询企业接口传入的是一个integer:根据名称和国家名称模糊匹配接口传入的是一个Map:针对三种不同的传参我怎么作接口测试呢? 1 package com.w ...
- 原 ng-include用法分析以及多标签页面的简单实现方式
Demo:http://webenh.chinacloudsites.cn/Default/Demo2 在平时的项目开发中,应该会经常遇到上图所示的需求,就是在一个页面中有多个标签,被选中的标签颜色会 ...
- Iconfont-阿里巴巴矢量图标库
http://iconfont.cn/ 网站为:
- List 简单升\降序实现
public class User { public int Id { get; set; } public string Code { get; set; } } //示例 //升序 list.So ...
- ORACLE 查看RMAN的备份信息总结
关于Oracle数据库的RMAN备份,除了邮件外,是否能通过其它方式检查RMAN备份的成功与失败呢?其实我们可以通过下面SQL脚本来检查某个时间段备份失败的记录: SELECT * FROM V$RM ...
- linux的“自动化”
h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h ...
- df,du,mount
df 查看当前系统中文件系统的使用情况 $df [-aTh]缺省选项查看当前系统的所有文件系统 -a列出所有的信息 -T列出文件系统类型 -hhuman-readable,用合适的单位表示大小 $df ...
- android RelativeLayout 动态设置高度
定义: private RelativeLayout mrlay; 调高度: mrlay = (RelativeLayout) findViewById(R.id.rlay_1); android.v ...
- 禁止用户选定文本: user-select
双击文本 select,会被选定,如下 但有时点击元素时不想要被选定的状态,有一个尚未成为标准的 CSS 属性: user-select,它有 4 个值: text 可以选择文本 element 可以 ...
- web性能优化系列之网站瓶颈识别
最近,公司网站的的访问量日益增大,PV马上过百万了.前期网站一到访问高峰,马上会变得很卡甚至打不开,后来做了很多优化后现在访问比较顺畅了.经过此事明白了一个道理,在遇到这类问题要做到两点,第一要相信自 ...