SERVER用完成端口
CLIENT用WSAAsyncSelect在Client,如下发送:
//My send function
BOOL MySend( INT tableno, MESSAGEKIND msgkind, CHAR *data )
{
int nret;
DATATRANSFERRED datatransfered;

datatransfered.tableno = tableno;
datatransfered.msgkind = msgkind;
strcpy( datatransfered.data, data );

//nret = send( clientsocket, (CHAR*)&datatransfered, sizeof(DATATRANSFERRED), 0 );
nret = send( clientsocket, (CHAR*)&datatransfered, 
sizeof(INT)+strlen(datatransfered.data)+sizeof(MESSAGEKIND), 0 );
if( SOCKET_ERROR==nret )
{
MsgTip( "Send data failed!" );
return FALSE;
}

return TRUE;
}在SERVER如下接收:
//SERVER ---- My send function
BOOL MyRecv( LPPER_IO_OPERATION_DATA periodata, LPPER_HANDLE_DATA perhandledata )
{
DWORD recvbytes;
DWORD flags;

flags = 0;
ZeroMemory(&(periodata->overlapped), sizeof(OVERLAPPED));

//Clean the buffer
ZeroMemory( periodata->buffer, strlen(periodata->buffer) );

periodata->databuf.len = DATA_BUFSIZE;
periodata->databuf.buf = periodata->buffer;

if (WSARecv(perhandledata->persocket, &(periodata->databuf), 1, &recvbytes, &flags,
&(periodata->overlapped), NULL) == SOCKET_ERROR)
{
if (WSAGetLastError() != ERROR_IO_PENDING)
{
printf("WSARecv() failed with error %d\n", WSAGetLastError());
return FALSE;
}
} return TRUE;
}这样能正确收到 结构体数据
但反过来就不行了
问题好像出在对传输数据的赋值:
//clean the buffer
ZeroMemory( datasend, strlen(datasend) );
sprintf( datasend, "%d", i );
datatransferred.tableno = -1; //this field is ignored
datatransferred.msgkind = CONNECT;
strcpy( datatransferred.data, datasend );//以下是想强制转换地址,但用几种方法都不行,得到的periodata->buffer的值是"YYYY" ?????
//strcpy( periodata->buffer, (CHAR*)&datatransferred );
memmove( (void*)periodata->buffer, (void*)(CHAR*)&datatransferred, 
sizeof(INT)+sizeof(MESSAGEKIND)+strlen(datatransferred.data) );

MySend( periodata, perhandledata ); -------------------------------------------------------------------
请教怎么正确地从SERVER发送结构体到CLIENT端?

