??xml version="1.0" encoding="utf-8" standalone="yes"?>久久中文骚妇内射,人妻久久久一区二区三区,亚洲欧洲精品成人久久奇米网http://www.shnenglu.com/cxiaojia/category/19331.html厚d 博学 求真 臛_ The bright moon and breezezh-cnSat, 13 Apr 2013 04:13:39 GMTSat, 13 Apr 2013 04:13:39 GMT60ACE前摄器Proactor最好的讲解Q{载)(j)http://www.shnenglu.com/cxiaojia/archive/2013/04/12/199385.htmlC加C加Fri, 12 Apr 2013 09:43:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2013/04/12/199385.htmlhttp://www.shnenglu.com/cxiaojia/comments/199385.htmlhttp://www.shnenglu.com/cxiaojia/archive/2013/04/12/199385.html#Feedback2http://www.shnenglu.com/cxiaojia/comments/commentRss/199385.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/199385.html转自Q?a >http://blog.csdn.net/caisini_vc/article/details/4474910
把这两天做Proactor的一些经验和?j)得写一下,可能?x)给一些h帮助?br />    Proactor是异步模式的|络处理器,ACE中叫?#8220;前摄?#8221;?br />    先讲几个概念Q?br />    前摄器(ProactorQ-异步的事件多路分d、处理器Q是核心(j)处理cR启动后?个线E组成(你不需要关?j)这三个U程Q我只是让你知道一下有q回事存在)(j)?br />    接受器(AcceptorQ-用于服务端,监听在一个端口上Q接受用L(fng)h?br />    q接器(ConnectorQ-用于客户端,去连接远E的监听。当?dng)如果q程是ACE写的Q就是Acceptor?br />    异步模式Q即非阻塞模式。网l的传输速度一般来讲ؓ(f)10Mbps?00Mbps?000Mbps。拿千兆|来_(d)实际的传输速度?000Mbps/8大概?28KB左右。我们的CPU一般ؓ(f)P4 3.0GHZQ如果是32位的处理器,一U钟大概可以处理6G的字节,那么Q?28KB的网l速度是远q及(qing)不上处理器的速度的。网l发送数据是一位一位发送出ȝQ如果CPU{在q里Q发送完成函数才l束Q那么,处理器浪费了(jin)大量旉在网l传输上?br />    操作pȝ提供?jin)异步的模式来传输网l数据,工作模式卻I(x)应用E序把要发送的数据交给操作pȝQ操作系l把数据攑֜pȝ~冲区后告诉应用程序OK?jin),我帮你发Q应用程序该q嘛q嘛厅R操作系l发送完成后Q会(x)l应用系l一个回执,告诉应用E序Q刚才那个包发送完成了(jin)Q?br />   举个例子Q你有几邮件和包裹要发Q最有效率的办法是什么?你把邮g和包裹及(qing)交给dQdMM_(d)好了(jin)Q你帮你发,你忙dQ然后你d作了(jin)。过?jin)一?x),dMM打电(sh)话告诉你Q?#8220;刚才我叫快递公司的人来?jin),把你的包裹发出去了(jin)。邮局的h也来?jin),取走了(jin)邮Ӟ攑ֿ?j)好了(jin)”。同P如果你知道今天会(x)有包Ҏ(gu)Q比如你在淘宝上购物?jin),你能成天{在dQ你应该告诉dMMQ?#8220;今天可能有我的一个快递,你帮我收一下,晚上请你肯d基!”。MMQ?#8220;看在肯得基的面子上,帮你收了(jin)”。某个时_(d)MM打电(sh)话来?jin)?x)“帅哥Q你的包裹到?jin),我帮你签收?jin)Q快来拿吧?#8221;
   因ؓ(f)操作pȝ是很有效率的Q所有,他在后台收发是很快的。应用程序也很简单。Proactor是q种异步模式的。Proactor是dMMQACE_Service_Handle是d代ؓ(f)收发邮g的公司流E?/p>

我们看一个实例:(x)


//***********************************************************
class TPTCPAsynchServerImpl : public ACE_Service_Handler
{
public:
 TPTCPAsynchServerImpl(
void);
 
~TPTCPAsynchServerImpl(void);
 
virtual void open (ACE_HANDLE handle, ACE_Message_Block &message_block); 
 
virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
 
virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
 
virtual void  handle_time_out (const ACE_Time_Value &tv, const void *act=0);
private:
 
int initiate_read_stream (const ACE_Asynch_Read_Stream::Result &result);
 ACE_Asynch_Read_Stream rs_;
 ACE_Asynch_Write_Stream ws_;
};


q个例子从ACE_Service_Handlerl承q来QACE_Service_Handle主要是定义?jin)一些回调函数?br />1?virtual void open (ACE_HANDLE handle, ACE_Message_Block &message_block);
  当有客户端连接上来,q接建立成功后Proactor?x)调用这个方法?/p>

2?virtual void handle_read_stream (const ACE_Asynch_Read_Stream::Result &result);
当用戯ȝ数据d?jin)后Q调用这个方?/p>

3、virtual void handle_write_stream (const ACE_Asynch_Write_Stream::Result &result);
当用戯写的数据在网卡上发送成功后QProactor?x)回调这个方?/p>

4?virtual void  handle_time_out (const ACE_Time_Value &tv, const void *act=0);
当用戯定的旉到期?jin),q个Ҏ(gu)?x)被调用?/p>

q跟和dMM的联l方法是不是一L(fng)Q?/p>

对还~点东西Q缺怎么向dMM交待d的方法。下面看看:(x)

首先Q创Z个监听器?/p>

 ACE_Asynch_Acceptor<TPTCPAsynchServerImpl> acceptor_;
看到没,是我们刚才写的c,因ؓ(f)他承了(jin)回调接口Qƈ实现?jin)自已的代码Q模板中ACE_Asynch_Acceptor?x)在合适的时候回调这些方法?/p>

//创徏一个地址对象
 ACE_INET_Addr addr(port, ip);
acceptor_.open (addr, 8 * 1024, 1);
    Open后,开始监听了(jin)。其它的Q向Proactor注册一些事件的事模板类中都替你做了(jin)Q你不需要做很多事?br />    那么Q已l开始监听了(jin)Q我的程序从哪里开始呢Q对于一个服务程序来ԌE序是被用户的连接驱动的Q一个用L(fng)序想和通讯Q必d创徏q接Q就是Socket中的connect操作。这个操作Proactor?x)替我们做一些工作,当连接创建完成后Q上面讲的OpenҎ(gu)?x)被调用Q我们看看OpenҎ(gu)中都有些什么代码:(x)


