前面。 我已经陆续介绍过select函数的一些零碎知识, 在本文中,我们来讨论这样一个问题:socket何时处于读就绪状态?
事实上主要讨论select函数, 毕竟socket的读就绪状态会导致select函数马上返回。select函数的重要性不言而喻, 我在这里就不再强调了。 须要注意的是: Windows环境下的select和Linux环境下的select大同小异, 为了便于叙述和实战, 我们以Windows下的select函数为例。

我们再次来复习一下select函数的原型吧:int PASCAL FAR select( int nfds, fd_set FAR* readfds, fd_set FAR* writefds, fd_set FAR* exceptfds, const struct timeval FAR* timeout);

nfds:是一个整数值。是指集合中全部文件描写叙述符的范围,在Linux中必须是全部文件描写叙述符的最大值加1,不能错!

在Windows中这个參数的值无所谓。会被忽略。

     readfds:(可选)指针。指向一组等待可读性检查的套接口。

writefds:(可选)指针,指向一组等待可写性检查的套接口。

     exceptfds:(可选)指针。指向一组等待错误检查的套接口。

     timeout:select()最多等待时间,对堵塞操作则为NULL。

那么。 select函数有什么作用呢?何时返回呢?  以下是应用程序(程序猿写的, 比方你。 我)和操作系统内核(微软的一些人写的)之间的精彩对话

内核: 应用程序大爷, 您好, 我提供了一个名叫select的函数, 供你用, 你爱咋调用就咋调用, 详细怎么用, 请见select函数原型说明。 大爷, 您仅仅须要负责下发命令就可以, 我负责运行。

应用程序: 喂。 内核孙子。 我要调用你提供的select函数了。 听说你能够帮我去监測一些我感兴趣的描写叙述符的状态? 一旦处于所谓的就绪状态(比方读就绪状态), 你能够报告给我, 对么?

内核: 是的。 大爷。

应用程序: 那好。 我要你去监測一些事件(比方读就绪状态)。 等待某个事件发生, 假设这个事件发生。 那你就好通知我。 否则,有你好受的。

内核: 好的, 大爷。 那要是大爷您定义的这个事件(比方读就绪状态)一直不发生呢? 我建议大爷您再定义一个超时时间, 假设在这个时间内没有发生, 我给大爷您报一个超时的信息。 你看看我提供的select函数。 最后一个时间參数就是特别为您准备的。

应用程序: 你这个孙子非常乖啊, 知道大爷我没有耐心, 主动给我报超时, 好吧, 那我就给你下发一个超时时间。 假设在超时时间内我定义的事件(比方读就绪状态)没有发生, 你务必通知到我, 否则, 没有否则!

内核: 一定一定。哦, 对了, 大爷, 既然我们已经沟通好了, 那我们就尝试着实战交流沟通一下吧。

应用程序: 好的。 好孙子。

好吧, 精彩对话已经对完了, 我们来看看socket何时处于读就绪状态?(当socket处于读就绪状态时, select函数会马上返回)

server1.cpp为:

#include <stdio.h>
#include <winsock2.h> // winsock接口
#pragma comment(lib, "ws2_32.lib") // winsock实现 int main()
{
WORD wVersionRequested; // 双字节,winsock库的版本号
WSADATA wsaData; // winsock库版本号的相关信息 wVersionRequested = MAKEWORD(1, 1); // 0x0101 即:257 // 载入winsock库并确定winsock版本号,系统会把数据填入wsaData中
WSAStartup( wVersionRequested, &wsaData ); // AF_INET 表示採用TCP/IP协议族
// SOCK_STREAM 表示採用TCP协议
// 0是通常的默认情况
unsigned int sockSrv = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv; addrSrv.sin_family = AF_INET; // TCP/IP协议族
addrSrv.sin_addr.S_un.S_addr = INADDR_ANY;
addrSrv.sin_port = htons(8888); // socket相应的port // 将socket绑定到某个IP和port(IP标识主机。port标识通信进程)
bind(sockSrv,(SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); // 将socket设置为监听模式,5表示等待连接队列的最大长度
listen(sockSrv, 5); SOCKADDR_IN addrClient;
int len = sizeof(SOCKADDR); unsigned int sockConn = accept(sockSrv,(SOCKADDR*)&addrClient, &len); int flag = 0;
scanf("%d", &flag); if(1 == flag)
{
char sendBuf[100] = "hello";
send(sockConn, sendBuf, strlen(sendBuf) + 1, 0); // 发送数据到客户端,最后一个參数一般设置为0
} if(2 == flag)
{
closesocket(sockConn);
} if(3 == flag)
{
closesocket(sockSrv);
} if(4 == flag)
{
WSACleanup();
} while(1); return 0;
}

client1.cpp为:

#include <winsock2.h>
#include <stdio.h>
#pragma comment(lib, "ws2_32.lib") int main()
{
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(1, 1); WSAStartup( wVersionRequested, &wsaData ); SOCKET sockClient = socket(AF_INET, SOCK_STREAM, 0); SOCKADDR_IN addrSrv;
addrSrv.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
addrSrv.sin_family = AF_INET;
addrSrv.sin_port = htons(8888); int ret = connect(sockClient, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR)); fd_set read_set;
struct timeval t;
FD_ZERO(&read_set);
FD_SET(sockClient, &read_set);
t.tv_sec = 20;
t.tv_usec = 0; while(1)
{
ret = select(-1, &read_set, NULL, NULL, &t);
printf("ret is %d\n", ret);
Sleep(1000);
} closesocket(sockClient);
WSACleanup(); return 0;
}