解决方案 »

  1.   

    首先把结构体当做普通的一段连续的流数据(对于使用于指针的须进行特殊处理),最好考虑数据对齐,在无法实现自动对齐的情况下应该当使用pack来强制对齐.尽可能不要在结构体当中使用指针.
      

  2.   

    数据的传输传输的是结构体流化以后的数据。而不是结构体的指针,所以你一定要先流化数据,然后在传输数据,结构在定义的时候,最好用PACK来强制对齐数据。
      

  3.   

    能不能具体点啊怎么流化?
    什么是pack?
      

  4.   

    一、对于字节对齐,以及pack的作用,建议看一本书《代码优化:有效使用内存》(电骡eMule上有下)二、所谓流化就是将(在内存当中可能连续也可能不连续存在的)数据放到连续的内存空间当中去。好比一个工厂,有多个车间(由于车间人数不定,所以使用指针)和多个办公室(人员确定,所以使用元数据):struct OFFICE{
    MANAGER manager;    //经理
    ASSISTANT assistant;//助理
    SECRETARY secretary;//秘书
    };
    struct WORKSHOP{
    int membership;     //人员数量
    MEMBER *member;     //人员
    };
    struct TEAM{
       OFFICE office;    //office
       WORKSHOP workshop;//车间
    };假设要让一个Team集合,则如果直接排下
    TEAM{
       OFFICE{
          manager;    //经理
          assistant;//助理
          secretary;//秘书
       }
       WORKSHOP{
          [membership=10;] //人员数量10,但不是实体
          [member;]        //人员(注意,这里面只说明是哪个车间,而并没有明确到个人实体)
       }
    }这将导致一清点人员时,就只有三个人到岗,即经理、助理、秘书,而车间只是挂了个排,说是有多少人,哪个车间,实际上一个人都没有到,如果要这样子调集到另外一个工场去作业,那么...所以这个时候就需要具体到人,并且一一排列下去,从而使得不再是挂个牌虚张声势的团队:
    TEAM{
       OFFICE{
          manager;    //经理
          assistant;//助理
          secretary;//秘书
       }
       WORKSHOP{
          member(01);
          member(02);
          member(03);
          member(04);
          member(05);
          member(06);
          member(07);
          member(08);
          member(09);
          member(10);
       }
    }这个时候才是一个由13人组成的完整团队。这样子说好象有那么点太过抽象^_^
      

  5.   

    关于字节对齐,可以在程序中嵌入#pragma 命令:
    1.#pragma pack(push) //保存以前的对齐状态
    2.#pragma pack(4)    //以4字节对齐
    3. 1与2可以合并,写作 #pragma pack(push,4)
    4. #pragma pack(pop) //pop可以省略在网络传输中:
           #pragma pack(push,1)  //一般加在相关代码前
           ......//代码
           #pragma pack()
      

  6.   

    为方便数据的交流,在非必要的情况下建议不要使用pack,而尽可能做到对齐,以省去如VB(VB6及以下版本)不支持pack的语言进行数据操作的不必要麻烦
      

  7.   

    跟对齐有关么
    加上了#pragma pack还是没变化
      

  8.   

    楼主的关键问题不应该是在数据对齐上面,再说从上面所贴出来的代码当中(后面的代码有点乱乱的感觉^_^,确切地说没能看得懂),由于没有明确结构如何定义,所以不能确定是否对齐问题,这是其一.其二是从server端发送到client端的代码,很抱歉我实在没能看得懂.
    前面的代码弄了半天,然后来一个MySend( periodata, perhandledata );前面赋值并没有perhandledata,并且也不知道MySend的写法如何.其实比较简单点,那么发送和接收就按照上面可用的代码去写(当然IOCP和select写法上面有点点差别,不过这里面没有体现IOCP的代码,所以不好妄加评论^_^).另外最最需要注意的问题就是每次收到数据后,须判断是否一整完整的结构体(多了可以少读,少了就不行,应该再加以等待).
      

  9.   

    结构体的结构比较简单,所以没把它帖出来
    源码比较长,所以也没全帖下面是结构体:
    //Message kind enum structure ( the same as the client )
    typedef enum { CONNECT, START, WINNER }MESSAGEKIND;
    //Data structure transferred ( the same as the client )
    typedef struct 
    {
    INT tableno;
    MESSAGEKIND msgkind;
    CHAR data[DATA_BUFSIZE];
    }DATATRANSFERRED;下面是main函数中循环接收的代码:
    while(TRUE)
    {
    if ((acceptsocket = WSAAccept(listensocket, NULL, NULL, NULL, 0)) == SOCKET_ERROR)
    {
    printf("WSAacceptsocket() 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 acceptsocketed socket with the original completion port.

    printf("Socket number %d connected\n", acceptsocket);
    perhandledata->persocket = acceptsocket;

    if (CreateIoCompletionPort((HANDLE) acceptsocket, 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; //fill the g_everyclien array
    for( i=0; i<MAX_CLIENT_NUM; i++ )
    {
    if( 0==g_everyclient[i].bused )
    {
    g_everyclient[i].bused = 1;
    g_everyclient[i].perhandledata = perhandledata;
    g_everyclient[i].periodata = periodata;
    g_everyclient[i].clientstate = CONNECTSTATE; break;
    }
    }
    if( MAX_CLIENT_NUM==i )
    {
    printf( "the server has reached the maximum connection!" );
    return;
    }
    //
    printf( "insert index = %d\n", i ); //After a connection, a affirmance need be sent to the client
    //clean the buffer ZeroMemory( datasend, strlen(datasend) );
    sprintf( datasend, "%d", i );
    datatransferred.tableno = -1; //this field is ignored
    datatransferred.msgkind = CONNECT;
    strcpy( datatransferred.data, datasend ); strcpy( periodata->buffer, (CHAR*)&datatransferred );
    //memmove( (void*)periodata->buffer, (void*)(CHAR*)&datatransferred, 
    //sizeof(INT)+sizeof(MESSAGEKIND)+strlen(datatransferred.data) );
    //response the index of g_everyclient[]
    MySend( periodata, perhandledata );

    }
    }下面是worker线程:
    DWORD WINAPI ServerWorkerThread(LPVOID completionportID)
    {
    HANDLE completionport = (HANDLE) completionportID;
    DWORD bytestransferred;
    LPPER_HANDLE_DATA perhandledata;
    LPPER_IO_OPERATION_DATA periodata;
    INT ret;
    DATATRANSFERRED *pdatatransferred;

    while(TRUE)
    {

    if (GetQueuedCompletionStatus(completionport, &bytestransferred,
    (LPDWORD)&perhandledata, (LPOVERLAPPED *) &periodata, INFINITE) == 0)
    {
    ret = GetLastError();
    printf("GetQueuedCompletionStatus failed with error %d\n", ret );
    if( ret==ERROR_NETNAME_DELETED ) //ERROR_NETNAME_DELETED = 64L
    {
    CleanConnection( perhandledata, periodata );
    }
    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.  ERROR_NETNAME_DELETED ERROR_INVALID_PARAMETER

    if (bytestransferred == 0)
    {
    CleanConnection( perhandledata, 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.

    //注意----一下的处理和重叠IO是类似的
    if (periodata->bytesrecv == 0)
    {
    periodata->bytesrecv = bytestransferred;
    periodata->bytessend = 0;

    pdatatransferred = (DATATRANSFERRED*)periodata->databuf.buf;
    //
    printf( "Data received1: %d\n\n", pdatatransferred->tableno );
    printf( "Data received2: %d\n\n", pdatatransferred->msgkind );
    printf( "Data received3: %s\n\n", pdatatransferred->data );
    //clean the buffer after use of it
    ZeroMemory( periodata->databuf.buf, strlen(periodata->databuf.buf) );
    }
    else
    {
    periodata->bytessend += bytestransferred;
    }

    //if it hasn't sent all the data, then send the rest of them
    if ( strlen(periodata->buffer) > periodata->bytessend )
    {
    MySend( periodata, perhandledata );
    }
    else
    {
    periodata->bytesrecv = 0; MyRecv( periodata, perhandledata );
    }
    }
    }下面是收发函数:
    //My send function
    BOOL MySend( LPPER_IO_OPERATION_DATA periodata, LPPER_HANDLE_DATA perhandledata )
    {
    DWORD sendbytes;

    ZeroMemory(&(periodata->overlapped), sizeof(OVERLAPPED));

    periodata->databuf.buf = periodata->buffer + periodata->bytessend;
    //
    periodata->databuf.len = strlen(periodata->buffer) - periodata->bytessend; //Set the bytesrecv=-1 to indicate that current periodata is sending something
    periodata->bytesrecv   = -1;

    if (WSASend(perhandledata->persocket, &(periodata->databuf), 1, &sendbytes, 0,
    &(periodata->overlapped), NULL) == SOCKET_ERROR)
    {
    if (WSAGetLastError() != ERROR_IO_PENDING)
    {
    printf("WSASend() failed with error %d\n", WSAGetLastError());
    return FALSE;
    }
    } return TRUE;
    }//SERVER ---- My send function
    BOOL MyRecv( LPPER_IO_OPERATION_DATA periodata, LPPER_HANDLE_DATA perhandledata )
    {
    DWORD recvbytes;
    DWORD flags;

    flags = 0;
    ZeroMemory(&(periodata->overlapped), sizeof(OVERLAPPED));

    //Clean the buffer
    ZeroMemory( periodata->buffer, strlen(periodata->buffer) );

    periodata->databuf.len = DATA_BUFSIZE;
    periodata->databuf.buf = periodata->buffer;

    if (WSARecv(perhandledata->persocket, &(periodata->databuf), 1, &recvbytes, &flags,
    &(periodata->overlapped), NULL) == SOCKET_ERROR)
    {
    if (WSAGetLastError() != ERROR_IO_PENDING)
    {
    printf("WSARecv() failed with error %d\n", WSAGetLastError());
    return FALSE;
    }
    } return TRUE;
    }
    ------------------------------------------
    其实比较简单点,那么发送和接收就按照上面可用的代码去写
    -----------------------------------------------------
    就是照着可以的写,但不行啊
      

  10.   

    问题应该现在IOCP的代码
    -----------------------
    具体在哪呢?也要考虑字节序
    ----------------
    何处需要考虑
      

  11.   

    你在当中使用的是strlen来判断缓冲区数据的长度,但是结构体当中可能有部分是'\0',那么你就有可能误判,进而导致,本来该传100个字节,但是实际上只传了30个字节就遇到'\0'而无法再继续传送.通常是一开始发送是就置一个预传送数据总长度,而后不是使用strlen来判断缓冲区的数据长度,直接使用该预置长度来判断还有多少等发送.
    下面是我所写的一个IOCP处理线程的代码,虽然写得不咋样,不过可以供参考一下.   while(1)
       {
      ////////////////////////////////////////////////////////////
      //判断当前同步运行之线程数量是否超出用户预期运行之结程数量//
      //如果超出该期望值,则判断是否有2个以上线程处于用户数据守 //
      //候状态,如果有足够线程等待新的完成例程事件,则结束线程  //
      //                                                        //
      //值得注意的是:                                           //
      //    1.完成例程通知线程是使用LIFO的顺序,                //
      //      也就是最近(后)进入待的线程将得到最大的优先运行权  //
      //      主要是考虑到当一个结程长时间不工作时对于操作系统  //
      //      则须将分配给该线程的资源转换到磁盘缓冲当中出      //
      //      从而提高物理内存的利用率,以预期达到最优的运行效果//
      //    2.对于网络(包括所有关联于该完成例程的I/O事件都采用 //
      //      FIFO的顺序,用以保证数据的顺序性和有效性          //
      ////////////////////////////////////////////////////////////
      if((tcpIOCP->ThreadCount>tcpIOCP->FExpectThreadCount)&&
     (tcpIOCP->FActiveThreadCount>2))
      {
     //将线程置入线程顺收站
     //以便让时脉处理例程完成对相关资源的回收,以及关闭相关句柄
     tcpIOCP->DumpThread(InternalThreadID);
     //结束线程循环,终结线程
     break;
      }   //Active Queued Thread Signal
      //增加活动{实际为等待完成例程队列)计数
      InterlockedIncrement(&(tcpIOCP->FActiveThreadCount));
      //加入完成端口例程处理线程队列,以等待完成例程事件/讯号
      bSuccess=GetQueuedCompletionStatus(hIOCP,
                                                 &dwIOSize,
                                                 (LPDWORD)&lpConnCtx,
                                                 &pOverLapped,
                                                 INFINITE);
      //Inactive Queued Thread Signal
      //得到一个完成例程讯号,线程从等待队列中出列
      //减少活动{实际为等待完成例程队列)计数
      InterlockedDecrement(&(tcpIOCP->FActiveThreadCount));   //No more thread waiting for completion
      //and in working State
      //and Thread count is lower than the Max count
      //Increment One Thread
      //为保证至少有一个线程处于等待完成例程的处理结程的队列当中
      //将在最大线程的限制范围内,增加实际工作线程
      //该值可能会超出用户预期同步运行线程数
      if((1>(tcpIOCP->FActiveThreadCount))
     &&(tcpIOCP->ThreadCount<(long)MAX_THREAD_NUMBER)
     &&(tcpIOCP->FRunningState>LS_SHUTDN))
      {
     tcpIOCP->AddThread();
      }   //Terminate thread by PostQueuedCompletionStatus
      //线程结束通知,由PostQueuedCompletionStatus发出
      //并使得参数lpCompletionKey为NULL
      if(lpConnCtx==NULL)
      {
     break;
      }   //取得重叠I/O信息扩展结构体(从原型指针当中还原)
      lpPerIOData=(LPOVERLAPPEDEX)(pOverLapped);   //当一个得到一个完成通知
      //并且传输数据量为0表示客户端正常断开
      if(bSuccess&&(dwIOSize==0))
      {
     //减少未决操作引用计数
     //该计数主要是为了免除时脉例程处理回收站数据时
     //在所有事件完成/取消前将相关的资源释放掉
     //而导致MSWINSOCK.DLL内部内存地址访问非法错误
     InterlockedDecrement(&(lpPerIOData->LockCount));
     //将该连接上下文信息节点移入回收站
     //以供资源回收例程进一步处理
     tcpIOCP->DumpConnection(lpConnCtx);
     //继续处理下一个完成端口通知事件
     continue;
      }   //完成端口未通知相关事件
      //则可能是由部分线程自我数量调控
      //而自行终结导致在该线程提交的I/O请求被取消
      //或者网络异常
      if(!bSuccess)
      {
     /*Here should Print the InternalThreadID
       and Previous InternalThread in OVERLAPPEDEX*/
     //取得最近错误代码
     LastError=GetLastError();  if(  LastError!=ERROR_IO_PENDING
    //重叠 I/O 操作在进行中。
    //Overlapped I/O operation is in progress.
    &&LastError!=ERROR_OPERATION_ABORTED
    //由于线程退出或应用程序请求,已放弃 I/O 操作。
    //The I/O operation has been aborted because of either a thread exit or an application request.
    &&LastError!=ERROR_NETNAME_DELETED
    //指定的网络名不存在
    //The specified network name is no longer available.
    &&LastError!=ERROR_INVALID_PARAMETER
    //参数不正确
    //The parameter is incorrect.
       )
    continue;
     Socket_Error=WSAGetLastError();
     switch(LastError)
     {
    case ERROR_NETNAME_DELETED://指定的网络名不再可用。
    case ERROR_INVALID_PARAMETER://参数不正确。
     //完成通知队列未弹出不能减少未决操作引用计数
     //该计数主要是为了免除时脉例程处理回收站数据时
     //在所有事件完成/取消前将相关的资源释放掉
     //而导致MSWINSOCK.DLL内部内存地址访问非法错误
     //将该连接上下文信息节点移入回收站
     //以供资源回收例程进一步处理
     tcpIOCP->DumpConnection(lpConnCtx);
     //继续处理下一个完成端口通知事件
     continue;
     }
      }   //减少未决操作引用计数
      //该计数主要是为了免除时脉例程处理回收站数据时
      //在所有事件完成/取消前将相关的资源释放掉
      //而导致MSWINSOCK.DLL内部内存地址访问非法错误
      InterlockedDecrement(&(lpPerIOData->LockCount));
      

  12.   

    //续上...   switch(lpPerIOData->oper)
      {
     case SVR_IO_READ://send then recv
      try
      {
     if(dwIOSize)//有收到数据
    //交给数据处理过程进行处理
    tcpIOCP->InternalOnReceiveData(lpConnCtx,dwIOSize,lpPerIOData->data);
      }
      catch(...)
      {
      }
      //更新流量计数,包括当前用户连接的流量统计值
      //以及全局流量统计值
      tcpIOCP->Lock();
      try
      {
     //更新单连接的总接收流量,超int64时"归零"
     if(lpConnCtx->TotalRecv>(MAX_INT64-dwIOSize))
    lpConnCtx->TotalRecv=dwIOSize;
     else
    lpConnCtx->TotalRecv=lpConnCtx->TotalRecv+dwIOSize;  //更新全局流量计数
     InterlockedExchangeAdd(&(tcpIOCP->BytesRecvPerInterval),dwIOSize);  //判断该连接是否已经标示为回收
     //进入回收状态的连接将不再提交作业请求
     if(true==lpConnCtx->InDumping)
    break;
     //增加未决传输引用计数
     InterlockedIncrement(&(lpPerIOData->LockCount));
      }
      __finally
      {
     tcpIOCP->Unlock();
      }   /*发起新的接收请求,以等待接收用户数据*/
      ZeroMemory(lpPerIOData,sizeof(OVERLAPPEDEX));
      lpPerIOData->OverLapped.hEvent=NULL;
      lpPerIOData->OverLapped.Internal=0;
      lpPerIOData->OverLapped.InternalHigh=0;
      lpPerIOData->OverLapped.Offset=0;
      lpPerIOData->OverLapped.OffsetHigh=0;
      lpPerIOData->wbuf.buf=(char*)&(lpPerIOData->data);
      lpPerIOData->wbuf.len=MAX_BUF_LEN;
      lpPerIOData->oper=SVR_IO_READ;
      lpPerIOData->flags=0;
      #ifdef __DEBUG
      lpPerIOData->WorkingThreadID=InternalThreadID;
      #endif
      //更新是后作业时间,是方便检测超时无数据传输的连接或非法连接
      InterlockedExchange(&(lpConnCtx->LastDataTime),time(0));
      nResult=WSARecv(lpConnCtx->sockAccept,
      &(lpPerIOData->wbuf),
      1,
      NULL,
      &(lpPerIOData->flags),
      &(lpPerIOData->OverLapped),
      NULL);   if(nResult==SOCKET_ERROR)
      {
     Socket_Error=WSAGetLastError();
     if( Socket_Error!=ERROR_IO_PENDING)
     {
    //网络错误清理连接
    InterlockedDecrement(&(lpPerIOData->LockCount));
    tcpIOCP->DumpConnection(lpConnCtx);
     }
      }
      break;
     case SVR_IO_WRITE://recv then echo
                              tcpIOCP->Lock();
                              try
                              {
         EnterCriticalSection(&(lpConnCtx->ctx_CriticalSection));
         try
         {
     /*更新发送缓冲区的已发送计数
       特别用来删除部分已经完成发送的缓冲区*/
     LPIODATANode OutDataNode=lpConnCtx->O_DATA;
     DWORD SentInByte=dwIOSize;
     if(lpConnCtx->TotalSent>(MAX_INT64-SentInByte))
    lpConnCtx->TotalSent=SentInByte;
     else
    lpConnCtx->TotalSent=lpConnCtx->TotalSent+SentInByte;
     InterlockedExchangeAdd(&(tcpIOCP->BytesSentPerInterval),dwIOSize);
     lpConnCtx->TotalSent=lpConnCtx->TotalSent+dwIOSize;
     if(true==lpPerIOData->DataInExtend)
     {
    lpPerIOData->SentBytes=lpPerIOData->SentBytes+SentInByte;
    SentInByte=0;
    if(lpPerIOData->SentBytes>=lpPerIOData->Length)
    {
       lpPerIOData->DataInExtend=false;
       lpPerIOData->Length=0;
       lpPerIOData->SentBytes=0;
    }
     }
     if(false==lpPerIOData->DataInExtend)
     {
    while(NULL!=OutDataNode)
    {
       OutData=OutDataNode->Data;
       if(NULL!=OutData)
       {
      OutData->SentBytes=OutData->SentBytes+SentInByte;
      SentInByte=0;
      if(OutData->SentBytes>=OutData->Length)
      {
     OutDataNode->Data=OutData->Next;
     FreeEx(OutData);
     OutData=NULL;
     OutData=OutDataNode->Data;
      }
      if(NULL!=OutData)
     break;
       }
       if(NULL==OutData)
       {
      lpConnCtx->O_DATA=OutDataNode->Next;
      FreeEx(OutDataNode);
      OutDataNode=lpConnCtx->O_DATA;
      if(NULL==OutDataNode)
     break;
       }
    }/*End of while*/
     }/*End of Not ExtendData*/  if(false==lpPerIOData->DataInExtend&&NULL==OutDataNode)
    //无数据待发送则不作为
    break;
     if(true==lpConnCtx->InDumping)
    //该连接已经置回收状态,不再提交作业
    break;
     //增加未决请求计数
     InterlockedIncrement(&(lpPerIOData->LockCount));
        }
         __finally
         {
     LeaveCriticalSection(&(lpConnCtx->ctx_CriticalSection));
         }
                              }
                              __finally
                              {
                                 tcpIOCP->Unlock();
                              }
      //No sending data
      lpPerIOData->oper=SVR_IO_WRITE;
      lpPerIOData->flags=0;
      lpPerIOData->OverLapped.hEvent=NULL;
      lpPerIOData->OverLapped.Internal=0;
      lpPerIOData->OverLapped.InternalHigh=0;
      lpPerIOData->OverLapped.Offset=0;
      lpPerIOData->OverLapped.OffsetHigh=0;
      #ifdef __DEBUG
      lpPerIOData->WorkingThreadID=InternalThreadID;
      #endif
      u_long Length;
      //Begin=========================O_OverLappedEx=====================//
      InterlockedExchange(&(lpConnCtx->LastDataTime),time(0));
      if(true==lpPerIOData->DataInExtend)
      {
     //发送重叠I/O信息扩展结构体内部数据
     Length=lpPerIOData->Length-lpPerIOData->SentBytes;
     lpPerIOData->wbuf.len=Length;
     lpPerIOData->wbuf.buf=(char *)(lpPerIOData->data+lpPerIOData->SentBytes);  nResult=WSASend(lpConnCtx->sockAccept,
     &(lpPerIOData->wbuf),
     1,
     NULL,
     lpPerIOData->flags,
     &(lpPerIOData->OverLapped),
     NULL);
      }
      //End===========================O_OverLappedEx=====================//
      //Begin=============================O_DATA=========================//
      else
      {
     //发送重叠I/O信息扩展结构体外的待发送数据
     Length=OutData->Length-OutData->SentBytes;
     lpPerIOData->wbuf.len=Length;
     lpPerIOData->wbuf.buf=(char *)(OutData->Buffer+OutData->SentBytes);
     nResult=WSASend(lpConnCtx->sockAccept,
     &(lpPerIOData->wbuf),
     1,
     NULL,
     lpPerIOData->flags,
     &(lpPerIOData->OverLapped),
     NULL);
      }
      //Begin=============================O_DATA=========================//
      if(nResult==SOCKET_ERROR)
      {
     Socket_Error=WSAGetLastError();
     if(Socket_Error!=ERROR_IO_PENDING)
     {
    //网络错误,清理连接
    InterlockedDecrement(&(lpPerIOData->LockCount));
    tcpIOCP->DumpConnection(lpConnCtx);
     }
      }
      break;
      }/*End of switch*/
       }
      

  13.   

    非常感谢unsigned
    可惜本人是新手
    很多地方看不明白
    我再仔细看看刚尝试过使用具体的内存拷贝,本以为应该可以的,但为何不行?//Message kind enum structure ( the same as the client )
    typedef enum { CONNECT, START, WINNER }MESSAGEKIND;
    //Data structure transferred ( the same as the client )
    typedef struct 
    {
    INT tableno;
    MESSAGEKIND msgkind;
    CHAR data[DATA_BUFSIZE];
    }DATATRANSFERRED;
    //拷贝
    memcpy( periodata->buffer, (CHAR*)&datatransferred.tableno, sizeof(INT) );
    memcpy( (periodata->buffer+sizeof(INT)), (CHAR*)&datatransferred.msgkind, sizeof(MESSAGEKIND) );
    memcpy( (periodata->buffer+sizeof(INT)+sizeof(MESSAGEKIND)), 
    (CHAR*)datatransferred.data, strlen(datatransferred.data) );
    //datatransferred.data假设为"hello"

    //末尾加0 periodata->buffer[strlen(datatransferred.data)+sizeof(INT)+sizeof(MESSAGEKIND)] = 0;
      

  14.   

    http://blog.csdn.net/ximenying/archive/2006/08/08/1037519.aspx