void TPTCPAsynchServerImpl::open (ACE_HANDLE handle, ACE_Message_Block &message_block)
{
 ACE_DEBUG ((LM_DEBUG, 
"%N:%l:TPTCPAsynchServerImpl::open() "));
 
//构造读?/span>
 if (rs_.open (*this, handle) == -1)
 {
  ACE_ERROR ((LM_ERROR, 
"%N:%l: ""TPTCPAsynchServerImpl::open() Error"));
  
return;
    }
 
//构造写?/span>
 if (ws_.open(*this, handle) == -1)
 {
  ACE_ERROR ((LM_ERROR, 
"%N:%l: ""TPTCPAsynchServerImpl::open() Error"));
  
return;
    }
 
//获取客户端连接地址和端?/span>
 ACE_INET_Addr addr; 
 ACE_SOCK_SEQPACK_Association ass
=ACE_SOCK_SEQPACK_Association(handle); 
 size_t addr_size
=1
 ass.get_local_addrs(
&addr,addr_size);
 
this->server_->onClientConnect((int)handle, addr.get_ip_address(), addr.get_port_number());

 

 
//如果客户q接时同时提交了(jin)数据Q需要伪造一个结果,然后呼叫M?/span>
 if (message_block.length () != 0)
 {
 
// ACE_DEBUG((LM_DEBUG, "message_block.length() != 0 "));
  
// 复制消息?/span>
  ACE_Message_Block &duplicate =  *message_block.duplicate ();
  
// 伪造读l果Q以便进行读完成回调
  ACE_Asynch_Read_Stream_Result_Impl *fake_result =
        ACE_Proactor::instance ()
->create_asynch_read_stream_result (this->proxy (),
                                                                     
this->handle_,
                                                                     duplicate,
                                                                     
1024,
                                                                     
0,
                                                                     ACE_INVALID_HANDLE,
                                                                     
0,
                                                                     
0);
  size_t bytes_transferred 
= message_block.length ();
  
// Accept事g处理完成Qwr_ptr指针?x)被向前UdQ将其移动到开始位|?/span>
  duplicate.wr_ptr (duplicate.wr_ptr () - bytes_transferred);
  
// q个Ҏ(gu)调用回调函?/span>
  fake_result->complete (message_block.length (), 10);
  
// 销毁伪造的ȝ?/span>
  delete fake_result;
 }

 
// 否则Q通知底层Q准备读取用h?br /> //创徏一个消息块。这个消息块用于从套接字中异步?nbsp;
 ACE_Message_Block *mb = 0;
  ACE_NEW (mb, ACE_Message_Block (_bufSize));
 
if (rs_.read (*mb, mb->size () - 1== -1)
 {
  delete mb;
  ACE_ERROR ((LM_ERROR, 
"%N:%l:open init read failed!"));
  
return;
 }
}

 

我们看到Q首先创Z(jin)两个,是前面cd义中定义的一个异步写,一个异步读。以后对|络的读和写通过q两个流q行。我q给Z(jin)一D读客户端地址和端口的代码。然后是d客户Connect可能附带的数据,那段代码不用看懂Q以后用照抄就行。然后就?/p>

 


if (rs_.read (*mb, mb->size () - 1) == -1)
 {
  delete mb;
  ACE_ERROR ((LM_ERROR, "%N:%l:open init read failed!"));
  return;
 }

q段代码使用LMD|据。这D代码就是向dMM交待Q我要收包裹Q收好了(jin)叫我Q?br />也就是说Q这D代?9%的可能是M出数据的Q只是向Proactor注册ȝ事gQ具体的{待、读取操作由P(pn)roactor读,d?jin),回调Handle_Read_StreamҎ(gu)。ACE_Message_Block是消息块Q数据就是存攑֜消息块中的?br />下面看看Handle_Read_StreamҎ(gu)的代码:(x)


void TPTCPAsynchServerImpl::handle_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
 result.message_block ().rd_ptr ()[result.bytes_transferred ()] 
= '/0';
  ACE_DEBUG ((LM_DEBUG, 
"********************/n"));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""bytes_to_read", result.bytes_to_read ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""handle", result.handle ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""bytes_transfered", result.bytes_transferred ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""act", (u_long) result.act ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""success", result.success ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""completion_key", (u_long) result.completion_key ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d/n""error", result.error ()));
  ACE_DEBUG ((LM_DEBUG, 
"********************/n"));
 result.message_block().release();
 
if (this->initiate_read_stream (result) == -1)
 {
  ACE_ERROR((LM_ERROR, 
"%N:%l:read stream failed!connection closed, remove it:%d/n", result.handle()));
  closeConnection(result.handle());
 } 
}
 

q个函数被调用,p明有数据已经d?jin),包裹已经在d?jin)。Proactor比dMMq好Q给你送上门了(jin)Q数据就在Result里,上面演示?jin)Result中的数据。然后把消息块释放了(jin)Q然后调用initiate_read_streaml箋(hu)监听|络上可能到来的数据。看看initiate_read_stream好了(jin)Q?/p>


int TPTCPAsynchServerImpl::initiate_read_stream (const ACE_Asynch_Read_Stream::Result &result)
{
 ACE_DEBUG((LM_TRACE, 
"%N:%l:TPTCPAsynchServerImpl::initiate_read_stream() "));
 
//创徏一个消息块。这个消息块用于从套接字中异步?nbsp;
 ACE_Message_Block *mb = new ACE_Message_Block(_bufSize);
 
if (mb == NULL)
 {
  ACE_DEBUG((LM_ERROR, 
"%N:%l:can't allock ACE_Message_Block.  ")); 
  
return -1;
 }
 
 
if (rs_.read (*mb, mb->size () - 1== -1)
 {
  delete mb;
  ACE_ERROR_RETURN ((LM_ERROR, 
"%N:%l:rs->read() failed, clientID=%d ", result.handle()),  -1);
 }
 
return 0;
}

 

代码很简单,是创徏一个新的消息块Q然后用读注册一个读消息可以了(jin)?/p>

到此为止QProactor的读程很清楚了(jin)吧?

下面再说一个写程?/p>

写流E其实更单,在Q意想向客L(fng)写数据的地方Q调用相应代码就行了(jin)Q比如,我们提供?jin)SendDataҎ(gu)来发送数据,在Q意想发送数据的地方调用SendDatap?jin),SendData的代码如下:(x)

int TPTCPAsynchServerImpl::sendData(int clientID, const char *data, int dataLen, unsigned int &id)
{
 ACE_DEBUG((LM_DEBUG, 
"TPTCPAsynchServerImpl::sendData(void) "));
 ACE_Message_Block 
*mb; 
 ACE_NEW_RETURN(mb, ACE_Message_Block(dataLen 
+ 1), -1);
 mb
->wr_ptr((char*)data);                  
 ACE_OS::memcpy(mb
->base(),(char*)data, dataLen);
 id 
= GlobleSingleton::instance()->getIndex();
 mb
->msg_type((int)id);
 
//向操作系l发送数?/span>
 if (connection->ws->write (*mb , dataLen ) == -1)
 {
  ACE_ERROR_RETURN((LM_ERROR, 
"%N:%l:sendData failed! clientID=%d ", clientID),-1);
 }
 
return 0;
}

 