实战開始啦:

1.  开启服务端, 再开启client。 然后啥也不干。 过约20秒后, client的select才返回0.    看来。 内核没有撒谎, 没有事件发生的时候, 超过20秒后, 确实如实把情况反馈给了应用程序。 真的非常乖。 好, 我们关闭服务端和client。

2.  开启服务端, 再开启client。 我们在服务端让flag为1, 发送数据。 制造客服端的可读就绪状态。 我们看到, client的select函数马上返回了1.  看来, 内核确实如实反馈了socket的可读就绪状态。 好。 我们关闭服务端和client。 (备注: 在这样的情况下。 一旦select检測到读就绪状态, 此时调用recv函数能马上返回)

3. 开启服务端, 再开启client。 我们在服务端让flag为2, 关闭通信的socket,   我们看到。 client的select函数马上返回了1.  好。 我们关闭服务端和client。

4. 开启服务端, 再开启client。

我们在服务端让flag为3, 关闭非通信的socket, 我们看到, client没有啥变化, 20秒后。 select函数才返回0,  实际就是1中描写叙述的情况。 好,我们关闭服务端和client。

5. 开启服务端。 再开启client。 我们在服务端让flag为4。 调用WSACleanup,   我们看到, client的select函数马上返回了1.  好, 我们关闭服务端和client。

6. 开启服务端, 再开启client。 然后又关掉服务端(关掉这个服务进程), 我们看到, client的select函数马上返回了1. 好。 我们把client也关了吧。

别急, 另一种情况的读就绪状态, 请直接參考我之前的博文:http://blog.csdn.net/stpeace/article/details/21129637。 我来把这个总结为第7点。

7. 假设某socket处于监听状态(当然啦。 这肯定是服务端的某socket),且设置了readfs, 那么一旦client发起了connect连接, 服务端的select函数会马上返回。 由此可知, 一旦服务端的select函数返回了非负值(比方1), 则表明肯定有client来connect连接, 此时服务端调用accept函数会马上成功。 详细实战请參考之前的博文。

总结一下: 1和4是超时返回。 2, 3, 5, 6, 7都相当于client套接字处于读就绪状态, 内核检測到这个读就绪状态后。 select函数马上返回, 将信息报告给应用程序。

当中仅有7是特别针对服务端的socket.

眼下来讲, 我主要接触到的就是读就绪状态或者超时后select函数的返回。 至于写就绪状态下select的返回以及异常就绪状态下select函数的返回。 事实上也是非常easy的, 以后假设有须要, 再学学, 那也不是什么难事, 毕竟网上资料一大堆啊。 OK, 本文到此为止。

