ImageVerifierCode 换一换
格式:DOCX , 页数:8 ,大小:29.54KB ,
资源ID:6382815      下载积分:10 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/6382815.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(windows和linux套接字中的select机制浅析.docx)为本站上传会员【pc****0】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

windows和linux套接字中的select机制浅析.docx

1、windows和linux套接字中的select机制浅析 先来谈谈为什么会出现select函数,也就是select是解决什么问题的? 平常使用的recv函数时阻塞的,也就是如果没有数据可读,recv就会一直阻塞在那里,这是如果有另外一个连接过来,就得一直等待,这样实时性就不是太好。 这个问题的几个解决方法:1. 使用ioctlsocket函数,将recv函数设置成非阻塞的,这样不管套接字上有没有数据都会立刻返回,可以重复调用recv函数,这种方式叫做轮询(polling),但是这样效率很是问题,因为,大多数时间实际上是无数据可读的,花费时间不断反复执行read系统调用,这样就比较浪费CP

2、U的时间。并且循环之间的间隔不好确定。2. 使用fork,使用多进程来解决,这里终止会比较复杂(待研究)。 3.使用多线程来解决,这样避免了终止的复杂性,但却要求处理线程之间的同步,在减少复杂性方面这可能会得不偿失。4. 使用异步IO(待研究)。5. 就是本文所使用的I/O多路转接(多路复用)--其实就是在套接字阻塞和非阻塞之间做了一个均衡,我们称之为半阻塞。 经过对select的初步了解,在windows和linux下的实现小有区别,所以分开来写。这里先写windows下的select机制。 select的大概思想:将多个套接字放在一个集合里,然后统一检查这些套接字的状态(可读、可写、异

3、常等),调用select后,会更新这些套接字的状态,然后做判断,如果套接字可读,就执行read操作。这样就巧妙地避免了阻塞,达到同时处理多个连接的目的。当然如果没有事件发生,select会一直阻塞,如果不想一直让它等待,想去处理其它事情,可以设置一个最大的等待时间。 /***********************************************************************************************************/ 下面具体讲讲函数的参数,参见MSDN的解释:澳门新濠天地66bb.org   1. int select

4、   2.   _In_     int nfds,   3.   _Inout_  fd_set *readfds,   4.   _Inout_  fd_set *writefds,   5.   _Inout_  fd_set *exceptfds,   6.   _In_     const struct timeval *timeout   7. );   函数的返回值,表示准备好的套接字的个数,如果是0,则表示没有一个准备好(超时就是一种情况),如果是-1(SOCKET_ERROR),表示有错误发生,可以使用WSAGetLastError()函数来得到错误代码,

5、从而知道是什么错误。   函数的参数,第一个是输入参数nfds,表示满足条件的套接字的个数,windows下可以设置为0,因为fd_set结构体中已经包含了这个参数,这个参数已经是多余的了,之所以还存在,只是是为了与FreeBSD兼容。 第二三四参数都是输入输出参数(值-结果参数,输入和输出会不一样),表示套接字的可读、可写和异常三种状态的集合。调用select之后,如果指定套接字不可读或者不可写,就会从相应队列中清除,这样就可以判断哪些套接字可读或者可写。  说明一下,这里的可读性是指:如果有客户的连接请求到达,套接口就是可读的,调用accept能够立即完成,而不发生阻塞;如果套接口

6、接收队列缓冲区中的字节数大于0,调用recv或者recvfrom就不会阻塞。可写性是指,可以向套接字发送数据(套接字创建成功后,就是可写的)。当然不是套接字可写就会去发送数据,就像不是看到电话就去打电话一样,而是由打电话的需求了,才去看电话是否可打;可读就不一样了,电话响了,自然要去接电话(除非,你有事忙或者不想接,一般都是要接的)。可读已经包含了缓冲区中有数据可以读取,可写只是说明了缓冲区有空间让你写,你需不需要写就要看你有没有数据要写了.关于异常,就是指一些意外情况,自己用的比较少,以后用到了,再过来补上。 第五个参数是等待的最大时间,是一个结构体:struct timeval,它的定义

7、是:   1. /*  2. * Structure used in select() call, taken from the BSD file sys/time.h.  3. */   4. struct timeval {   5.         long    tv_sec;         /* seconds */   6.         long    tv_usec;        /* and microseconds */   7. };   具体到秒和微妙,按照等待的时间长短可以分为不等待、等待一定时间、一直等待。对应的设置分别为,(0,0)是不等待

8、这是select是非阻塞的,(x,y)最大等待时间x秒y微妙(如果有事件就会提前返回,而不继续等待),NULL表示一直等待,直到有事件发生。这里可以将timeout分别设置成0(不阻塞)或者1微妙(阻塞很短的时间),然后观察CPU的使用率,会发现设置成非阻塞后,CPU的使用率已下载就上升到了50%左右,这样可以看出非阻塞占用CPU很多,但利用率不高。   /***********************************************************************************************************/ 跟select