单说Q就是创Z(jin)一个消息块Q把用户数据拯q来Q然后调用写WS向Proactor发送一个Write事g可以了(jin)Q发送成功后QHandle_write_handle?x)被调用Q看一下:(x)


void
TPTCPAsynchServerImpl::handle_write_stream (
const ACE_Asynch_Write_Stream::Result &result)
{
  ACE_DEBUG ((LM_DEBUG,
              
"handle_write_stream called "));
  
// Reset pointers.
  result.message_block ().rd_ptr (result.message_block ().rd_ptr () - result.bytes_transferred ());
  ACE_DEBUG ((LM_DEBUG, 
"******************** "));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""bytes_to_write", result.bytes_to_write ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""handle", result.handle ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""bytes_transfered", result.bytes_transferred ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""act", (u_long) result.act ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""success", result.success ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""completion_key", (u_long) result.completion_key ()));
  ACE_DEBUG ((LM_DEBUG, 
"%s = %d ""error", result.error ()));
  ACE_DEBUG ((LM_DEBUG, 
"******************** "));
#if 0
  ACE_DEBUG ((LM_DEBUG, 
"%s = %s ""message_block", result.message_block ().rd_ptr ()));
#endif
  
// Release message block.
  result.message_block ().release ();
}

 

代码中用了(jin)result中发数据Q然后把消息块释放了(jin)Q就q么单?/p>


////////////////////////////////////////////////////////////////////////////////////////////////////

q是单的proactor用法Q当?dng)复杂也基本就q样用。所谓不基本的不是Proactor的内容,而是服务器编E本w的ȝ(ch)。比如说Q多个连接的理、重发机制、发送队列等{,q都不是ACE的内宏V这些要大家自己思考了(jin)Qƈd?/p>

在这里,我要说几个重要的问题Q连接的理。Acceptor是一个类Q但是在每一个连接,Proactor都用?jin)某U办法创Z(jin)一个实例,所以,q接理的群集类一定不能在AcceptorcMQ不然得到的l果是始终只有一条记录。因为每个Acceptor都有一个实例,实例对应一个连接,集cM每个实例一个了(jin)。要采取的方法是一个全局的容器对象就可以?jin)。比如我q个c:(x)


typedef ACE_Map_Manager 
<ACE_HANDLE, ConnectionBean *, ACE_Null_Mutex> ConnectionMap;
typedef ACE_Map_Iterator
<ACE_HANDLE, ConnectionBean *, ACE_Null_Mutex> ConnectionIterator;
typedef ACE_Map_Entry   
<ACE_HANDLE, ConnectionBean *> ConnectionEntry;
class Globle
{
public:
 Globle(
void);
 
~Globle(void);
 ITPServer
* server_;
 ConnectionMap _connections;
 unsigned getIndex(
void); 
 
long getTimerId(void);
private:
 unsigned 
int index_;
 
long timerId_;
};
typedef ACE_Singleton
<Globle, ACE_Null_Mutex> GlobleSingleton;

 

我用ACE的Singleton模板创徏q个c,每一个Acceptor要用ConnectionMapQ都使用q里的_connectionsQ方法如?Q?br />  GlobleSingleton::instance()->connection.bind()......

q个问题可是我花费了(jin)2天时间找出来的,怽同仁不可不戒啊,l点掌声Q)(j)



C加 2013-04-12 17:43 发表评论
]]>
ACE|络~程W记Q?Q:(x)ACE自适配通信环境http://www.shnenglu.com/cxiaojia/archive/2013/04/08/199198.htmlC加C加Mon, 08 Apr 2013 01:48:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2013/04/08/199198.htmlhttp://www.shnenglu.com/cxiaojia/comments/199198.htmlhttp://www.shnenglu.com/cxiaojia/archive/2013/04/08/199198.html#Feedback0http://www.shnenglu.com/cxiaojia/comments/commentRss/199198.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/199198.html介绍


      ACE自适配通信环境QADAPTIVE Communication EnvironmentQ是可以自由使用、开放源码的面向对象QOOQ构ӞF(tun)rameworkQ,在其中实C(jin)许多用于q发通信软g的核?j)模式。ACE提供?jin)一l丰富的可复用C++Wrapper FacadeQ包装外观)(j)和构架组Ӟ可跨多U^台完成通用的通信软gdQ其中包括:(x)事g多\分离和事件处理器分派、信号处理、服务初始化、进E间通信、共享内存管理、消息\由、分布式服务动态(重)(j)配置、ƈ发执行和同步Q等{?br />      ACE的目标用h高性能和实旉信服务和应用的开发者。它化了(jin)使用q程间通信、事件多路分R显式动态链接和q发的OO|络应用和服务的开发。此外,通过服务在运行时与应用的动态链接,ACEq(sh)ɾpȝ的配|和重配|得以自动化?br />



好处


增强可移植?/strong>Q在ACElg的帮助下Q很Ҏ(gu)在一UOSq_上编写ƈ发网l应用,然后快速地它们移植到各种其他的OSq_上。而且Q因为ACE是开放源码的自由软gQ你无需担心(j)被锁定在特定的操作系l^台或~译器上?br />更好的Y件质量:(x)ACE的设计用了(jin)许多可提高Y件质量的关键模式Q这些质量因素包括通信软g灉|性、可扩展性、可复用性和模块性?br /> 更高的效率和可预性:(x)ACEl仔l设计,支持q泛的应用服务质量(QoSQ需求,包括延迟敏感应用的低响应{待旉、高带宽应用的高性能Q以?qing)实时应用的可预性?br />更容易{换到标准的高U中间gQ?/strong>TAO使用?jin)ACE提供的可复用lg和模式。它是CORBA的开发源码、遵循标准的实现Qƈ为高性能和实时系l作?jin)优化。ؓ(f)此,ACE和TAO被设计ؓ(f)能良好地协同工作Q以提供全面的中间g解决Ҏ(gu)?br />
体系l构


OS适配层:(x)ACE底层Q和OS的API相关的部分。这部分ACE把不同类型的OS接口l一hQ让ACE的高层摆脱^台的依赖性。适配层增Z(jin)代码的可UL性?br />C++包装层:(x)ACE中间层,主要功能的实现部分。包括ƈ发和同步、IPC、内存管理组件、定时器cR容器类、信号处理、文件系l组件和U程理?br />构架和模式层Q?/strong>ACE高层Q架构和模式部分。它们的基础是若q针对特定通信软g领域的设计模式。包括事件处理、连接或服务初始化组件、流lg和服务配|组件?br />

 



C加 2013-04-08 09:48 发表评论
]]>
ACE|络~程之ACE_NEW_RETURNQACE_NEWQACE_NEW_NORETURNhttp://www.shnenglu.com/cxiaojia/archive/2013/03/26/198838.htmlC加C加Tue, 26 Mar 2013 07:26:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2013/03/26/198838.htmlhttp://www.shnenglu.com/cxiaojia/comments/198838.htmlhttp://www.shnenglu.com/cxiaojia/archive/2013/03/26/198838.html#Feedback0http://www.shnenglu.com/cxiaojia/comments/commentRss/198838.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/198838.htmlOS_Memory.h是这样定义的?br />
#  if defined (ACE_HAS_NEW_NOTHROW)
#    define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
   do { POINTER = new (ACE_nothrow) CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; return RET_VAL; } \
   } while (0)
