个人旅游网站模版前端网站开发实例视频
- 作者: 五速梦信息网
- 时间: 2026年03月21日 11:13
当前位置: 首页 > news >正文
个人旅游网站模版,前端网站开发实例视频,可以用AI做网站上的图吗,做淘宝内部优惠券网站要钱么一
1.首先将标志位设为Non-blocking模式#xff0c;准备在非阻塞模式下调用connect函数 2.调用connect#xff0c;正常情况下#xff0c;因为TCP三次握手需要一些时间#xff1b;而非阻塞调用只要不能立即完成就会返回错误#xff0c;所以这里会返回EINPROGRESS#xf…一
1.首先将标志位设为Non-blocking模式准备在非阻塞模式下调用connect函数 2.调用connect正常情况下因为TCP三次握手需要一些时间而非阻塞调用只要不能立即完成就会返回错误所以这里会返回EINPROGRESS表示在建立连接但还没有完成。 3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位用FD_ZERO()、FD_SET()宏并设置好超时时间(struct timeval *timeout) 4.调用select( socket, rset, wset, NULL, timeout ) 返回0表示connect超时 如果你设置的超时时间大于75秒就没有必要这样做了因为内核中对connect有超时限制就是75秒。 [From]http://www.ycgczj.com.cn/34733.html 网络编程中 socket 的分量我想大家都很清楚了 socket 也就是套接口在套接口编程中提到超时的概念我们一下子就能想到 3 个发送超时接收超时以及 select 超时注 select 函数并不是只用于套接口的但是套接口编程中用的比较多在 connect 到目标主机的时候这个超时是不由我们来设置的。不过正常情况下这个超时都很长并且 connect 又是一个阻塞方法一个主机不能连接等着 connect 返回还能忍受你的程序要是要试图连接多个主机恐怕遇到多个不能连接的主机的时候会塞得你受不了的。我也废话少说先说说我的方法如果你觉得你已掌握这种方法你就不用再看下去了如果你还不了解我愿意与你分享。本文是已在 Linux 下的程序为例子不过拿到 Windows 中方法也是一样无非是换几个函数名字罢了。 Linux 中要给 connect 设置超时应该是有两种方法的。一种是该系统的一些参数这个方法我不讲因为我讲不清楚 :P 它也不是编程实现的。另外一种方法就是变相的实现 connect 的超时我要讲的就是这个方法原理上是这样的 1 建立 socket 2 将该 socket 设置为非阻塞模式 3 调用 connect() 4 使用 select() 检查该 socket 描述符是否可写注意是可写 5 根据 select() 返回的结果判断 connect() 结果 6 将 socket 设置为阻塞模式如果你的程序不需要用阻塞模式的这步就省了不过一般情况下都是用阻塞模式的这样也容易管理 如果你对网络编程很熟悉的话其实我一说出这个过程你就知道怎么写你的程序了下面给出我写的一段程序仅供参考。 /****************************** * Time out for connect() Write by Kerl W ****************************/ #include sys/socket.h #include sys/types.h #define TIME_OUT_TIME 20 //connect 超时时间 20 秒 int main(int argc , char argv) { ……………… int sockfd socket(AF_INET, SOCK_STREAM, 0); if(sockfd 0) exit(1); struct sockaddr_in serv_addr; ………// 以服务器地址填充结构 serv_addr int error-1, len; len sizeof(int); timeval tm; fd_set set; unsigned long ul 1; ioctl(sockfd, FIONBIO, ul); // 设置为非阻塞模式 bool ret false; if( connect(sockfd, (struct sockaddr )serv_addr, sizeof(serv_addr)) -1) { tm.tv_set TIME_OUT_TIME; tm.tv_uset 0; FD_ZERO(set); FD_SET(sockfd, set); if( select(sockfd1, NULL, set, NULL, tm) 0) { getsockopt(sockfd, SOL_SOCKET, SO_ERROR, error, (socklen_t )len); if(error 0) ret true; else ret false; } else ret false; } else ret true; ul 0; ioctl(sockfd, FIONBIO, ul); // 设置为阻塞模式 if(!ret) { close( sockfd ); fprintf(stderr , Cannot Connect the server!/n); return; } fprintf( stderr , Connected!/n); // 下面还可以进行发包收包操作 …………… } 以上代码片段仅供参考也是为初学者提供一些提示主要用到的几个函数 select, ioctl, getsockopt 都可以找到相关资料具体用法我这里就不赘述了你只需要在 linux 中轻轻的敲一个 man 函数名 就能够看到它的用法。 此外我需要说明的几点是虽然我们用 ioctl 把套接口设置为非阻塞模式不过 select 本身是阻塞的阻塞的时间就是其超时的时间由调用 select 的时候的最后一个参数 timeval 类型的变量指针指向的 timeval 结构变量来决定的 timeval 结构由一个表示秒数的和一个表示微秒数 long 类型的成员组成一般我们设置了秒数就行了把微妙数设为 0 注 1 秒等于 100 万微秒。而 select 函数另一个值得一提的参数就是上面我们用到的 fd_set 类型的变量指针。调用之前这个变量里面存了要用 select 来检查的描述符调用之后针对上面的程序这里面是可写的描述符我们可以用宏 FD_ISSET 来检查某个描述符是否在其中。由于我这里只有一个套接口描述符我就没有使用 FD_ISSET 宏来检查调用 select 之后这个 sockfd 是否在 set 里面其实是需要加上这个判断的。不过我用了 getsockopt 来检查这样才可以判断出这个套接口是否是真的连接上了因为我们只是变相的用 select 来检查它是否连接上了实际上 select 检查的是它是否可写而对于可写是针对以下三种条件任一条件满足时都表示可写的 1 套接口发送缓冲区中的可用控件字节数大于等于套接口发送缓冲区低潮限度的当前值且或者 i) 套接口已连接或者 ii) 套接口不要求连接 UDP 方式的 2 连接的写这一半关闭。 3 有一个套接口错误待处理。 这样我们就需要用 getsockopt 函数来获取套接口目前的一些信息来判断是否真的是连接上了没有连接上的时候还能给出发生了什么错误当然我程序中并没有标出那么多状态只是简单的表示可连接 / 不可连接。 下面我来谈谈对这个程序测试的结果。我针对 3 种情形做了测试 1 目标机器网络正常的情况 可以连接到目标主机并能成功以阻塞方式进行发包收包作业。 2 目标机器网络断开的情况 在等待设置的超时时间上面的程序中为 20 秒后显示目标主机不能连接。 3 程序运行前断开目标机器网络超时时间内恢复目标机器的网络 在恢复目标主机网络连接之前程序一只等待恢复目标主机后程序显示连接目标主机成功并能成功以阻塞方式进行发包收包作业。 以上各种情况的测试结果表明这种设置 connect 超时的方法是完全可行的。我自己是把这种设置了超时的 connect 封装到了自己的类库用在一套监控系统中到目前为止运行还算正常。这种编程实现的 connect 超时比起修改系统参数的那种方法的有点就在于它只用于你的程序之中而不影响系统。 connect 超时 ,socket connect,socket 超时 ,socket 连接超时设置 ,connect,mysql connect,connect by,connect by prior,connect player,media connect 关于c/s socket中超时问题的总结 [size18:ac54d21053] 在客户端与服务器端通过 socket 连接时有两个问题必须考虑 1 、 connect 连接时可能会发生连接不上的情况需要实现超时退出程序。 2 、连接后在接收数据的过程中可能发生网络中断不能接受数据的情况需要退出程序。 这两个问题应该很常见希望高手给大家详细地讲解一下谢谢。 [/size:ac54d21053] 【 发表回复 】【 查看论坛原帖 】【 添加到收藏夹 】【 关闭 】 gadfly 回复于 2003-08-11 14:40:32 这两个都可以用非阻塞 socket select 控制超时 yuanyawei 回复于 2003-08-12 09:08:00 我觉得第一种情况用 select 可以很好解决。 但第二种情况在遇到客户端直接拔网线的情况时 server 端的情况较难判断要看内核的参数 linux 下较好处理 BSD 也没问题 HP 和 AIX 也能处理但 SCO 下就不好办了参数老调不好。 minsky 回复于 2003-08-12 10:52:27 1.connect 超时 : 1)setsockopt();// 将 socket 置为非阻塞模式 ; 2)connect(); 3) 判断 connect() 的返回值 , 一般情况会返回 -1, 这时你还必须判断错误码如果是 EINPROGRESS, 那说明 connect 还在继续 ; 如果错误码不是前者那么就是有问题了 , 不必往下执行 , 必须关掉 socket; 待下次重联 ; 4)select(); 设置好函数中的超时时间 , 将 select() 中的 read 和 write 项置上 , 在超时时间内 , 如果 select 返回 1, 即描述字变为了可写 , 那么连接成功 ; 如果返回 2, 即描述字变为即可读又可写 , 那么出错 ; 如果返回 0, 那么超时 ; 2. 网络中断 : 如果你的程序是客户端 . 用 select 检查描述符的状态 , 如果可读就 recv(), 根据 recv() 的返回值来判断网络情况 ; calfen 回复于 2003-12-18 15:18:55 unp 上明确说 setsockopt 只能用在读写时候不能用在 connect 上啊 … grouploo 回复于 2004-06-25 23:06:35 /*****************************************/ /* 作者 : 夕君 / / 时间 2004.04.04 / /** 北京金万维科技 http://www.gnway.com / /******************************************/ /* 此函数实现判断 m_server 的 m_port 端口是否可以连上超时限制为 nTimeOut 秒 */ BOOL ConnectTest(char * m_server,int m_port) { struct hostent host NULL; struct sockaddr_in saddr; unsigned int s 0; BOOL ret; time_t start; int error; host gethostbyname (m_server); if (hostNULL)return FALSE; saddr.sin_family AF_INET; saddr.sin_port htons(m_port); saddr.sin_addr ((struct in_addr)host-h_addr); if( (ssocket(AF_INET, SOCK_STREAM, 0))0){ return FALSE; } fcntl(s,F_SETFL, O_NONBLOCK); if(connect(s,(struct sockaddr)saddr, sizeof(saddr)) -1) { if (errno EINPROGRESS){// it is in the connect process struct timeval tv; fd_set writefds; tv.tv_sec m_nTimeOut; tv.tv_usec 0; FD_ZERO(writefds); FD_SET(s, writefds); if(select(s1,NULL,writefds,NULL,tv)0){ int lensizeof(int); // 下面的一句一定要主要针对防火墙 getsockopt(s, SOL_SOCKET, SO_ERROR, error, len); if(error0) retTRUE; else retFALSE; }else retFALSE;//timeout or error happen }else retFALSE; } else retTRUE; close(s); return ret; } setsockopt函数解析(转) - [IT]{#timeline} Tag IT int setsockopt ( SOCKET s , int level , int optname , const char FAR * optval , int optlen ); The Windows Sockets setsockopt function sets a socket option. 中文解释好像是设置套接字的选项。 先看如下代码 setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char )flag,sizeof(int)) 这里是设置SockRaw这个套接字的ip选项中的IP_HDRINCL 参考以下资料 ************************************************************************************************** Linux网络编程–8. 套接字选项 有时候我们要控制套接字的行为(如修改缓冲区的大小),这个时候我们就要控制套接字的选项了. 8.1 getsockopt和 setsockopt int getsockopt(int sockfd,int level,int optname,void *optval,socklen_t *optlen) int setsockopt(int sockfd,int level,int optname,const void *optval,socklen_t optlen) level指定控制套接字的层次.可以取三种值: 1)SOL_SOCKET:通用套接字选项. 2)IPPROTO_IP:IP选项. 3)IPPROTO_TCP:TCP选项. optname指定控制的方式(选项的名称),我们下面详细解释 optval获得或者是设置套接字选项.根据选项名称的数据类型进行转换 选项名称 说明 数据类型 SOL_SOCKET ———————————————————————— SO_BROADCAST 允许发送广播数据 int SO_DEBUG 允许调试 int SO_DONTROUTE 不查找路由 int SO_ERROR 获得套接字错误 int SO_KEEPALIVE 保持连接 int SO_LINGER 延迟关闭连接 struct linger SO_OOBINLINE 带外数据放入正常数据流 int SO_RCVBUF 接收缓冲区大小 int SO_SNDBUF 发送缓冲区大小 int SO_RCVLOWAT 接收缓冲区下限 int SO_SNDLOWAT 发送缓冲区下限 int SO_RCVTIMEO 接收超时 struct timeval SO_SNDTIMEO 发送超时 struct timeval SO_REUSERADDR 允许重用本地地址和端口 int SO_TYPE 获得套接字类型 int SO_BSDCOMPAT 与BSD系统兼容 int IPPROTO_IP ————————————————————————– IP_HDRINCL 在数据包中包含IP首部 int IP_OPTINOS IP首部选项 int IP_TOS 服务类型 IP_TTL 生存时间 int IPPRO_TCP ————————————————————————– TCP_MAXSEG TCP最大数据段的大小 int TCP_NODELAY 不使用Nagle算法 int 关于这些选项的详细情况请查看 Linux Programmers Manual 8.2 ioctl ioctl可以控制所有的文件描述符的情况,这里介绍一下控制套接字的选项. int ioctl(int fd,int req,…) ioctl的控制选项 ————————————————————————– SIOCATMARK 是否到达带外标记 int FIOASYNC 异步输入/输出标志 int FIONREAD 缓冲区可读的字节数 int 详细的选项请用 man ioctl_list 查看. 1.closesocket一般不会立即关闭而经历TIME_WAIT的过程后想继续重用该socket BOOL bReuseaddrTRUE; setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const char)bReuseaddr,sizeof(BOOL)); 2. 如果要已经处于连接状态的soket在调用closesocket后强制关闭不经历 TIME_WAIT的过程 BOOL bDontLinger FALSE; setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const char)bDontLinger,sizeof(BOOL)); 3.在send(),recv()过程中有时由于网络状况等原因发收不能预期进行,而设置收发时限 int nNetTimeout1000;//1秒 //发送时限 setsockopt(socketSOL_S0CKET,SO_SNDTIMEO(char )nNetTimeout,sizeof(int)); //接收时限 setsockopt(socketSOL_S0CKET, SO_RCVTIMEO(char *)nNetTimeout,sizeof(int)); 4.在send()的时候返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节 (异步);系统默认的状态发送和接收一次为8688字节(约为8.5K)在实际的过程中发送数据 和接收数据量比较大可以设置socket缓冲区而避免了send(),recv()不断的循环收发 // 接收缓冲区 int nRecvBuf321024;//设置为32K setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char)nRecvBuf,sizeof(int)); //发送缓冲区 int nSendBuf321024;//设置为32K setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char)nSendBuf,sizeof(int)); 5. 如果在发送数据的时希望不经历由系统缓冲区到socket缓冲区的拷贝而影响 程序的性能 int nZero0; setsockopt(socketSOL_S0CKET,SO_SNDBUF(char )nZero,sizeof(nZero)); 6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区) int nZero0; setsockopt(socketSOL_S0CKET,SO_RCVBUF(char )nZero,sizeof(int)); 7.一般在发送UDP数据报的时候希望该socket发送的数据具有广播特性 BOOL bBroadcastTRUE; setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char)bBroadcast,sizeof(BOOL)); 8.在client连接服务器过程中如果处于非阻塞模式下的socket在connect()的过程中可 以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的 作用在阻塞的函数调用中作用不大) BOOL bConditionalAcceptTRUE; setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const char)bConditionalAccept,sizeof(BOOL)); 9.如果在发送数据的过程中(send()没有完成还有数据没发送)而调用了closesocket(),以前我们 一般采取的措施是从容关闭shutdown(s,SD_BOTH),但是数据是肯定丢失了如何设置让程序满足具体 应用的要求(即让没发完的数据发送出去后在关闭socket) struct linger { u_short l_onoff; u_short l_linger; }; linger m_sLinger; m_sLinger.l_onoff1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留) // 如果m_sLinger.l_onoff0;则功能和2.)作用相同; m_sLinger.l_linger5;//(容许逗留的时间为5秒) setsockopt(s,SOL_SOCKET,SO_LINGER,(const char*)m_sLinger,sizeof(linger)); 二 boost windows asio自带的例子里是用deadline_timer的async_wait方法来实现超时的这种方法需要单独写一个回调函数不利于把连接和超时封装到单个函数里。传统的Winsock编程可以先把socket设为非阻塞然后connect再用select来判断超时asio也可以这样做唯一“非主流”的是asio里没有一个类似select的函数所以得调用原始的Winsock API也就牺牲了跨平台 #include iostream #include boost/asio.hpp int main() { boost::asio::io_service ios; boost::asio::ip::tcp::socket s(ios); boost::system::error_code ec; s.open(boost::asio::ip::tcp::v4()); // 设为非阻塞 s.io_control(boost::asio::ip::tcp::socket::non_blocking_io(true)); // connect时必须指定error_code参数否则会有异常抛出 s.connect( boost::asio::ip::tcp::endpoint( boost::asio::ip::address::from_string(192.168.1.1), 80) , ec); fd_set fdWrite; FD_ZERO(fdWrite); FD_SET(s.native(), fdWrite); timeval tv {5}; // 5秒超时 if (select(0, NULL, fdWrite, NULL, tv) 0 || !FD_ISSET(s.native(), fdWrite)) { std::cout 超时/出错啦 std::endl; s.close(); return 0; } // 设回阻塞 s.io_control(boost::asio::ip::tcp::socket::non_blocking_io(false)); std::cout 连接成功 std::endl; s.close(); return 0; } 三 同步异步 阻塞 非阻塞 [] 概念理解Linux下的五种IO模型 阻塞IO模型非阻塞IO模型IO复用模型信号驱动IO异步IO模型个IO模型的比较 selectpollepoll简介 socket阻塞与非阻塞同步与异步 作者huangguisu 1. 概念理解 在进行网络编程时我们常常见到同步(Sync)/异步(Async)阻塞(Block)/非阻塞(Unblock)四种调用方式 同步 所谓同步就是在发出一个功能调用时在没有得到结果之前该调用就不返回。也就是必须一件一件事做,等前一件做完了才能做下一件事。 例如普通B/S模式同步提交请求-等待服务器处理-处理完毕返回 这个期间客户端浏览器不能干任何事 异步 异步的概念和同步相对。当一个异步过程调用发出后调用者不能立刻得到结果。实际处理这个调用的部件在完成后通过状态、通知和回调来通知调用者。 例如 ajax请求异步: 请求通过事件触发-服务器处理这是浏览器仍然可以作其他事情-处理完毕 阻塞 阻塞调用是指调用结果返回之前当前线程会被挂起线程进入非可执行状态在这个状态下cpu不会给线程分配时间片即线程暂停运行。函数只有在得到结果之后才会返回。 有人也许会把阻塞调用和同步调用等同起来实际上他是不同的。对于同步调用来说很多时候当前线程还是激活的只是从逻辑上当前函数没有返回而已。 例如我们在socket中调用recv函数如果缓冲区中没有数据这个函数就会一直等待直到有数据才返回。而此时当前线程还会继续处理各种各样的消息。 非阻塞 非阻塞和阻塞的概念相对应指在不能立刻得到结果之前该函数不会阻塞当前线程而会立刻返回。 对象的阻塞模式和阻塞函数调用 对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式我们可以通过一定的API去轮询状 态在适当的时候调用阻塞函数就可以避免阻塞。而对于非阻塞对象调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。 1. 同步就是我调用一个功能该功能没有结束前我死等结果。 2. 异步就是我调用一个功能不需要知道该功能结果该功能有结果后通知我回调通知 3. 阻塞 就是调用我函数我函数没有接收完数据或者没有得到结果之前我不会返回。 4. 非阻塞 就是调用我函数我函数立即返回通过select通知调用者 同步IO和异步IO的区别就在于数据拷贝的时候进程是否阻塞 阻塞IO和非阻塞IO的区别就在于应用程序的调用是否立即返回 对于举个简单c/s 模式 同步提交请求-等待服务器处理-处理完毕返回这个期间客户端浏览器不能干任何事 异步请求通过事件触发-服务器处理这是浏览器仍然可以作其他事情-处理完毕 同步和异步都只针对于本机SOCKET而言的。 同步和异步,阻塞和非阻塞,有些混用,其实它们完全不是一回事,而且它们修饰的对象也不相同。 阻塞和非阻塞是指当进程访问的数据如果尚未就绪,进程是否需要等待,简单说这相当于函数内部的实现区别,也就是未就绪时是直接返回还是等待就绪; 而同步和异步是指访问数据的机制,同步一般指主动请求并等待I/O操作完毕的方式,当数据就绪后在读写的时候必须阻塞(区别就绪与读写二个阶段,同步的读写必须阻塞),异步则指主动请求数据后便可以继续处理其它任务,随后等待I/O,操作完毕的通知,这可以使进程在数据读写时也不阻塞。(等待通知) 1. Linux下的五种I/O模型 1)阻塞I/Oblocking I/O 2)非阻塞I/O nonblocking I/O 3) I/O复用(select 和poll) I/O multiplexing 4)信号驱动I/O signal driven I/O (SIGIO) 5)异步I/O asynchronous I/O (the POSIX aio_functions) 前四种都是同步只有最后一种才是异步IO。 阻塞I/O模型 简介进程会一直阻塞直到数据拷贝完成 应用程序调用一个IO函数导致应用程序阻塞等待数据准备好。 如果数据没有准备好一直等待….数据准备好了从内核拷贝到用户空间,IO函数返回成功指示。 阻塞I/O模型图在调用recv()/recvfrom函数时发生在内核中等待数据和复制数据的过程。 当调用recv()函数时系统首先查是否有准备好的数据。如果数据没有准备好那么系统就处于等待状态。当数据准备好后将数据从系统缓冲区复制到用户空间然后该函数返回。在套接应用程序中当调用recv()函数时未必用户空间就已经存在数据那么此时recv()函数就会处于等待状态。 当使用socket()函数和WSASocket()函数创建套接字时默认的套接字都是阻塞的。这意味着当调用Windows Sockets API不能立即完成时线程处于等待状态直到操作完成。 并不是所有Windows Sockets API以阻塞套接字为参数调用都会发生阻塞。例如以阻塞模式的套接字为参数调用bind()、listen()函数时函数会立即返回。将可能阻塞套接字的Windows Sockets API调用分为以下四种: 1输入操作 recv()、recvfrom()、WSARecv()和WSARecvfrom()函数。以阻塞套接字为参数调用该函数接收数据。如果此时套接字缓冲区内没有数据可读则调用线程在数据到来前一直睡眠。 2输出操作 send()、sendto()、WSASend()和WSASendto()函数。以阻塞套接字为参数调用该函数发送数据。如果套接字缓冲区没有可用空间线程会一直睡眠直到有空间。 3接受连接accept()和WSAAcept()函数。以阻塞套接字为参数调用该函数等待接受对方的连接请求。如果此时没有连接请求线程就会进入睡眠状态。 4外出连接connect()和WSAConnect()函数。对于TCP连接客户端以阻塞套接字为参数调用该函数向服务器发起连接。该函数在收到服务器的应答前不会返回。这意味着TCP连接总会等待至少到服务器的一次往返时间。 使用阻塞模式的套接字开发网络程序比较简单容易实现。当希望能够立即发送和接收数据且处理的套接字数量比较少的情况下使用阻塞模式来开发网络程序比较合适。 阻塞模式套接字的不足表现为在大量建立好的套接字线程之间进行通信时比较困难。当使用“生产者-消费者”模型开发网络程序时为每个套接字都分别分配一个读线程、一个处理数据线程和一个用于同步的事件那么这样无疑加大系统的开销。其最大的缺点是当希望同时处理大量套接字时将无从下手其扩展性很差 非阻塞IO模型 简介非阻塞IO通过进程反复调用IO函数 多次系统调用并马上返回 在数据拷贝的过程中进程是阻塞的 我们把一个SOCKET接口设置为非阻塞就是告诉内核当所请求的I/O操作无法完成时不要将进程睡眠而是返回一个错误。这样我们的I/O操作函数将不断的测试数据是否已经准备好如果没有准备好继续测试直到数据准备好为止。在这个不断测试的过程中会大量的占用CPU的时间。 把SOCKET设置为非阻塞模式即通知系统内核在调用Windows Sockets API时不要让线程睡眠而应该让函数立即返回。在返回时该函数返回一个错误代码。图所示一个非阻塞模式套接字多次调用recv()函数的过程。前三次调用recv()函数时内核数据还没有准备好。因此该函数立即返回WSAEWOULDBLOCK错误代码。第四次调用recv()函数时数据已经准备好被复制到应用程序的缓冲区中recv()函数返回成功指示应用程序开始处理数据。 当使用socket()函数和WSASocket()函数创建套接字时默认都是阻塞的。在创建套接字之后通过调用ioctlsocket()函数将该套接字设置为非阻塞模式。Linux下的函数是:fcntl(). 套接字设置为非阻塞模式后在调用Windows Sockets API函数时调用函数会立即返回。大多数情况下这些函数调用都会调用“失败”并返回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有时间完成。通常应用程序需要重复调用该函数直到获得成功返回代码。 需要说明的是并非所有的Windows Sockets API在非阻塞模式下调用都会返回WSAEWOULDBLOCK错误。例如以非阻塞模式的套接字为参数调用bind()函数时就不会返回该错误代码。当然在调用WSAStartup()函数时更不会返回该错误代码因为该函数是应用程序第一调用的函数当然不会返回这样的错误代码。 要将套接字设置为非阻塞模式除了使用ioctlsocket()函数之外还可以使用WSAAsyncselect()和WSAEventselect()函数。当调用该函数时套接字会自动地设置为非阻塞方式。 由于使用非阻塞套接字在调用函数时会经常返回WSAEWOULDBLOCK错误。所以在任何时候都应仔细检查返回代码并作好对“失败”的准备。应用程序连续不断地调用这个函数直到它返回成功指示为止。上面的程序清单中在While循环体内不断地调用recv()函数以读入1024个字节的数据。这种做法很浪费系统资源。 要完成这样的操作有人使用MSG_PEEK标志调用recv()函数查看缓冲区中是否有数据可读。同样这种方法也不好。因为该做法对系统造成的开销是很大的并且应用程序至少要调用recv()函数两次才能实际地读入数据。较好的做法是使用套接字的“I/O模型”来判断非阻塞套接字是否可读可写。 非阻塞模式套接字与阻塞模式套接字相比不容易使用。使用非阻塞模式套接字需要编写更多的代码以便在每个Windows Sockets API函数调用中对收到的WSAEWOULDBLOCK错误进行处理。因此非阻塞套接字便显得有些难于使用。 但是非阻塞套接字在控制建立的多个连接在数据的收发量不均时间不定时明显具有优势。这种套接字在使用上存在一定难度但只要排除了这些困难它在功能上还是非常强大的。通常情况下可考虑使用套接字的“I/O模型”它有助于应用程序通过异步方式同时对一个或多个套接字的通信加以管理。 IO复用模型 简介主要是select和epoll对一个IO端口两次调用两次返回比阻塞IO并没有什么优越性关键是能实现同时对多个IO端口进行监听 I/O复用模型会用到select、poll、epoll函数这几个函数也会使进程阻塞但是和阻塞I/O所不同的的这两个函数可以同时阻塞多个I/O操作。而且可以同时对多个读操作多个写操作的I/O函数进行检测直到有数据可读或可写时才真正调用I/O操作函数。 信号驱动IO 简介两次调用两次返回 首先我们允许套接口进行信号驱动I/O,并安装一个信号处理函数进程继续运行并不阻塞。当数据准备好时进程会收到一个SIGIO信号可以在信号处理函数中调用I/O操作函数处理数据。 异步IO模型 简介数据拷贝的时候进程无需阻塞。 当一个异步过程调用发出后调用者不能立刻得到结果。实际处理这个调用的部件在完成后通过状态、通知和回调来通知调用者的输入输出操作 同步IO引起进程阻塞直至IO操作完成。 异步IO不会引起进程阻塞。 IO复用是先通过select调用阻塞。 5个I/O模型的比较 1. select、poll、epoll简介 epoll跟select都能提供多路I/O复用的解决方案。在现在的Linux内核里有都能够支持其中epoll是Linux所特有而select则应该是POSIX所规定一般操作系统均有实现 select select本质上是通过设置或者检查存放fd标志位的数据结构来进行下一步处理。这样所带来的缺点是 1、 单个进程可监视的fd数量被限制即能监听端口的大小有限。 一般来说这个数目和系统内存关系很大具体数目可以cat /proc/sys/fs/file-max察看。32位机默认是1024个。64位机默认是2048. 2、 对socket进行扫描时是线性扫描即采用轮询的方法效率较低 当套接字比较多的时候每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数当他们活跃时自动完成相关操作那就避免了轮询这正是epoll与kqueue做的。 3、需要维护一个用来存放大量fd的数据结构这样会使得用户空间和内核空间在传递该结构时复制开销大 poll poll本质上和select没有区别它将用户传入的数组拷贝到内核空间然后查询每个fd对应的设备状态如果设备就绪则在设备等待队列中加入一项并继续遍历如果遍历完所有fd后没有发现就绪设备则挂起当前进程直到设备就绪或者主动超时被唤醒后它又要再次遍历fd。这个过程经历了多次无谓的遍历。 它没有最大连接数的限制原因是它是基于链表来存储的但是同样有一个缺点 1、大量的fd的数组被整体复制于用户态和内核地址空间之间而不管这样的复制是不是有意义。 2、poll还有一个特点是“水平触发”如果报告了fd后没有被处理那么下次poll时会再次报告该fd。 epoll: epoll支持水平触发和边缘触发最大的特点在于边缘触发它只告诉进程哪些fd刚刚变为就需态并且只会通知一次。还有一个特点是epoll使用“事件”的就绪通知方式通过epoll_ctl注册fd一旦该fd就绪内核就会采用类似callback的回调机制来激活该fdepoll_wait便可以收到通知 epoll的优点 1、没有最大并发连接的限制能打开的FD的上限远大于10241G的内存上能监听约10万个端口 2、效率提升不是轮询的方式不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数 即Epoll最大的优点就在于它只管你“活跃”的连接而跟连接总数无关因此在实际的网络环境中Epoll的效率就会远远高于select和poll。 3、 内存拷贝利用mmap()文件映射内存加速与内核空间的消息传递即epoll使用mmap减少复制开销。 select、poll、epoll 区别总结 1、支持一个进程所能打开的最大连接数 select 单个进程所能打开的最大连接数有FD_SETSIZE宏定义其大小是32个整数的大小在32位的机器上大小就是32*32同理64位机器上FD_SETSIZE为32*64当然我们可以对进行修改然后重新编译内核但是性能可能会受到影响这需要进一步的测试。 poll poll本质上和select没有区别但是它没有最大连接数的限制原因是它是基于链表来存储的 epoll 虽然连接数有上限但是很大1G内存的机器上可以打开10万左右的连接2G内存的机器可以打开20万左右的连接 2、FD剧增后带来的IO效率问题 select 因为每次调用时都会对连接进行线性遍历所以随着FD的增加会造成遍历速度慢的“线性下降性能问题”。 poll 同上 epoll 因为epoll内核中实现是根据每个fd上的callback函数来实现的只有活跃的socket才会主动调用callback所以在活跃socket较少的情况下使用epoll没有前面两者的线性下降的性能问题但是所有socket都很活跃的情况下可能会有性能问题。 3、 消息传递方式 select 内核需要将消息传递到用户空间都需要内核拷贝动作 poll 同上 epoll epoll通过内核和用户空间共享一块内存来实现的。 总结 综上在选择selectpollepoll时要根据具体的使用场合以及这三种方式的自身特点。 1、表面上看epoll的性能最好但是在连接数少并且连接都十分活跃的情况下select和poll的性能可能比epoll好毕竟epoll的通知机制需要很多函数回调。 2、select低效是因为每次它都需要轮询。但低效也是相对的视情况而定也可通过良好的设计改善
- 上一篇: 个人类网站类网站外贸网站建设深圳
- 下一篇: 个人免费建网站方法求做图的网站
相关文章
-
个人类网站类网站外贸网站建设深圳
个人类网站类网站外贸网站建设深圳
- 技术栈
- 2026年03月21日
-
个人空间网站免费网站建设提案ppt
个人空间网站免费网站建设提案ppt
- 技术栈
- 2026年03月21日
-
个人可以做哪些网站企业网站建设市场前景
个人可以做哪些网站企业网站建设市场前景
- 技术栈
- 2026年03月21日
-
个人免费建网站方法求做图的网站
个人免费建网站方法求做图的网站
- 技术栈
- 2026年03月21日
-
个人免费网站建设模板在线crm管理系统
个人免费网站建设模板在线crm管理系统
- 技术栈
- 2026年03月21日
-
个人免费网站开发珠海科技网站建设
个人免费网站开发珠海科技网站建设
- 技术栈
- 2026年03月21日