9、配合使用的几个宏和fd_set结构体介绍: 套接字描述符为了方便管理是放在一个集合里的,这个集合是fd_set,它的具体定义是:   1. typedef struct fd_set {   2.         u_int   fd_count;               /* how many are SET? */   3.         SOCKET  fd_array[FD_SETSIZE];   /* an array of SOCKETs */   4. } fd_set;   fd_count是集合中已经设置的套接口描述符的数量。fd_array数组保存已经设

10、置的套接口描述符,其中FD_SETSIZE的定义是:     1. #ifndef FD_SETSIZE   2. #define FD_SETSIZE      64   3. #endif /* FD_SETSIZE */   这个默认值在一般的程序中已经够用,如果需要,可以将其更改为更大的值。   集合的管理操作,比如元素的清空、加入、删除以及判断元素是否在集合中都是用宏来完成的。四个宏是:   1. FD_ZERO(*set)   2. FD_SET(s, *set)   3. FD_ISSET(s, *set)   4. FD_CLR(s, *set)  

11、 下面一一介绍这些宏的作用和定义:   FD_ZERO(*set),是把集合清空(初始化为0,确切的说,是把集合中的元素个数初始化为0,并不修改描述符数组).使用集合前,必须用FD_ZERO初始化,否则集合在栈上作为自动变量分配时,fd_set分配的将是随机值,导致不可预测的问题。它的宏定义如下:   1. #define FD_ZERO(set) (((fd_set FAR *)(set))->fd_count=0)   FD_SET(s,*set),向集合中加入一个套接口描述符(如果该套接口描述符s没在集合中,并且数组中已经设置的个数小于最大个数时,就把该描述符加入到集合中,集合

12、元素个数加1)。这里是将s的值直接放入数组中。它的宏定义如下:     1. #define FD_SET(fd, set) do { \   2.     if (((fd_set FAR *)(set))->fd_count < FD_SETSIZE) \   3.         ((fd_set FAR *)(set))->fd_array[((fd_set FAR *)(set))->fd_count++]=(fd);\   4. } while(0)   FD_ISSET(s,*set),检查描述符是否在集合中,如果在集合中返回非0值,否则返回0. 它的宏定义并没有给

13、出具体实现,但实现的思路很简单,就是搜索集合,判断套接字s是否在数组中。它的宏定义是:     1. #define FD_ISSET(fd, set) __WSAFDIsSet((SOCKET)(fd), (fd_set FAR *)(set))   FD_CLR(s,*set),从集合中移出一个套接口描述符(比如一个套接字连接中断后,就应该移除它)。实现思路是,在数组集合中找到对应的描述符,然后把后面的描述依次前移一个位置,最后把描述符的个数减1. 它的宏定义是:     1. #define FD_CLR(fd, set) do { \   2.     u_int __