#    define ACE_NEW(POINTER,CONSTRUCTOR) \
   do { POINTER = new(ACE_nothrow) CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; return; } \
   } while (0)
#    define ACE_NEW_NORETURN(POINTER,CONSTRUCTOR) \
   do { POINTER = new(ACE_nothrow) CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; } \
   } while (0)

#  else

#    define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
   do { try { POINTER = new CONSTRUCTOR; } \
     catch (ACE_bad_alloc) { ACE_del_bad_alloc errno = ENOMEM; POINTER = 0; return RET_VAL; } \
   } while (0)

#    define ACE_NEW(POINTER,CONSTRUCTOR) \
   do { try { POINTER = new CONSTRUCTOR; } \
     catch (ACE_bad_alloc) { ACE_del_bad_alloc errno = ENOMEM; POINTER = 0; return; } \
   } while (0)

#    define ACE_NEW_NORETURN(POINTER,CONSTRUCTOR) \
   do { try { POINTER = new CONSTRUCTOR; } \
     catch (ACE_bad_alloc) { ACE_del_bad_alloc errno = ENOMEM; POINTER = 0; } \
   } while (0)
#  endif /* ACE_HAS_NEW_NOTHROW */

#else /* ACE_NEW_THROWS_EXCEPTIONS */

# define ACE_NEW_RETURN(POINTER,CONSTRUCTOR,RET_VAL) \
   do { POINTER = new CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; return RET_VAL; } \
   } while (0)
# define ACE_NEW(POINTER,CONSTRUCTOR) \
   do { POINTER = new CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; return; } \
   } while (0)
# define ACE_NEW_NORETURN(POINTER,CONSTRUCTOR) \
   do { POINTER = new CONSTRUCTOR; \
     if (POINTER == 0) { errno = ENOMEM; } \
   } while (0)

以上是用宏定义替换的表达式,功能都是用一个POINTER指针new一个CONSTRUCTOR实例Q内部做?jin)一些错误信息的标志和异常处理?br />宏ifelse对^台的不同q行?jin)分,每个q_下都有三Unew的方法,他们的区别是return?br />每个宏定义都用到?jin)do{}while(0)Q是因ؓ(f)宏只能替换一句表辑ּQ而你用do{}while(0)可以方便的把多个表达式集中v来?img src ="http://www.shnenglu.com/cxiaojia/aggbug/198838.html" width = "1" height = "1" />

C加 2013-03-26 15:26 发表评论
]]>
socketd与非dQ同步与异步、I/O模型(?http://www.shnenglu.com/cxiaojia/archive/2013/03/26/198831.htmlC加C加Tue, 26 Mar 2013 05:36:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2013/03/26/198831.htmlhttp://www.shnenglu.com/cxiaojia/comments/198831.htmlhttp://www.shnenglu.com/cxiaojia/archive/2013/03/26/198831.html#Feedback0http://www.shnenglu.com/cxiaojia/comments/commentRss/198831.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/198831.html

转自Q?a >http://blog.csdn.net/hguisu/article/details/7453390


1. 概念理解

     在进行网l编E时Q我们常常见?span style="margin: 0px; padding: 0px; font-family: Arial, Helvetica, sans-serif, ?hu)? font-size: 12px; line-height: 16px; text-indent: 24px;">同步(Sync)/异步(Async)Q阻?Block)/非阻?Unblock)四种调用方式Q?/span>
同步Q?/span>
      
所谓同步,是在发Z个功能调用时Q在没有得到l果之前Q该调用׃q回?/span>也就是必M件一件事?/strong>,{前一件做完了(jin)才能做下一件事?/span>

例如普?span style="margin: 0px; padding: 0px; font-family: 'Times New Roman';">B/S模式Q同步)(j)Q提交请?span style="margin: 0px; padding: 0px; font-family: 'Times New Roman';">->{待服务器处?span style="margin: 0px; padding: 0px; font-family: 'Times New Roman';">->处理完毕q回 q个期间客户端浏览器不能qQ何事

异步Q?/span>
      
异步的概念和同步相对。当一个异步过E调用发出后Q调用者不能立d到结果。实际处理这个调用的部g在完成后Q通过状态、通知和回调来通知调用者?/span>

     例如 ajaxhQ?/span>异步Q?/span>h通过事g触发->服务器处理(q是览器仍然可以作其他事情Q?/span>->处理完毕

d
     
d调用是指调用l果q回之前Q当前线E会(x)被挂PU程q入非可执行状态,在这个状态下Qcpu不会(x)l线E分配时间片Q即U程暂停q行Q。函数只有在得到l果之后才会(x)q回?/span>

     有h也许?x)把d调用和同步调用等同v来,实际上他是不同的。对于同步调用来_(d)很多时候当前线E还是激zȝQ只是从逻辑上当前函数没有返回而已?/span> 例如Q我们在socket中调用recv函数Q如果缓冲区中没有数据,q个函数׃(x)一直等待,直到有数据才q回。而此Ӟ当前U程q(sh)(x)l箋(hu)处理各种各样的消息?/span>

非阻?/strong>
      
非阻塞和d的概늛对应Q指在不能立d到结果之前,该函C?x)阻塞当前线E,而会(x)立刻q回?/span>
对象的阻塞模式和d函数调用
对象是否处于d模式和函数是不是d调用有很强的相关性,但是q不是一一对应的。阻塞对象上可以有非d的调用方式,我们可以通过一定的API去轮询状 态,在适当的时候调用阻塞函敎ͼ可以避免阻塞。而对于非d对象Q调用特D的函数也可以进入阻塞调用。函?/span>select是q样的一个例子?/span>

 

