菜鸟笔记
提升您的技术认知

网络编程笔记

《unix网络编程》五种I/O模型《unix网络编程》select、shutdown函数《unix网络编程》套接字选项《unix网络编程》守护进程和inetd超级服务器《UNIX网络编程》epoll 的accept , read, writeLinux 套接字编程中的 5 个隐患《unix网络编程》tcp服务器的几种常见状况分析《unix网络编程》epoll函数《unix网络编程》wait/waitpid处理僵死进程(SIGCHLD信号)《unix网络编程》socket是什么《UNIX网络编程》epoll的ET/LT模式注意点IO复用与并发编程Reactor和Proactor模型基于TCP的客户端、服务器端socket编程网络编程调试水平触发和边缘触发五种IO模型brpc长连接问题I/O多路复用之 selectI/O多路复用之 pollI/O多路复用之 epollselect,poll,epoll之间的优点和缺点总结大端模式和小端模式的区别大端模式和小端模式详解大端模式和小端模式netperf大小端的介绍判断机器的大小端Linux epoll模型正向代理与反向代理DNS的工作原理常用计算机网络端口号brpc编译运行Connection reset by peer的解决办法TCP粘包问题分析和解决Thrift之服务模型和序列化机制Epoll原理解析TCP、UDP数据包大小的限制socket,tcp,http三者之间的区别和原理Epoll模型讲解epoll原理详解及epoll反应堆模型非阻塞socket调用connect, epoll和select检查连接情况示例tcp为什么要三次握手Socket 编程详解udp如何实现可靠性传输?网络基础面试整理你真的了解IP地址吗?什么是RPC最详细的 I/O 多路复用解析OSI参考模型

《unix网络编程》select、shutdown函数

阅读 : 707

《unix网络编程》(11)tcp服务器的几种常见状况分析的“服务器进程终止”提到客户阻塞于fgets所以没办法收到服务器发的FIN,只有当客户再次输入文本并发送给服务器后才会从套接字中读取,这时才知道服务器的状态。但这可能已经过了很长时间。这样的进程就需要预先告知内核的能力,使得内核一旦发现进程指定的一个或多个I/O条件就绪(即,输入已经准备好读取,或描述符能够承接更多输出),它就通知进程。这种能力就是I/O复用(I/O mutiplexing)。该能力由select和poll支持

select

该函数允许进程指示内核等待多个事件中的任何一个发生,并只在有一个或多个事件发生或经历了一段指定的时间后才唤醒它。

select函数及参数

#include 
#include 
int select(int maxfdp1, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);
//返回:若有就绪描述符则返回就绪描述符的数目,若超时返回0,若出错返回-1

参数:

(1) timeout:告知内核等待指定描述符中任何一个就绪花费的最长时间,其timeval结构用于指定秒数和微妙数。

//timeval结构:
struct timeval
{
    long    tv_sec;     /* seconds */
    long    tv_usec;    /* microseconds */
};

使用select,设置其3个set为空指针, nfds为0, 一个非空的timeout来达到较为
精确的sleep(单位为微秒),普通的sleep单位为


timeout取值:

         (1)timeout== NULL,仅当一个描述符准备好I/O时才返回。

         (2)timeout->tv_sec == 0 && tvptr->tv_usec == 0,立即返回,称为
轮询
五种I/O模型)。

         (3) timeout->tv_sec != 0 || tvptr->tv_usec !=0, 等待特定时间长度,超时返回0;
在这段时间内如果有描述符准备好就返回。

(2)中间的三个参数:指定要让内核测试读、写、异常的描述符,若对某一个不感兴趣可置为NULL

          这三个参数都是socket,调用函数时,用于指定所关心的描述符的值;函数返回时,结果将指示哪些描述符已经就绪。

         select使用描述符集,通常是一个整数数组,其中每个整数的一位对应一个描述符。而poll是用可变长度的结构数组,每个结构代表一个描述符

 通过fd_set的数据类型和四个宏实现:

       FD_CLR(int fd, fd_set *set);  //关闭fd_set中的fd位
       FD_ISSET(int fd, fd_set *set); //测试该位是否打开,如果为1则该位对应描述符就绪
       FD_SET(int fd, fd_set *set);  //打开该fd位
       FD_ZERO(fd_set *set);         //清空所有位

如下打开描述符1、4位:

fd_set rset;
FD_ZERO(&rset);  //清空所有,每次调用select都要清空为0
FD_SET(1,&rset);  //调用select将我们关心的位置为1.
FD_SET(4,&rset);

(3)maxfdp1参数指定待测试的描述符的个数,其值为最大待测试描述符加1。例如上例打开1、4描述符,那么这里maxfdp1值为5。

描述符就绪条件

当某套接字发生错误,将由select标记为既可读又可写。

shutdown函数

终止网络连接通常使用close函数。

不过close有两个限制,但可通过shutdown函数避免

(1)close把描述符引用计数减1,仅在该计数为0时才关闭套接字。shutdown可以不管引用计数就激发TCP的正常连接终止。

(2)close终止读和写两个方向的数据传输。有时候需要告诉对端我们已经发完数据,即使对端仍有数据发送

#include 
int shutdown(int sockfd, int howto);
//成功返回0,出错返回-1

shutdown允许我们处理批量数据,典型情况:

该函数行为依赖于howto参数:

(1)SHUT_RD

           关闭连接读这一半——套接字不再有数据接收,而且套接字接收缓冲区现有数据丢弃。不再对这样的套接字调用读函数。来自对端的数据都被确认并丢弃

(2)SHUT_WR

          关闭连接写这一半,这称为半关闭。当前留在套接字缓冲区内的数据将被发送掉,后跟TCP的正常连接终止序列。

(3)SHUT_RDWR

         连接的读和写都关闭。