14、i; \   3.     for (__i = 0; __i < ((fd_set FAR *)(set))->fd_count ; __i++) { \   4.         if (((fd_set FAR *)(set))->fd_array[__i] == fd) { \   5.             while (__i < ((fd_set FAR *)(set))->fd_count-1) { \   6.                 ((fd_set FAR *)(set))->fd_array[__i] = \   7.                

15、     ((fd_set FAR *)(set))->fd_array[__i+1]; \   8.                 __i++; \   9.             } \   10.             ((fd_set FAR *)(set))->fd_count--; \   11.             break; \   12.         } \   13.     } \   14. } while(0)   /**********************************************************

16、/   至此,一些基础的点基本就讲完了,b31.org 然后给出大概流程和一个示例: 1.调用FD_ZERO来初始化套接字状态; 2.调用FD_SET将感兴趣的套接字描述符加入集合中(每次循环都要重新加入,因为select更新后,会将一些没有满足条件的套接字移除队列); 3.设置等待时间后,调用select函数--更新套接字的状态; 4.调用FD_ISSET,来判断套接字是否有相应状态,然后做相应操作,比如,如果套接字可读,就调用recv函数去接收数据。 关键技术:套接字队列和状态的

17、表示与处理。 server端得程序如下(套接字管理队列一个很重要的作用就是保存套接字描述符,因为accept得到的套接字描述符会覆盖掉原来的套接字描述符,而readfs中的描述符在select后会删除这些套接字描述符):   1. // server.cpp :    2. //程序中加入了套接字管理队列,这样管理起来更加清晰、方便,当然也可以不用这个东西   3.    4. #include "winsock.h"   5. #include "stdio.h"   6. #pragma comment (lib,"wsock32.lib")   7. struct so

18、cket_list{   8.     SOCKET MainSock;   9.     int num;   10.     SOCKET sock_array[64];   11. };   12. void init_list(socket_list *list)   13. {   14.     int i;   15.     list->MainSock = 0;   16.     list->num = 0;   17.     for(i = 0;i < 64;i ++){   18.         list->sock_array[i] = 0;

19、   19.     }   20. }   21. void insert_list(SOCKET s,socket_list *list)   22. {   23.     int i;   24.     for(i = 0;i < 64; i++){   25.         if(list->sock_array[i] == 0){   26.             list->sock_array[i] = s;   27.             list->num += 1;   28.             break;   29.       

20、  }   30.     }   31. }   32. void delete_list(SOCKET s,socket_list *list)   33. {   34.     int i;   35.     for(i = 0;i < 64; i++){   36.         if(list->sock_array[i] == s){   37.             list->sock_array[i] = 0;   38.             list->num -= 1;   39.             break;   40.    

21、     }   41.     }   42. }   43. void make_fdlist(socket_list *list,fd_set *fd_list)   44. {   45.     int i;   46.     FD_SET(list->MainSock,fd_list);   47.     for(i = 0;i < 64;i++){   48.         if(list->sock_array[i] > 0){   49.             FD_SET(list->sock_array[i],fd_list);   50.  

22、       }   51.     }   52. }   53. int main(int argc, char* argv[])   54. {   55.     SOCKET s,sock;   56.     struct sockaddr_in ser_addr,remote_addr;   57.     int len;   58.     char buf[128];   59.     WSAData wsa;   60.     int retval;   61.     struct socket_list sock_list;   62.  

23、   fd_set readfds,writefds,exceptfds;   63.     timeval timeout;        //select的最多等待时间,防止一直等待   64.     int i;   65.     unsigned long arg;   66.    67.     WSAStartup(0x101,&wsa);   68.     s = socket(AF_INET,SOCK_STREAM,0);   69.     ser_addr.sin_family = AF_INET;   70.     ser_addr.sin_a

24、ddr.S_un.S_addr = htonl(INADDR_ANY);   71.     ser_addr.sin_port = htons(0x1234);   72.     bind(s,(sockaddr*)&ser_addr,sizeof(ser_addr));   73.    74.     listen(s,5);   75.     timeout.tv_sec = 5;     //如果套接字集合中在1s内没有数据,select就会返回,超时select返回0   76.     timeout.tv_usec = 0;   77.     init_li

25、st(&sock_list);   78.     FD_ZERO(&readfds);   79.     FD_ZERO(&writefds);   80.     FD_ZERO(&exceptfds);   81.     sock_list.MainSock = s;   82.     arg = 1;   83.     ioctlsocket(sock_list.MainSock,FIONBIO,&arg);   84.     while(1){   85.         make_fdlist(&sock_list,&readfds);   86.   

26、      //make_fdlist(&sock_list,&writefds);   87.         //make_fdlist(&sock_list,&exceptfds);   88.    89.         retval = select(0,&readfds,&writefds,&exceptfds,&timeout);     //超过这个时间,就不阻塞在这里,返回一个0值。   90.         if(retval == SOCKET_ERROR){   91.             retval = WSAGetLastError();  

27、92.             break;   93.         }   94.         else if(retval == 0) {   95.             printf("select() is time-out! There is no data or new-connect coming!\n");   96.             continue;   97.         }   98.         if(FD_ISSET(sock_list.MainSock,&readfds)){   99.             len =

28、 sizeof(remote_addr);   100.             sock = accept(sock_list.MainSock,(sockaddr*)&remote_addr,&len);   101.             if(sock == SOCKET_ERROR)   102.                 continue;   103.             printf("accept a connection\n");   104.             insert_list(sock,&sock_list);   105.     

29、    }   106.         for(i = 0;i < 64;i++){   107.             if(sock_list.sock_array[i] == 0)   108.                 continue;   109.             sock = sock_list.sock_array[i];   110.             if(FD_ISSET(sock,&readfds)){   111.                 retval = recv(sock,buf,128,0);   112.     

30、            if(retval == 0){   113.                     closesocket(sock);   114.                     printf("close a socket\n");   115.                     delete_list(sock,&sock_list);   116.                     continue;   117.                 }else if(retval == -1){   118.                 

31、    retval = WSAGetLastError();   119.                     if(retval == WSAEWOULDBLOCK)   120.                         continue;   121.                     closesocket(sock);   122.                     printf("close a socket\n");   123.                     delete_list(sock,&sock_list);   //连接断开

32、后,从队列中移除该套接字   124.                     continue;   125.                 }   126.                 buf[retval] = 0;   127.                 printf("->%s\n",buf);   128.                 send(sock,"ACK by server",13,0);   129.             }   130.             //if(FD_ISSET(sock,&writefds)){   13

33、1.             //}   132.             //if(FD_ISSET(sock,&exceptfds)){   133.                134.         }   135.         FD_ZERO(&readfds);   136.         FD_ZERO(&writefds);   137.         FD_ZERO(&exceptfds);   138.     }   139.     closesocket(sock_list.MainSock);   140.     WSACleanup();   141.     return 0;   142. }     关于linux下的select跟windows下的区别还有待学习。

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服