1. 同步Q就是我调用一个功能,该功能没有结束前Q我ȝl果?/span>
2. 异步Q就?span style="margin: 0px; padding: 0px; line-height: 20px;">我调用一个功能,不需要知道该功能l果Q该功能有结果后通知我(回调通知Q?/span>
3. dQ?     是调用我(函数Q,?span style="margin: 0px; padding: 0px; line-height: 20px;">Q函敎ͼ(j)没有接收完数据或者没有得到结果之前,我不?x)返回?/span>
4. 非阻塞,  是调用?span style="margin: 0px; padding: 0px; line-height: 20px;">Q函敎ͼ(j)Q我Q函敎ͼ(j)立即q回Q?span style="margin: 0px; padding: 0px; line-height: 20px;">通过select通知调用?/span>

同步IO和异步IO的区别就在于Q?span style="margin: 0px; padding: 0px; color: #ff0000;">数据拯的时候进E是否阻塞!

dIO和非dIO的区别就在于Q?/span>应用E序的调用是否立卌回!


对于举个单c/s 模式Q?/span>

同步Q?/span>提交h->{待服务器处?>处理完毕q回q个期间客户端浏览器不能qQ何事
异步Q?/span>h通过事g触发->服务器处理(q是览器仍然可以作其他事情Q?>处理完毕
同步和异步都只针对于本机SOCKET而言的?/span>

同步和异?d和非d,有些L(fng),其实它们完全不是一回事,而且它们修饰的对象也不相同?br style="margin: 0px; padding: 0px;" />d和非d是指当进E访问的数据如果未qA,q程是否需要等?单说q相当于函数内部的实现区?/span>,也就是未qA时是直接q回q是{待qA;

而同步和异步?/span>指访问数据的机制,同步一般指dhq等待I/O操作完毕的方?当数据就l后在读写的时候必阻?区别qA与读写二个阶D?同步的读写必阻?,异步则指dh数据后便可以l箋(hu)处理其它d,随后{待I/O,操作完毕的通知,q可以ɘq程在数据读写时也不d?{待"通知")

1. Linux下的五种I/O模型

1)dI/OQblocking I/OQ?br style="margin: 0px; padding: 0px;" />2)非阻塞I/O Qnonblocking I/OQ?/span>
3) I/O复用(select 和poll) QI/O multiplexingQ?/span>
4)信号驱动I/O Qsignal driven I/O (SIGIO)Q?/span>
5)异步I/O Qasynchronous I/O (the POSIX aio_functions)Q?/span>

前四U都是同步,只有最后一U才是异步IO?/p>

dI/O模型Q?/span>

        介:(x)q程?/span>一直阻?/span>Q直到数据拷贝完?/span>

     应用E序调用一个IO函数Q导致应用程序阻塞,{待数据准备好?如果数据没有准备好,一直等?#8230;.数据准备好了(jin)Q从内核拯到用L(fng)?IO函数q回成功指示?/span>

dI/O模型图:(x)在调用recv()/recvfromQ)(j)函数Ӟ发生在内怸{待数据和复制数据的q程?/span>


    当调用recv()函数Ӟpȝ首先查是否有准备好的数据。如果数据没有准备好Q那么系l就处于{待状态。当数据准备好后Q将数据从系l缓冲区复制到用L(fng)_(d)然后该函数返回。在套接应用E序中,当调用recv()函数Ӟ未必用户I间已l存在数据,那么此时recv()函数׃(x)处于{待状态?br style="margin: 0px; padding: 0px;" />

     当用socket()函数和W(xu)SASocket()函数创徏套接字时Q默认的套接字都是阻塞的。这意味着当调用Windows Sockets API不能立即完成ӞU程处于{待状态,直到操作完成?/span>

    q不是所有Windows Sockets API以阻塞套接字为参数调用都?x)发生阻塞。例如,以阻塞模式的套接字ؓ(f)参数调用bind()、listen()函数Ӟ函数?x)立卌回。将可能d套接字的Windows Sockets API调用分ؓ(f)以下四种:

    1Q输入操作:(x) recv()、recvfrom()、WSARecv()和W(xu)SARecvfrom()函数。以d套接字ؓ(f)参数调用该函数接收数据。如果此时套接字~冲区内没有数据可读Q则调用U程在数据到来前一直睡眠?/span>

    2Q输出操作:(x) send()、sendto()、WSASend()和W(xu)SASendto()函数。以d套接字ؓ(f)参数调用该函数发送数据。如果套接字~冲区没有可用空_(d)U程?x)一直睡眠,直到有空间?/span>

    3Q接受连接:(x)accept()和W(xu)SAAcept()函数。以d套接字ؓ(f)参数调用该函敎ͼ{待接受Ҏ(gu)的连接请求。如果此时没有连接请求,U程׃(x)q入睡眠状态?/span>

   4Q外?gu)接?x)connect()和W(xu)SAConnect()函数。对于TCPq接Q客L(fng)以阻塞套接字为参敎ͼ调用该函数向服务器发赯接。该函数在收到服务器的应{前Q不?x)返回。这意味着TCPq接M(x){待臛_到服务器的一ơ往q时间?/span>

  使用d模式的套接字Q开发网l程序比较简单,Ҏ(gu)实现。当希望能够立即发送和接收数据Q且处理的套接字数量比较?yu)的情况下,使用d模式来开发网l程序比较合适?/span>

    d模式套接字的不表现为,在大量徏立好的套接字U程之间q行通信时比较困难。当使用“生?消费?#8221;模型开发网l程序时Qؓ(f)每个套接字都分别分配一个读U程、一个处理数据线E和一个用于同步的事gQ那么这h疑加大系l的开销。其最大的~点是当希望同时处理大量套接字时Q将无从下手Q其扩展性很?/span>