socket何时处于”读就绪状态“?---通过“应用程序大爷&quot;和&quot;内核孙子&quot;对话再看重要的select函数的使用方法的更多相关文章

  1. Python Socket 编程——聊天室演示样例程序

    上一篇 我们学习了简单的 Python TCP Socket 编程,通过分别写服务端和client的代码了解主要的 Python Socket 编程模型.本文再通过一个样例来加强一下对 Socket ...

  2. 如何快速读懂大型C++程序代码

    要搞清楚别人的代码,首先,你要了解代码涉及的领域知识,这是最重要的,不懂领域知识,只看代码本身,不可能搞的明白.其次,你得找各种文档:需求文档(要做什么),设计文档(怎么做的),先搞清楚你即将要阅读是 ...

  3. python简单的监控脚本-利用socket、psutil阻止远程主机运行特定程序

    python简单的监控脚本-利用socket.psutil阻止远程主机运行特定程序 psutil是一个跨平台的库(http://code.google.com/p/psutil/),能够轻松的实现获取 ...

  4. socket通信中select函数的使用和解释

    select函数的作用: select()在SOCKET编程中还是比较重要的,可是对于初学SOCKET的人来说都不太爱用select()写程序,他们只是习惯写诸如 conncet().accept() ...

  5. 使用select函数改进客户端/服务器端程序

    一.当我们使用单进程单连接且使用readline修改后的客户端程序,去连接使用readline修改后的服务器端程序,会出现一个有趣的现象,先来看输出: 先运行服务器端,再运行客户端, simba@ub ...

  6. PHP Socket实现websocket(四)Select函数

    int select(int maxfdp,fd_set *readfds,fd_set *writefds,fd_set *errorfds,struct timeval *timeout); /* ...

  7. 转 linux socket的select函数例子

    使用select函数可以以非阻塞的方式和多个socket通信.程序只是演示select函数的使用,功能非常简单,即使某个连接关闭以后也不会修改当前连接数,连接数达到最大值后会终止程序. 1. 程序使用 ...

  8. socket通信时如何判断当前连接是否断开--select函数,心跳线程,QsocketNotifier监控socket

    client与server建立socket连接之后,如果突然关闭server,此时,如果不在客户端close(socket_fd),会有不好的影响: QsocketNotifier监控socket的槽 ...

  9. CAD调试时抛出“正试图在 os 加载程序锁内执行托管代码。不要尝试在 DllMain 或映像初始化函数内运行托管代码”异常的解决方法

    这些天重装了电脑Win10系统,安装了CAD2012和VS2012,准备进行软件开发.在调试程序的时候,CAD没有进入界面就抛出 “正试图在 os 加载程序锁内执行托管代码.不要尝试在 DllMain ...

随机推荐

  1. Linux搭建主从数据库服务器(主从复制)

    配置主机数据库: 1.克隆linux操作系统 2.修改Linux系统主机IP地址 主机IP:192.168.247.150 从机IP:192.168.247.151 3.通过xshell连接Maste ...

  2. Mybatis框架-1

    1.Mybatis框架: Mybatis是一个半自动的对象关系映射(ORM),实现结果集的自动封装,sql写到配置文件中: Mybatis使用的是DTD约束. 2.Mybatis模块调用: 3.Sql ...

  3. vue v-bind绑定属性和样式

    这期跟大家分享的,是v-bind指令.它可以往元素的属性中绑定数据,也可以动态地根据数据为元素绑定不同的样式. 绑定属性 最简单的例子,我们有一张图片,需要定义图片的src.我们可以直接在元素的属性里 ...

  4. java.lang.ClassCastException: xut.bookshop.entity.User_$$_javassist_3 cannot be cast to javassist.util.proxy.Proxy

    报错信息 java.lang.ClassCastException: xut.bookshop.entity.User_$$_javassist_3 cannot be cast to javassi ...

  5. leetcode104 Maximum Depth

    题意:二叉树最大深度 思路:递归,但是不知道怎么回事直接在return里面计算总是报超时,用俩变量就可以A···奇怪,没想通 代码: int maxDepth(TreeNode* root) { if ...

  6. Friends number NBUT - 1223 (暴力打表)

    Paula and Tai are couple. There are many stories between them. The day Paula left by airplane, Tai s ...

  7. BZOJ 2430 [Poi2003]Chocolate(贪心+归并排序)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2430 [题目大意] 有一块n*m的矩形巧克力,准备将它切成n*m块. 巧克力上共有n- ...

  8. [UOJ347]通道

    锟题x1 以下用$d_k(x,y)$表示$x,y$在第树$k$上的距离,$h_k(x)$表示$x$在树$k$上的深度 先做两棵树,即最大化$d_1(x,y)+d_2(x,y)=h_1(x)+h_1(y ...

  9. 【DFS】XIII Open Championship of Y.Kupala Grodno SU Grodno, Saturday, April 29, 2017 Problem D. Divisibility Game

    题意:给你一个序列,长度不超过52,每个元素不超过13.让你重新对这个序列排序,sum(i)表示i的前缀和,使得排序过后,对每个i,都有sum(i)%i==0. 深搜,加两个优化:①倒着从后向前搜:② ...

  10. 【分块】【暴力】XVII Open Cup named after E.V. Pankratiev Grand Prix of Moscow Workshops, Sunday, April 23, 2017 Problem I. Rage Minimum Query

    1000w的数组,一开始都是2^31-1,然后经过5*10^7次随机位置的随机修改,问你每次的全局最小值. 有效的随机修改的期望次数很少,只有当修改到的位置恰好是当前最小值的位置时才需要扫一下更新最小 ...