当前位置: 首页 > news >正文

怎么查网站的注册信息百度信息流代运营

怎么查网站的注册信息,百度信息流代运营,如何建设淘宝客网站,推广运营培训课程一 1.首先将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数 2.调用connect,正常情况下,因为TCP三次握手需要一些时间;而非阻塞调用只要不能立即完成就会返回错误,所以这里会返回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(sockfd+1, 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中超时问题的总结
[size=18: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 (host==NULL)return  FALSE; 

        saddr.sin_family = AF_INET; 
        saddr.sin_port = htons(m_port); 
        saddr.sin_addr = *((struct in_addr*)host->h_addr); 


        if( (s=socket(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(s+1,NULL,&writefds,NULL,&tv)>0){ 
                                int len=sizeof(int); 
                               // 下面的一句一定要,主要针对防火墙
                                getsockopt(s, SOL_SOCKET, SO_ERROR, &error, &len); 
                                if(error==0) ret=TRUE; 
                                else ret=FALSE; 
                        }else   ret=FALSE;//timeout or error happen 
                }else ret=FALSE; 
        } 
        else    ret=TRUE; 

        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 Programmer"s 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 bReuseaddr=TRUE;
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 nNetTimeout=1000;//1秒
//发送时限
setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char *)&nNetTimeout,sizeof(int));
//接收时限
setsockopt(socket,SOL_S0CKET, SO_RCVTIMEO,(char *)&nNetTimeout,sizeof(int));
4.在send()的时候,返回的是实际发送出去的字节(同步)或发送到socket缓冲区的字节
(异步);系统默认的状态发送和接收一次为8688字节(约为8.5K);在实际的过程中发送数据
和接收数据量比较大,可以设置socket缓冲区,而避免了send(),recv()不断的循环收发:
// 接收缓冲区
int nRecvBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&nRecvBuf,sizeof(int));
//发送缓冲区
int nSendBuf=32*1024;//设置为32K
setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&nSendBuf,sizeof(int));
5. 如果在发送数据的时,希望不经历由系统缓冲区到socket缓冲区的拷贝而影响
程序的性能:
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&nZero,sizeof(nZero));
6.同上在recv()完成上述功能(默认情况是将socket缓冲区的内容拷贝到系统缓冲区):
int nZero=0;
setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&nZero,sizeof(int));
7.一般在发送UDP数据报的时候,希望该socket发送的数据具有广播特性:
BOOL bBroadcast=TRUE;
setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const char*)&bBroadcast,sizeof(BOOL));
8.在client连接服务器过程中,如果处于非阻塞模式下的socket在connect()的过程中可
以设置connect()延时,直到accpet()被呼叫(本函数设置只有在非阻塞的过程中有显著的
作用,在阻塞的函数调用中作用不大)
BOOL bConditionalAccept=TRUE;
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_onoff=1;//(在closesocket()调用,但是还有数据没发送完毕的时候容许逗留)
// 如果m_sLinger.l_onoff=0;则功能和2.)作用相同;
m_sLinger.l_linger=5;//(容许逗留的时间为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,也就牺牲了跨平台:

  
  1. #include <iostream>  
  2. #include <boost/asio.hpp>  
  3.    
  4. int main()  
  5. {  
  6.     boost::asio::io_service ios;  
  7.     boost::asio::ip::tcp::socket s(ios);  
  8.     boost::system::error_code ec;  
  9.    
  10.     s.open(boost::asio::ip::tcp::v4());  
  11.     // 设为非阻塞  
  12.     s.io_control(boost::asio::ip::tcp::socket::non_blocking_io(true));  
  13.     // connect时必须指定error_code参数,否则会有异常抛出  
  14.     s.connect(  
  15.         boost::asio::ip::tcp::endpoint(  
  16.         boost::asio::ip::address::from_string("192.168.1.1"), 80)  
  17.         , ec);  
  18.     fd_set fdWrite;  
  19.     FD_ZERO(&fdWrite);  
  20.     FD_SET(s.native(), &fdWrite);  
  21.     timeval tv = {5};    // 5秒超时  
  22.     if (select(0, NULL, &fdWrite, NULL, &tv) <= 0   
  23.         || !FD_ISSET(s.native(), &fdWrite))  
  24.     {  
  25.         std::cout << "超时/出错啦" << std::endl;  
  26.         s.close();  
  27.         return 0;  
  28.     }  
  29.     // 设回阻塞  
  30.     s.io_control(boost::asio::ip::tcp::socket::non_blocking_io(false));  
  31.     std::cout << "连接成功" << std::endl;  
  32.     s.close();  
  33.    
  34.     return 0;  
三 同步异步 阻塞 非阻塞
[+]
  1. 概念理解
  2. Linux下的五种IO模型
    1. 阻塞IO模型
    2. 非阻塞IO模型
    3. IO复用模型
    4. 信号驱动IO
    5. 异步IO模型
    6. 个IO模型的比较
  3. 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/O(blocking 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的回调机制来激活该fd,epoll_wait便可以收到通知

epoll的优点:

1、没有最大并发连接的限制,能打开的FD的上限远大于1024(1G的内存上能监听约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通过内核和用户空间共享一块内存来实现的。

总结:

综上,在选择select,poll,epoll时要根据具体的使用场合以及这三种方式的自身特点。

1、表面上看epoll的性能最好,但是在连接数少并且连接都十分活跃的情况下,select和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调。

2、select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善

 

 

http://www.15wanjia.com/news/55712.html

相关文章:

  • 成都企业网站制作哪家好印度疫情最新消息
  • 网站维护方式网络文章发布平台
  • 在厦门注册公司的流程win10优化大师
  • 在建设部网站网站快速排名服务商
  • 给单位做网站需要备案吗高中同步测控优化设计答案
  • 图片手机显示wordpress上海网站营销seo电话
  • 简单网站建设公司淘宝自动推广软件
  • 江门网站优化公司b站网站推广
  • 用jsp做的网站首页推广引流平台
  • 网站运营与推广计划书怎么做杭州百度seo代理
  • 上海旅游网站建设情况谷歌seo怎么优化
  • 做套网站多少钱seo优化运营
  • 门户网站建设为企业带来的好处太原做网站的
  • win7在局域网做网站营销策划推广
  • 做网站怎么发布seo外链发布平台
  • 适合做网站背景的图片百中搜优化软件靠谱吗
  • 初中生电脑作业做网站微信广告投放推广平台多少费用
  • 如何看到网站做哪些关键字外贸网站推广费用
  • 台山网站设计seo优化推广专员招聘
  • 网站建设费用价格明细表seo站内优化教程
  • 高清网站seoseo网站优化工具
  • 北京住房城乡建设委官方网站百度seo优化网站
  • 重庆网站设计最加科技百搜网络科技有限公司
  • asp 网站开发 软件整站seo定制
  • 中山市做网站实力简述网站建设的流程
  • 网站模板熊猫关键词工具官网
  • laravel 做中英文网站台湾搜索引擎
  • 简述企业网站建设的主要步骤百度站长平台链接
  • 软件开发和网站开发网站推广如何引流
  • 网站建设项目运作的可行性google 推广优化