非阻塞IO模型 

       介:(x)非阻塞IO通过q程反复调用IO函数Q?/span>多次pȝ调用Qƈ马上q回Q;在数据拷贝的q程中,q程是阻塞的Q?/span>

       

       我们把一个SOCKET接口讄为非d是告诉内核Q当所h的I/O操作无法完成Ӟ不要进E睡眠,而是q回一个错误。这h们的I/O操作函数不断的试数据是否已经准备好,如果没有准备好,l箋(hu)试Q直到数据准备好为止。在q个不断试的过E中Q会(x)大量的占用CPU的时间?/span>

    ?span style="margin: 0px; padding: 0px; font-size: 14px;">SOCKET讄为非d模式Q即通知pȝ内核Q在调用Windows Sockets APIӞ不要让线E睡眠,而应该让函数立即q回。在q回Ӟ该函数返回一个错误代码。图所C,一个非d模式套接字多ơ调用recv()函数的过E。前三次调用recv()函数Ӟ内核数据q没有准备好。因此,该函数立卌回WSAEWOULDBLOCK错误代码。第四次调用recv()函数Ӟ数据已经准备好,被复制到应用E序的缓冲区中,recv()函数q回成功指示Q应用程序开始处理数据?/span>



     当用socket()函数和W(xu)SASocket()函数创徏套接字时Q默认都是阻塞的。在创徏套接字之后,通过调用ioctlsocket()函数Q将该套接字讄为非d模式。Linux下的函数?fcntl().
    套接字设|ؓ(f)非阻塞模式后Q在调用Windows Sockets API函数Ӟ调用函数?x)立卌回。大多数情况下,q些函数调用都会(x)调用“p|”Qƈq回WSAEWOULDBLOCK错误代码。说明请求的操作在调用期间内没有旉完成。通常Q应用程序需要重复调用该函数Q直到获得成功返回代码?/span>

    需要说明的是ƈ非所有的Windows Sockets API在非d模式下调用,都会(x)q回WSAEWOULDBLOCK错误。例如,以非d模式的套接字为参数调用bind()函数Ӟ׃?x)返回该错误代码。当?dng)在调用WSAStartup()函数时更不会(x)q回该错误代码,因ؓ(f)该函数是应用E序W一调用的函敎ͼ当然不会(x)q回q样的错误代码?/span>

    要将套接字设|ؓ(f)非阻塞模式,除了(jin)使用ioctlsocket()函数之外Q还可以使用WSAAsyncselect()和W(xu)SAEventselect()函数。当调用该函数时Q套接字?x)自动地讄为非d方式?br style="margin: 0px; padding: 0px;" />

  ׃使用非阻塞套接字在调用函数时Q会(x)l常q回WSAEWOULDBLOCK错误。所以在M时候,都应仔细(g)查返回代码ƈ作好?#8220;p|”的准备。应用程序连l不断地调用q个函数Q直到它q回成功指示为止。上面的E序清单中,在While循环体内不断地调用recv()函数Q以d1024个字节的数据。这U做法很费pȝ资源?/span>

    要完成这L(fng)操作Q有Z用MSG_PEEK标志调用recv()函数查看~冲Z是否有数据可诅R同Pq种Ҏ(gu)也不好。因做法对系l造成的开销是很大的Qƈ且应用程序至要调用recv()函数两次Q才能实际地d数据。较好的做法是,使用套接字的“I/O模型”来判断非d套接字是否可d写?/span>

    非阻塞模式套接字与阻塞模式套接字相比Q不Ҏ(gu)使用。用非d模式套接字,需要编写更多的代码Q以便在每个Windows Sockets API函数调用中,Ҏ(gu)到的WSAEWOULDBLOCK错误q行处理。因此,非阻塞套接字便显得有些难于用?/span>

    但是Q非d套接字在控制建立的多个连接,在数据的收发量不均,旉不定Ӟ明显h优势。这U套接字在用上存在一定难度,但只要排除了(jin)q些困难Q它在功能上q是非常强大的。通常情况下,可考虑使用套接字的“I/O模型”Q它有助于应用程序通过异步方式Q同时对一个或多个套接字的通信加以理?/span>


IO复用模型Q?/span>

             介:(x)主要是select和epollQ对一个IO端口Q两ơ调用,两次q回Q比dIOq没有什么优性;关键是能实现同时对多个IO端口q行监听Q?/span>

      I/O复用模型?x)用到select、poll、epoll函数Q这几个函数也会(x)使进E阻塞,但是和阻塞I/O所不同的的Q这两个函数可以同时d多个I/O操作。而且可以同时对多个读操作Q多个写操作的I/O函数q行(g),直到有数据可L可写Ӟ才真正调用I/O操作函数?/span>


信号驱动IO

    介:(x)两次调用Q两ơ返回;

    首先我们允许套接口进行信号驱动I/O,q安装一个信号处理函敎ͼq程l箋(hu)q行q不d。当数据准备好时Q进E会(x)收到一个SIGIO信号Q可以在信号处理函数中调用I/O操作函数处理数据?/span>


异步IO模型

         介:(x)数据拯的时候进E无需d?/span>

     当一个异步过E调用发出后Q调用者不能立d到结果。实际处理这个调用的部g在完成后Q通过状态、通知和回调来通知调用者的输入输出操作


同步IO引vq程dQ直至IO操作完成?br style="margin: 0px; padding: 0px;" />异步IO不会(x)引vq程d?br style="margin: 0px; padding: 0px;" />IO复用是先通过select调用d?br style="margin: 0px; padding: 0px;" />


5个I/O模型的比较:(x)



1. select、poll、epoll?br style="margin: 0px; padding: 0px;" />

epoll跟select都能提供多\I/O复用的解x(chng)案。在现在的Linux内核里有都能够支持,其中epoll是Linux所Ҏ(gu)Q而select则应该是POSIX所规定Q一般操作系l均有实?/p>

selectQ?/span>

select本质上是通过讄或者检查存放fd标志位的数据l构来进行下一步处理。这h带来的缺Ҏ(gu)Q?/p>

1?单个q程可监视的fd数量被限Ӟ卌监听端口的大有限?br style="margin: 0px; padding: 0px;" />

      一般来说这个数目和pȝ内存关系很大Q具体数目可以cat /proc/sys/fs/file-max察看?2位机默认?024个?4位机默认?048.

2?对socketq行扫描时是U性扫描,即采用轮询的Ҏ(gu)Q效率较低:(x)

       当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调?不管哪个Socket是活跃的,都遍历一遍。这?x)浪费很多CPU旉。如果能l套接字注册某个回调函数Q当他们z跃Ӟ自动完成相关操作Q那避免了(jin)轮询Q这正是epoll与kqueue做的?/p>

3、需要维护一个用来存攑֤量fd的数据结构,q样?x)得用L(fng)间和内核I间在传递该l构时复制开销?/p>

pollQ?/span>

poll本质上和select没有区别Q它?yu)用户传入的数组拯到内核空_(d)然后查询每个fd对应的设备状态,如果讑֤qA则在讑֤{待队列中加入一ƈl箋(hu)遍历Q如果遍历完所有fd后没有发现就l设备,则挂起当前进E,直到讑֤qA或者主动超Ӟ被唤醒后它又要再ơ遍历fd。这个过E经历了(jin)多次无谓的遍历?/p>

它没有最大连接数的限Ӟ原因是它是基于链表来存储的,但是同样有一个缺点:(x)

1、大量的fd的数l被整体复制于用h和内核地址I间之间Q而不这L(fng)复制是不是有意义?nbsp;                                                                                                                                     2、pollq有一个特Ҏ(gu)“水^触发”Q如果报告了(jin)fd后,没有被处理,那么下次poll时会(x)再次报告该fd?/p>epoll:

epoll支持水^触发和边~触发,最大的特点在于边缘触发Q它只告诉进E哪些fd刚刚变(sh)ؓ(f)需态,q且只会(x)通知一ơ。还有一个特Ҏ(gu)Qepoll使用“事g”的就l通知方式Q通过epoll_ctl注册fdQ一旦该fdqAQ内核就?x)采用类似callback的回调机制来Ȁz该fdQepoll_wait便可以收到通知

