向你请教一个疑问.
在发送32 个字节正常.( 这里好奇怪,字节数多一点也正常..现在就是40个不正常.)我用IOCP出现这样的情况:
C 端发送40 个字节.
S 端的
GetQueuedCompletionStatus(pThis->m_hIocp,&lenght,&key, (OVERLAPPED **) &pov,INFINITE);这个lenght值是32.
要投递一个读操作( 可以读出来后面的8个字节.)
if(ov.dwTotol>lenght)
{//在第一次没有读被完的情况...这时的读才真正的生效,,
  PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-lenght, 0, (OVERLAPPED *)&ov);
//或  WSARecv( ov.skt, &ov.wbuf, /* number of WSABUFs */ 1,&  ov.dwLenght, &ov.recvFlags, &ov, /* completion routine address */ 0 );   把后8 个字节读完.
return false;
}
接收数据正常.
但下次C端再发送数据.
GetQueuedCompletionStatus 还在阻塞着.
不能调度.
用TCPVIEW 监视. 端口 是 ESTABLISHED 状态.
有什么办法可以让 S 端 一次投递完成接收.
或者二次接收之后.
下次 数据到来能正常投递?逢UP给分....可以开贴再给... int COICPServer::InitServer( UINT nPort )
{
HL thread; // vector of thread handles
HLI hli; // iterator into that vector
OICPOL ovl; // linked list of OVERLAPPED derivates
OICPOLI ovi; // iterator into that list
HANDLE h; // temporary thread handle
int i;
unsigned int dummy;
m_hsuicideEvent = CreateEvent( 0, TRUE, FALSE, 0 );
m_hEvenWaitingSocketClose=CreateEvent(NULL,TRUE,FALSE,0);
m_hIocp = CreateIoCompletionPort( INVALID_HANDLE_VALUE, 0, 0, 0 );
VERIFY(m_hIocp);
// create threads
SYSTEM_INFO si={ 0 };
GetSystemInfo(&si);
si.dwNumberOfProcessors=1;
for ( i = 0; i  < (int)si.dwNumberOfProcessors; ++ i )
{
h = (HANDLE) _beginthreadex( 0, 0, s_Worker, this, 0, &dummy );
if ( VALID( h ) )
thread.push_back(h);
}WSADATA wd = { 0 };
LRESULT e;
e = WSAStartup( MAKEWORD( 2, 2 ), &wd );
// create listen socket
SOCKADDR_IN addr;
m_slistener = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED );
HANDLE hListen=CreateIoCompletionPort( (HANDLE) m_slistener, m_hIocp, 0, 0 );
if(hListen==NULL)
{
ASSERT(FALSE);
return FALSE;
}addr.sin_family = AF_INET;
addr.sin_addr.s_addr = INADDR_ANY;
addr.sin_port = htons( (short) nPort );
VERIFY(bind( m_slistener, (SOCKADDR *) &addr, sizeof SOCKADDR )==ERROR_SUCCESS) ;
VERIFY(listen( m_slistener, 20 )==ERROR_SUCCESS);
// wait until end indicated
// kick socket scavenger loose
for ( i = 0; i  < MAX_CLIENT_SOCK; ++ i )
{
OV *o = new OV;
o->state = stAccepting;
o->sktbuf=new char [MAX_RECV_BUF+2*IPADDRLENGHT];
ReinitContext( *o );
if ( o->skt != INVALID_SOCKET )
ovl.push_back( o );
}WaitForSingleObject( m_hsuicideEvent, INFINITE );
closesocket( m_slistener );
m_slistener = INVALID_SOCKET;
// 关闭的.不贴代码了.
return LRESULT();
}
void COICPServer::ReinitContext(OV &ov)
{
int zero = 0;
if(ov.skt!=SOCKET_ERROR)
closesocket(ov.skt);
ov.skt = WSASocket( AF_INET, SOCK_STREAM, IPPROTO_TCP,NULL,0,WSA_FLAG_OVERLAPPED);
if ( ov.skt != INVALID_SOCKET )
{
ov.state = stAccepting;
setsockopt( ov.skt, SOL_SOCKET, SO_SNDBUF, (char *) &zero, sizeof zero );
setsockopt( ov.skt, SOL_SOCKET, SO_RCVBUF, (char *) &zero, sizeof zero );
if(ov.sktbuf!=NULL)
memset( ov.sktbuf, '\0', MAX_RECV_BUF );
if(!AcceptEx( m_slistener, ov.skt, ov.sktbuf,MAX_LISTEN_BUF_SIZE, IPADDRLENGHT,IPADDRLENGHT, &ov.dwLenght, &ov ))
{
int n=IPADDRLENGHT;
LRESULT lErrcode=WSAGetLastError();
if(lErrcode!=ERROR_IO_PENDING)
{
ASSERT(FALSE);
}
}
}
}void COICPServer::DoClose( OV& ov, bool clientforceClose/*=FALSE*/, bool listenAgain/*=TRUE*/ )
{
struct linger li = { 0, 0 }; 
if ( clientforceClose )
{
li.l_onoff = 1;
}
ASSERT(ov.skt!=NULL);
setsockopt( ov.skt, SOL_SOCKET, SO_LINGER, (char *) &li, sizeof li );
closesocket( ov.skt );
ov.skt=SOCKET_ERROR;
if ( listenAgain )
ReinitContext( ov );
}
BOOL COICPServer::PostRead( OV &ov,DWORD dwReadLenght/*=MAX_RECV_BUF*/,BOOL fForceRead )
{
long result,errcoe;
errcoe=WSAGetLastError();
if(ov.state==stReadBegin)
{
LPNETCLIENT pNccLogo=(LPNETCLIENT)ov.sktbuf;
ov.dwAlreadyOp=0;
if(pNccLogo->szHead[0]!='B'  ¦ ¦ pNccLogo->szHead[1]!='J')
return FALSE;
ov.dwTotol=pNccLogo->lenght;
TRACE("----------------- time_off=%08x recv lenght=%d  SOCKET %08x headflag %c%c---------------\n",pNccLogo->nTimerSycn,pNccLogo->lenght,ov.skt,pNccLogo->szHead[0],pNccLogo->szHead[1]);
}
ov.dwAlreadyOp+=dwReadLenght;
ov.recvFlags=0;
ov.state=stReading; 
ov.dwLenght=0;
ov.wbuf.len=ov.dwTotol;//-ov.dwAlreadyOp-dwReadLenght;
ov.wbuf.buf=ov.sktbuf;//+ov.dwAlreadyOp+dwReadLenght;
if(ov.dwTotol>dwReadLenght && ov.dwAlreadyOp!=ov.dwTotol)
{//在第一次没有读被完的情况..
PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
return FALSE;
}
result = WSARecv( ov.skt, &ov.wbuf, /* number of WSABUFs */ 1,&ov.dwLenght, &ov.recvFlags, &ov, /* completion routine address */ 0 );
ov.dwAlreadyOp+=ov.dwLenght;
if(ov.dwLenght!=0)
{
TRACE("---------读取多少字节-------- recv lenght=%d---------------\n",ov.dwLenght);
return FALSE;
}
if ( result==SOCKET_ERROR )
{//WSAENOBUFS
errcoe=WSAGetLastError();
if(errcoe!=WSA_IO_PENDING)
{
DoClose( ov, true );
return FALSE;
}
}
if(dwReadLenght+ov.dwAlreadyOp>= ov.dwTotol)
{
ParseWorker(ov);
}
return FALSE;}
UINT __stdcall COICPServer::s_Worker( void * arg )
{
DWORD n;
ULONG key;
BOOL result;
OV *pov;
COICPServer *pThis=(COICPServer*) arg;
InterlockedIncrement( &pThis->m_lrunningThreads );
for ( ; ; )
{
InterlockedDecrement( &pThis->m_lrunningThreads );
result = GetQueuedCompletionStatus(pThis->m_hIocp,&n,&key, (OVERLAPPED **) &pov,INFINITE);
InterlockedIncrement( &pThis->m_lrunningThreads );
if ( result == FALSE  ) // something gone awry?
{
DWORD dwIOError = GetLastError();
if(WAIT_TIMEOUT!=dwIOError && 0x000003e3 != dwIOError)
{
pThis->DoClose( *pov, true, pThis->m_slistener == INVALID_SOCKET? false: true );
}
}
else if(pov!=NULL) // GQCS() returned TRUE
{
int locallen, remotelen;
sockaddr_in *plocal = 0, *premote = 0;
char  bValue;
// what was that socket doing, anyway?
UINT lerrcode=0;
switch (pov->state)
{
case stAccepting:
GetAcceptExSockaddrs( pov->sktbuf, MAX_LISTEN_BUF_SIZE,IPADDRLENGHT,IPADDRLENGHT, (sockaddr **) &plocal, &locallen,(sockaddr **) &premote, &remotelen );
memcpy( &pov->peer, premote, sizeof sockaddr_in );
setsockopt( pov->skt, SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,(char *) &pThis->m_slistener, sizeof SOCKET );
// we still need to associate the newly connected socket to our IOCP:
CreateIoCompletionPort( (HANDLE) pov->skt, pThis->m_hIocp, 0, 0);
lerrcode=setsockopt(pov->skt,IPPROTO_TCP,TCP_NODELAY,&bValue,sizeof(char)); // add by Auly
pov->state=stReadBegin;
pThis->PostRead(*pov,n);
break; // nothing read yet, don't attempt to buffer it
case stReadBegin:
pThis->PostRead(*pov,n);
break;
case stReading:
//pov->dwAlreadyOp+=n;
if(pov->dwTotol <=pov->dwAlreadyOp+n)
pThis->ParseWorker(*pov);
else
pThis->PostRead(*pov,n);
break;
case stWriting:
pov->dwAlreadyOp+=n;
if(pov->dwTotol>pov->dwAlreadyOp)
pThis->PostWrite(*pov);
else
pov->state=stReadBegin;
break;
case stReadCompleted:
ASSERT(FALSE);
pov->state=stReading;
break;
}
}
}
InterlockedDecrement( &pThis->m_lrunningThreads );
TRACE("s_Worker end\n");
return 0;
}BOOL COICPServer::PostWrite(OV& ov)
{
ov.state=stWriting;
ov.wbuf.buf+=ov.dwAlreadyOp;
ov.wbuf.len-=ov.dwAlreadyOp;
memset(ov.sktbuf,0,ov.wbuf.len);
LRESULT lErrcode=WSASend(ov.skt,&ov.wbuf,1,&ov.dwLenght,/*flag*/0,&ov,NULL);
if ( lErrcode==SOCKET_ERROR &&  WSAGetLastError() != WSA_IO_PENDING)
{
DoClose( ov, true );
return FALSE;
}
TRACE("PostWrite()--------------------lenght %d\n",ov.dwLenght);
ov.dwLenght=0;
return TRUE;

解决方案 »

  1.   

    服务器端接受请求的代码似乎有些问题,通常的做法是将AcceptEx返回的Socket和Complete IO关联,而且你创建的线程数据和处理器一样,这样就可能发生线程阻塞。Client的代码没仔细看.
      

  2.   

     //   Module   Name:   iocmplt.cpp   
      //   
      //   Description:   
      //   
      //         This   sample   illustrates   how   to   develop   a   simple   echo   server   Winsock   
      //         application   using   the   completeion   port   I/O   model.   This     
      //         sample   is   implemented   as   a   console-style   application   and   simply   prints   
      //         messages   when   connections   are   established   and   removed   from   the   server.   
      //         The   application   listens   for   TCP   connections   on   port   5150   and   accepts   them   
      //         as   they   arrive.   When   this   application   receives   data   from   a   client,   it   
      //         simply   echos   (this   is   why   we   call   it   an   echo   server)   the   data   back   in   
      //         it's   original   form   until   the   client   closes   the   connection.   
      //   
      //   Compile:   
      //   
      //         cl   -o   iocmplt   iocmplt.cpp   ws2_32.lib   
      //   
      //   Command   Line   Options:   
      //   
      //         iocmplt.exe     
      //   
      //         Note:   There   are   no   command   line   options   for   this   sample.   
        
      #include   <winsock2.h>   
      #include   <windows.h>   
      #include   <stdio.h>   
        
      #define   PORT   5150   
      #define   DATA_BUFSIZE   8192   
        
      typedef   struct   
      {   
            OVERLAPPED   Overlapped;   
            WSABUF   DataBuf;   
            CHAR   Buffer[DATA_BUFSIZE];   
            DWORD   BytesSEND;   
            DWORD   BytesRECV;   
      }   PER_IO_OPERATION_DATA,   *   LPPER_IO_OPERATION_DATA;   
        
        
      typedef   struct     
      {   
            SOCKET   Socket;   
      }   PER_HANDLE_DATA,   *   LPPER_HANDLE_DATA;   
        
        
      DWORD   WINAPI   ServerWorkerThread(LPVOID   CompletionPortID);   
        
      void   main(void)   
      {   
            SOCKADDR_IN   InternetAddr;   
            SOCKET   Listen;   
            SOCKET   Accept;   
            HANDLE   CompletionPort;   
            SYSTEM_INFO   SystemInfo;   
            LPPER_HANDLE_DATA   PerHandleData;   
            LPPER_IO_OPERATION_DATA   PerIoData;   
            int   i;   
            DWORD   RecvBytes;   
            DWORD   Flags;   
            DWORD   ThreadID;   
            WSADATA   wsaData;   
            DWORD   Ret;   
        
            if   ((Ret   =   WSAStartup(0x0202,   &wsaData))   !=   0)   
            {   
                  printf("WSAStartup   failed   with   error   %d\n",   Ret);   
                  return;   
            }   
        
            //   Setup   an   I/O   completion   port.   
        
            if   ((CompletionPort   =   CreateIoCompletionPort(INVALID_HANDLE_VALUE,   NULL,   0,   0))   ==   NULL)   
            {   
                  printf(   "CreateIoCompletionPort   failed   with   error:   %d\n",   GetLastError());   
                  return;   
            }   
        
            //   Determine   how   many   processors   are   on   the   system.   
        
            GetSystemInfo(&SystemInfo);   
        
            //   Create   worker   threads   based   on   the   number   of   processors   available   on   the   
            //   system.   Create   two   worker   threads   for   each   processor.   
        
            for(i   =   0;   i   <   SystemInfo.dwNumberOfProcessors   *   2;   i++)   
            {   
                  HANDLE   ThreadHandle;   
        
                  //   Create   a   server   worker   thread   and   pass   the   completion   port   to   the   thread.   
        
                  if   ((ThreadHandle   =   CreateThread(NULL,   0,   ServerWorkerThread,   CompletionPort,   
                        0,   &ThreadID))   ==   NULL)   
                  {   
                        printf("CreateThread()   failed   with   error   %d\n",   GetLastError());   
                        return;   
                  }   
        
                  //   Close   the   thread   handle   
                  CloseHandle(ThreadHandle);   
            }   
        
            //   Create   a   listening   socket   
        
            if   ((Listen   =   WSASocket(AF_INET,   SOCK_STREAM,   0,   NULL,   0,   
                  WSA_FLAG_OVERLAPPED))   ==   INVALID_SOCKET)   
            {   
                  printf("WSASocket()   failed   with   error   %d\n",   WSAGetLastError());   
                  return;   
            }     
        
            InternetAddr.sin_family   =   AF_INET;   
            InternetAddr.sin_addr.s_addr   =   htonl(INADDR_ANY);   
            InternetAddr.sin_port   =   htons(PORT);   
        
            if   (bind(Listen,   (PSOCKADDR)   &InternetAddr,   sizeof(InternetAddr))   ==   SOCKET_ERROR)   
            {   
                  printf("bind()   failed   with   error   %d\n",   WSAGetLastError());   
                  return;   
            }   
        
            //   Prepare   socket   for   listening   
        
            if   (listen(Listen,   5)   ==   SOCKET_ERROR)   
            {   
                  printf("listen()   failed   with   error   %d\n",   WSAGetLastError());   
                  return;   
            }   
      

  3.   

    //   Accept   connections   and   assign   to   the   completion   port.   
        
            while(TRUE)   
            {   
                  if   ((Accept   =   WSAAccept(Listen,   NULL,   NULL,   NULL,   0))   ==   SOCKET_ERROR)   
                  {   
                        printf("WSAAccept()   failed   with   error   %d\n",   WSAGetLastError());   
                        return;   
                  }   
        
                  //   Create   a   socket   information   structure   to   associate   with   the   socket   
                  if   ((PerHandleData   =   (LPPER_HANDLE_DATA)   GlobalAlloc(GPTR,     
                        sizeof(PER_HANDLE_DATA)))   ==   NULL)   
                  {   
                        printf("GlobalAlloc()   failed   with   error   %d\n",   GetLastError());   
                        return;   
                  }   
        
                  //   Associate   the   accepted   socket   with   the   original   completion   port.   
        
                  printf("Socket   number   %d   connected\n",   Accept);   
                  PerHandleData->Socket   =   Accept;   
        
                  if   (CreateIoCompletionPort((HANDLE)   Accept,   CompletionPort,   (DWORD)   PerHandleData,   
                        0)   ==   NULL)   
                  {   
                        printf("CreateIoCompletionPort   failed   with   error   %d\n",   GetLastError());   
                        return;   
                  }   
        
                  //   Create   per   I/O   socket   information   structure   to   associate   with   the     
                  //   WSARecv   call   below.   
        
                  if   ((PerIoData   =   (LPPER_IO_OPERATION_DATA)   GlobalAlloc(GPTR,                     sizeof(PER_IO_OPERATION_DATA)))   ==   NULL)   
                  {   
                        printf("GlobalAlloc()   failed   with   error   %d\n",   GetLastError());   
                        return;   
                  }   
        
                  ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));   
                  PerIoData->BytesSEND   =   0;   
                  PerIoData->BytesRECV   =   0;   
                  PerIoData->DataBuf.len   =   DATA_BUFSIZE;   
                  PerIoData->DataBuf.buf   =   PerIoData->Buffer;   
        
                  Flags   =   0;   
                  if   (WSARecv(Accept,   &(PerIoData->DataBuf),   1,   &RecvBytes,   &Flags,   
                        &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)   
                  {   
                        if   (WSAGetLastError()   !=   ERROR_IO_PENDING)   
                        {   
                              printf("WSARecv()   failed   with   error   %d\n",   WSAGetLastError());   
                              return;   
                        }   
                  }   
            }   
      }   
        
      DWORD   WINAPI   ServerWorkerThread(LPVOID   CompletionPortID)   
      {   
            HANDLE   CompletionPort   =   (HANDLE)   CompletionPortID;   
            DWORD   BytesTransferred;   
            LPOVERLAPPED   Overlapped;   
            LPPER_HANDLE_DATA   PerHandleData;   
            LPPER_IO_OPERATION_DATA   PerIoData;   
            DWORD   SendBytes,   RecvBytes;   
            DWORD   Flags;   
              
            while(TRUE)   
            {   
        
                  if   (GetQueuedCompletionStatus(CompletionPort,   &BytesTransferred,   
                        (LPDWORD)&PerHandleData,   (LPOVERLAPPED   *)   &PerIoData,   INFINITE)   ==   0)   
                  {   
                        printf("GetQueuedCompletionStatus   failed   with   error   %d\n",   GetLastError());   
                        return   0;   
                  }   
        
        
                  //   First   check   to   see   if   an   error   has   occured   on   the   socket   and   if   so   
                  //   then   close   the   socket   and   cleanup   the   SOCKET_INFORMATION   structure   
                  //   associated   with   the   socket.   
        
                  if   (BytesTransferred   ==   0)   
                  {   
                        printf("Closing   socket   %d\n",   PerHandleData->Socket);   
        
                        if   (closesocket(PerHandleData->Socket)   ==   SOCKET_ERROR)   
                        {   
                              printf("closesocket()   failed   with   error   %d\n",   WSAGetLastError());   
                              return   0;   
                        }   
        
                        GlobalFree(PerHandleData);   
                        GlobalFree(PerIoData);   
                        continue;   
                  }   
        
                  //   Check   to   see   if   the   BytesRECV   field   equals   zero.   If   this   is   so,   then   
                  //   this   means   a   WSARecv   call   just   completed   so   update   the   BytesRECV   field   
                  //   with   the   BytesTransferred   value   from   the   completed   WSARecv()   call.   
        
                  if   (PerIoData->BytesRECV   ==   0)   
                  {   
                        PerIoData->BytesRECV   =   BytesTransferred;   
                        PerIoData->BytesSEND   =   0;   
                  }   
                  else   
                  {   
                        PerIoData->BytesSEND   +=   BytesTransferred;   
                  }   
        
                  if   (PerIoData->BytesRECV   >   PerIoData->BytesSEND)   
                  {   
        
                        //   Post   another   WSASend()   request.   
                        //   Since   WSASend()   is   not   gauranteed   to   send   all   of   the   bytes   requested,   
                        //   continue   posting   WSASend()   calls   until   all   received   bytes   are   sent.   
        
                        ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));   
        
                        PerIoData->DataBuf.buf   =   PerIoData->Buffer   +   PerIoData->BytesSEND;   
                        PerIoData->DataBuf.len   =   PerIoData->BytesRECV   -   PerIoData->BytesSEND;   
        
                        if   (WSASend(PerHandleData->Socket,   &(PerIoData->DataBuf),   1,   &SendBytes,   0,   
                              &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)   
                        {   
                              if   (WSAGetLastError()   !=   ERROR_IO_PENDING)   
                              {   
                                    printf("WSASend()   failed   with   error   %d\n",   WSAGetLastError());   
                                    return   0;   
                              }   
                        }   
                  }   
                  else   
                  {   
                        PerIoData->BytesRECV   =   0;   
        
                        //   Now   that   there   are   no   more   bytes   to   send   post   another   WSARecv()   request.   
        
                        Flags   =   0;   
                        ZeroMemory(&(PerIoData->Overlapped),   sizeof(OVERLAPPED));   
        
                        PerIoData->DataBuf.len   =   DATA_BUFSIZE;   
                        PerIoData->DataBuf.buf   =   PerIoData->Buffer;   
        
                        if   (WSARecv(PerHandleData->Socket,   &(PerIoData->DataBuf),   1,   &RecvBytes,   &Flags,   
                              &(PerIoData->Overlapped),   NULL)   ==   SOCKET_ERROR)   
                        {   
                              if   (WSAGetLastError()   !=   ERROR_IO_PENDING)   
                              {   
                                    printf("WSARecv()   failed   with   error   %d\n",   WSAGetLastError());   
                                    return   0;   
                              }   
                        }   
                  }   
            }   
      }
      

  4.   

    http://topic.csdn.net/u/20080427/16/9aadc7dc-141c-4ac7-83b3-446dec5c8620.html看看这个是否对你有所帮助先去办点事请 回来认真看一下你的帖子
      

  5.   

    to laiyiling :
    这个代码是微软官方的IOCP代码 在实际的项目中 我想并没有实际的意义期待laiyiling 兄发表一下您真实项目中的感受 让大家学习一下 谢谢
      

  6.   


    在 PostRead()函数中, 下面这段代码是有问题的.if(ov.dwTotol>dwReadLenght && ov.dwAlreadyOp!=ov.dwTotol)
    {//在第一次没有读被完的情况..
    PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
    return FALSE;
    }其问题在于:
    1.它是错的.用PostQueuedCompletionStatus并不能提交给内核一个读操作,它只是发了一个消息到IOCP队列中.
    2.它是多余的.如果第1次没读玩,第2次也不一定就完成.一个packet可能被拆分成很多分.
     不要幻想可以将某packet一次读完,它不受应用程序控制.
     删掉这段,基本就可以了.
      

  7.   

    囧,贴代码失败,再试在 PostRead()函数中, 下面这段代码是有问题的.if(ov.dwTotol>dwReadLenght && ov.dwAlreadyOp!=ov.dwTotol)
    {//在第一次没有读被完的情况..
    PostQueuedCompletionStatus( m_hIocp, ov.dwTotol-dwReadLenght, 0, (OVERLAPPED *) &ov );
    return FALSE;
    }其问题在于:
    1.它是错的.用PostQueuedCompletionStatus并不能提交给内核一个读操作,它只是发了一个消息到IOCP队列中.
    2.它是多余的.如果第1次没读玩,第2次也不一定就完成.一个packet可能被拆分成很多分.
     不要幻想可以将某packet一次读完,它不受应用程序控制.
     删掉这段,基本就可以了.