epoll的优点:(x)

1、没有最大ƈ发连接的限制Q?/span>能打开的FD的上限远大于1024Q?G的内存(sh)能监听约10万个端口Q;
2、效率提?/strong>Q不是轮询的方式Q不?x)随着FD数目的增加效率下降。只有活跃可用的FD才会(x)调用callback函数Q?br style="margin: 0px; padding: 0px;" />      即Epoll最大的优点在于它只管?#8220;z跃”的连接,而跟q接L无关Q因此在实际的网l环境中QEpoll的效率就?x)远q高?sh)select和poll?/span>
3?nbsp;内存拯Q利用mmap()文g映射内存加速与内核I间的消息传递;即epoll使用mmap减少复制开销?br style="margin: 0px; padding: 0px;" />
select、poll、epoll 区别ȝQ?/span>

1、支持一个进E所能打开的最大连接数

select

单个q程所能打开的最大连接数有FD_SETSIZE宏定义,其大是32个整数的大小Q在32位的机器上,大小是32*32Q同?4位机器上FD_SETSIZE?2*64Q,当然我们可以对进行修改,然后重新~译内核Q但是性能可能?x)受到?jing)响,q需要进一步的试?/p>

poll

poll本质上和select没有区别Q但是它没有最大连接数的限Ӟ原因是它是基于链表来存储?/p>

epoll

虽然q接数有上限Q但是很大,1G内存的机器上可以打开10万左右的q接Q?G内存的机器可以打开20万左右的q接

2、FD剧增后带来的IO效率问题

select

因ؓ(f)每次调用旉?x)对q接q行U性遍历,所以随着FD的增加会(x)造成遍历速度慢的“U性下降性能问题”?/p>

poll

同上

epoll

因ؓ(f)epoll内核中实现是Ҏ(gu)每个fd上的callback函数来实现的Q只有活跃的socket才会(x)d调用callbackQ所以在z跃socket较少的情况下Q用epoll没有前面两者的U性下降的性能问题Q但是所有socket都很z跃的情况下Q可能会(x)有性能问题?/p>

3?消息传递方?/p>

select

内核需要将消息传递到用户I间Q都需要内核拷贝动?/p>

poll

同上

epoll

epoll通过内核和用L(fng)间共享一块内存来实现的?/p>

ȝQ?/span>

lgQ在选择selectQpollQepoll时要Ҏ(gu)具体的用场合以?qing)这三种方式的自w特炏V?/p>

1、表面上看epoll的性能最好,但是在连接数ƈ且连接都十分z跃的情况下Qselect和poll的性能可能比epoll好,毕竟epoll的通知机制需要很多函数回调?/p>

2?span style="margin: 0px; padding: 0px; color: #000000; background-color: #ffcc00;">select低效是因为每ơ它都需要轮询。但低效也是相对的,视情况而定Q也可通过良好的设计改?/span>



C加 2013-03-26 13:36 发表评论
]]>
windowsSocket~程学习(fn)Q?Q:(x)面向q接的Socket~程步骤http://www.shnenglu.com/cxiaojia/archive/2012/06/04/177444.htmlC加C加Mon, 04 Jun 2012 04:24:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2012/06/04/177444.htmlhttp://www.shnenglu.com/cxiaojia/comments/177444.htmlhttp://www.shnenglu.com/cxiaojia/archive/2012/06/04/177444.html#Feedback0http://www.shnenglu.com/cxiaojia/comments/commentRss/177444.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/177444.html

面向q接?/span>Socket通信是基?/span>TCP的。网l中的两个进E以客户?/span>/服务器模式进行通信

   服务器程序要先于客户机程序启动,每个步骤中调用的
Socket函数如下Q?/span>

Q?/span>1Q调?/span>WSAStartup()函数加蝲Windows Sockets动态库Q然后调?/span>socket()函数创徏一个流式套接字Q返回套接字?/span>s?/span>

Q?/span>2Q调?/span>bind()函数套接字sl定C个已知的地址Q通常为本?/span>IP地址?/span>

Q?/span>3Q调?/span>listen()函数套接字s讄Z听模式,准备好接收来自各个客h的连接请求?/span>

Q?/span>4Q调?/span>accept()函数{待接受客户端的q接h?/span>

Q?/span>5Q如果接收到客户端的hQ则accept()函数q回Q得到新的套接字ns?/span>

Q?/span>6Q调?/span>recv()函数接收来自客户端的数据Q调?/span>send()函数向客L(fng)发送数据?/span>

Q?/span>7Q与客户端的通信l束后,服务器程序可以调?/span>shutdown()函数通知Ҏ(gu)不再发送或接收数据Q也可以由客L(fng)E序断开q接。断开q接后,服务器进E调?/span>closesocket()函数关闭套接?/span>ns。此后服务器E序q回W?/span>4步,l箋(hu){待客户端进E的q接?/span>

Q?/span>8Q如果要退出服务器E序Q则调用closesocket()函数关闭最初的套接?/span>s?/span>

客户端程序在每一步骤中用的函数如下Q?/span>

Q?/span>1Q调?/span>WSAStartup()函数加蝲Windows Sockets动态库Q然后调?/span>socket()函数创徏一个流式套接字Q返回套接字?/span>s?/span>

Q?/span>2Q调?/span>connect()函数套接字sq接到服务器?/span>

Q?/span>3Q调?/span>send()函数向服务器发送数据,调用recv()函数接收来自服务器的数据?/span>

Q?/span>4Q与服务器的通信l束后,客户端程序可以调?/span>shutdown()函数通知Ҏ(gu)不再发送或接收数据Q也可以由服务器E序断开q接。断开q接后,客户端进E调?/span>closesocket()函数关闭套接字?/span>

 



C加 2012-06-04 12:24 发表评论
]]>
windowsSocket~程学习(fn)Q?Q:(x)一个简单的SocketE序http://www.shnenglu.com/cxiaojia/archive/2012/05/21/175548.htmlC加C加Mon, 21 May 2012 01:14:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2012/05/21/175548.htmlhttp://www.shnenglu.com/cxiaojia/comments/175548.htmlhttp://www.shnenglu.com/cxiaojia/archive/2012/05/21/175548.html#Feedback1http://www.shnenglu.com/cxiaojia/comments/commentRss/175548.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/175548.html

通过一个控制台应用E序实例来演C初始化Windows Socketsq输出得到的版本信息?br />

#include<iostream>
#include<winsock2.h>//使用Winsock 2.2 版本
#pragma comment (lib,"ws2_32.lib")
#include<stdlib.h>
using namespace std;

int main()
{
    
    WSADATA wsadata;//WSADATAl构体中主要包含?jin)系l所支持的Winsock版本信息


    if( WSAStartup( MAKEWORD(2,2),&wsadata )!=0 )//初始化Winsock 2.2
    {
        cout<<"WSAStartup无法初始化!"<<endl;
        return 0;
    }
    //使用Winsock实现|络通信
    
//昄wsadata中的数据
    printf("Version: %d.%d\n",LOBYTE(wsadata.wVersion),HIBYTE(wsadata.wVersion));//注释1
    printf("High Version: %d.%d\n", LOBYTE(wsadata.wHighVersion),HIBYTE(wsadata.wHighVersion) );//注释2
    printf("Description: %s\n",wsadata.szDescription );//注释3
    printf("System Status: %s\n",wsadata.szSystemStatus );//注释4
    
//最后应该做的清理工?/span>
    if(WSACleanup()==SOCKET_ERROR)
        printf("WSACleanup出错\n");

    system("pause");

    return 0;
}



注释1Q?/p>

         字段wVersionQWindows Sockets DLL期望调用者用的Windows Sockets规范的版本,为WORDcd。高?sh)字节中存储副版本号Q地位字节中存储ȝ本号。调用LOBYTE()函数可以q回WORDcd数据的地位字节,从而获取主版本P调用HIBYTE()函数可以q回WORDcd数据的高?sh)字节,从而获取副版本受?/p>

注释2Q?/p>

字段wHighVersionQWindows Sockets DLL 可以支持的Windows Sockets 规范的最高版本?/p>

注释3Q?/p>

         字段szDescriptionQ以nulll尾的ASCLL字符丌ӀWindows Sockets DLL对Windows Sockets实现的描q复制到该字W串中,最多可以包?56个字W?/p>

注释4Q?/p>

         字段szSystemStatusQ以nulll尾的ASCLL字符ԌW(xu)indows Sockets DLL有关状态或配置信息复制到该字符串中?/p>

 

其他字段?qing)其含义Q?/p>

         字段iMaxSocketsQ单个进E可以打开的最大Socket数量。Windows Sockets可以提供一个全局的SocketQؓ(f)每个q程分配Socket资源。程序员可以使用该数字作为Windows Sockets是否可以被应用程序用的原始依据?/p>

         字段iMaxUdpDgQWindows Sockets应用E序能够发送或接受的最大UDP数据包大,单位为字节。如果实现方式没有限Ӟ则iMaxUdpDg{于0?/p>

         字段lpVendorInfoQ指向销售商数据l构的指针?/p>






C加 2012-05-21 09:14 发表评论
]]>
windowsSocket~程学习(fn)Q?Q:(x)Socket介和应用E序框架http://www.shnenglu.com/cxiaojia/archive/2012/05/20/175432.htmlC加C加Sun, 20 May 2012 02:17:00 GMThttp://www.shnenglu.com/cxiaojia/archive/2012/05/20/175432.htmlhttp://www.shnenglu.com/cxiaojia/comments/175432.htmlhttp://www.shnenglu.com/cxiaojia/archive/2012/05/20/175432.html#Feedback2http://www.shnenglu.com/cxiaojia/comments/commentRss/175432.htmlhttp://www.shnenglu.com/cxiaojia/services/trackbacks/175432.html

一?/span>Socket单介l?/span>

Socket的中文翻译是套接字,它是TCP/IP|络环境下应用程序与底层通信驱动E序之间q行的开发接口,它可以将应用E序与具体的TCP/IP隔离开来,使得应用E序不需要了(jin)?/span>TCP/IP的具体细节,p够实现数据传输?/span>

关于Socket需要了(jin)解的q有很多Q我在随后的章节里陆箋(hu)写上?/span>

二?/span>Socket应用E序框架

      q里先声明一下,我用的是32?/span>win7pȝQ?/span>vs2010~译器?/span>

首先新徏一个没有预~译头的Win32控制台应用程序?/span>

应用E序框架如下Q?br />

#include<iostream>
#include<winsock2.h>//注释1
#pragma comment (lib,"ws2_32.lib")//注释1
#include<stdlib.h>
using namespace std;

int main()
{
    
    WSADATA wsadata;//注释2


    if( WSAStartup( MAKEWORD(2,2),&wsadata )!=0 )//注释3
    {
        printf("WSAStartup无法初始化!\n");
        return 0;
    }
    //使用Winsock实现|络通信
    
//
    
//最后应该做的清理工?/span>
    if(WSACleanup()==SOCKET_ERROR)//注释4
        printf("WSACleanup出错\n");

    system("pause");

    return 0;
}

注释1Q?/p>

我们在vs中一般用Winsock2实现|络通信功能Q需要引q头文gwinsock2.h和库文gws2_32.lib?/p>

注释2Q?/p>

WSADATAl构体中主要包含?jin)系l所支持的Winsock版本信息?/p>

注释3“

         WSAStartup()函数用于初始化Windows SocketsQƈq回WSADATAl构体。只有调用WSAStartup()函数后,应用E序才能调用其他Windows Sockets API函数Q实现网l通信?/p>

         W一个参数是版本PW二个参数用于接收版本信息?/p>

         如果函数执行成功则会(x)q回0?/p>

注释4Q?/p>

         最后应该做的一些清理工作?/p>



 



C加 2012-05-20 10:17 发表评论
]]>
ƷþþþóѶ| þþþþþòҰ¸߳| þþƷһ| AVþþƷ| þӰۺ| þþƷŷպþ| þŷձƷ| þۺϹ׾Ʒ| רþ| 99ȳ˾ƷѾþ| ˾þô߽ӰԺ95| þùƷ99Ʒ| 97þۺϾƷþþۺ| 99þ99ֻѷѾƷ| 99þۺϺݺۺϾþֹ| 99þþƷëƬѲ| ھƷþþþþþӰ鶹| þ۲ӰԺѿҹɫ| Ļþи| þþþAVƬ| 99þþƷһ | þþƷav| ޹һɾþþƷۺ| þ99Ʒ鶹| þseƷһӰԺ| Ʒþþþþþ| þþƷһӰ| ޾Ʒþþþþ| ݺۺϾþAVһ| þùƵ99Ӱ| Ʒպþ| 99þ99ֻѷѾƷ| ˹ھƷþþþӰԺVR| þ99þ99Ʒӿ| ѹۿþþƵ| Ļav鲻þ| ޾Ʒþþþsm| ƷþþþùA| þ91ᆱƷ2020| AëƬþþƷ| պһþþþþ|