IOCP (关于WSASend,WSARecv调用)

最近都在做windows socket相关的东西,使用IOCP其中还是遇到了一些问题,当然遇到问题就要尝试解决问题,这也是一个学习的过程。

IOCP可以说是windows 上性能最好的网络模型了,具体IOCP,就不介绍了.在用我的网络接口,发大量数据时,发现,数据对不上,即收包量会增多,内容是不会丢的,由于我是严格控制服务器端的收包大小,和收包量,所以也感觉很奇怪。

先是怀疑WSASend连续调用,会有问题,但大致看了看这篇文章(http://bbs.pediy.com/showthread.php?p=826108),这文章写的很给力,所以又觉得不会有问题,于是我就自己开始写了一个测试程序。

当然也不是写了就马上能发现问题,调了一下午加一个晚上,发现了问题所在。

问题在WSARecv,这个东西它居然没填满我要求的缓存,就给完成端口发了通知,导致客户端发过来的数据,被截开了,所以包的数量就增加了,但是由于是TCP,所以内容,顺序都没问题。

接下来说说如何解决问题:

BOOL bIORet = GetQueuedCompletionStatus(CompPort,

                                    &dwIoSize,

                                    (LPDWORD)&pCompletionKey,

                                    &lpOverlapped,

                                    INFINITE);

关键看第二个参数,dwIoSize,它告诉你,你实际接收到了多少数据,通过它,你就应该知道还要继续接受多少数据了吧,明白人,应该就知道该如何做了,不明白的看我的代码吧。

 

注意:WSARecv,最好不要连续调用,特别是在多线程里连续调用,因为后果可能会无法预料,这个应该还是根据需求而定,也许有的情况下可以。

 

剩下的就是贴代码了,时间紧任务重,加上本人比较水,所以代码质量不高,多多包涵,同时还请各位朋友给出建议,提出批评,大家一起学习,共同进步。

 

//client.cpp

  1. #include<iostream>  
  2. #include<fstream>  
  3. #include<WinSock2.h>  
  4. #include<Windows.h>  
  5. #include<tchar.h>  
  6. using namespace std;  
  7. #define BUF_TIMES 10  
  8. struct CompletionKey{SOCKET s;};  
  9. typedef struct io_operation_data  
  10. {  
  11.     WSAOVERLAPPED   overlapped;             //重叠结构  
  12.     WSABUF      wsaBuf;                  //发送接收缓冲区  
  13. }IO_OPERATION_DATA, *PIO_OPERATION_DATA;  
  14. SOCKET sClient;  
  15. //char (*data)[1024];  
  16. DWORD WINAPI ServiceThreadProc(PVOID pParam);  
  17. int main()  
  18. {  
  19.     HRESULT  hr=CoInitializeEx(NULL,COINIT_MULTITHREADED);  
  20.     if(FAILED(hr))  
  21.     {  
  22.         MessageBox(NULL,_T("Initialize COM failed!"),_T("error"),MB_OK);  
  23.         //cout<<"Initialize COM failed!"<<endl;  
  24.         //return false;  
  25.     }  
  26.     WORD wVersionRequest;  
  27.     WSADATA wsaData;  
  28.     wVersionRequest=MAKEWORD(2,2);  
  29.     int nErrCode=WSAStartup(wVersionRequest,&wsaData);  
  30.     if(nErrCode!=0)  
  31.     {  
  32.         //cout<<" start up error!"<<endl;  
  33.         MessageBox(NULL,_T("start up error!"),_T("error"),MB_OK);  
  34.     }  
  35.     if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)  
  36.     {  
  37.         //cout<<" lib is not 2.2!"<<endl;  
  38.         MessageBox(NULL,_T("lib is not 2.2!"),_T("error"),MB_OK);  
  39.         WSACleanup();  
  40.     }  
  41.     sClient=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);//socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
  42.     if(INVALID_SOCKET==sClient)  
  43.     {  
  44.         MessageBox(NULL,_T("socket error!"),_T("error"),MB_OK);  
  45.     }  
  46.   
  47.     //获取系统默认的发送数据缓冲区大小  
  48.     unsigned int uiRcvBuf;  
  49.     int uiRcvBufLen = sizeof(uiRcvBuf);  
  50.     nErrCode= getsockopt(sClient, SOL_SOCKET, SO_SNDBUF,(char*)&uiRcvBuf, &uiRcvBufLen);  
  51.     if (SOCKET_ERROR == nErrCode)  
  52.     {  
  53.         //cout<<"获取系统默认的发送数据缓冲区大小failed!"<<endl;  
  54.         MessageBox(NULL,_T("获取系统默认的发送数据缓冲区大小failed!"),_T("error"),MB_OK);  
  55.         //return false;  
  56.     }  
  57.     //设置系统发送数据缓冲区为默认值的BUF_TIMES倍  
  58.     uiRcvBuf *= BUF_TIMES;  
  59.     nErrCode = setsockopt(sClient, SOL_SOCKET, SO_SNDBUF,(char*)&uiRcvBuf, uiRcvBufLen);  
  60.     if (SOCKET_ERROR == nErrCode)  
  61.     {  
  62.         //cout<<"修改系统发送数据缓冲区失败!"<<endl;  
  63.         MessageBox(NULL,_T("修改系统发送数据缓冲区失败!"),_T("error"),MB_OK);  
  64.     }  
  65.   
  66.     //检查设置系统发送数据缓冲区是否成功  
  67.     unsigned int uiNewRcvBuf;  
  68.     nErrCode=getsockopt(sClient, SOL_SOCKET, SO_SNDBUF,(char*)&uiNewRcvBuf, &uiRcvBufLen);  
  69.     if (SOCKET_ERROR == nErrCode || uiNewRcvBuf != uiRcvBuf)  
  70.     {  
  71. //      cout<<"修改系统发送数据缓冲区失败!"<<endl;  
  72.         MessageBox(NULL,_T("修改系统发送数据缓冲区失败!"),_T("error"),MB_OK);  
  73.     }  
  74.     HANDLE CompPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);  
  75.     if (CompPort == NULL)  
  76.     {  
  77.         MessageBox(NULL,_T("创建完成端口失败!"),_T("error"),MB_OK);  
  78.         //WSACleanup();  
  79.         //return ;  
  80.     }  
  81.     CompletionKey iCompletionKey;  
  82.     iCompletionKey.s=sClient;  
  83.     if (CreateIoCompletionPort((HANDLE)sClient,CompPort,(DWORD)&iCompletionKey,0) == NULL)  
  84.     {  
  85.         //出错处理。。  
  86.         MessageBox(NULL,_T("关联完成端口失败!"),_T("error"),MB_OK);  
  87.     }  
  88.     //addrHost    
  89.     SOCKADDR_IN addrHost;  
  90.     addrHost.sin_family=AF_INET;  
  91.     addrHost.sin_port=htons(8800);  
  92.     addrHost.sin_addr.S_un.S_addr=inet_addr("192.168.0.137");  
  93.   
  94.     int retVal=connect(sClient,(sockaddr*)&addrHost,sizeof(sockaddr));  
  95.     if(retVal==SOCKET_ERROR)  
  96.     {  
  97.         MessageBox(NULL,_T("connect error!"),_T("error"),MB_OK);  
  98.         //return false;  
  99.     }  
  100.     cout<<"connect success"<<endl;  
  101.   
  102.     HANDLE hThread=CreateThread(NULL,0,ServiceThreadProc,NULL,0,NULL);  
  103.       
  104.     DWORD           dwIoSize=-1;        //传输字节数  
  105.     LPOVERLAPPED    lpOverlapped=NULL;  //重叠结构指针  
  106.     CompletionKey*  pCompletionKey=NULL;  
  107.     PIO_OPERATION_DATA pIO=NULL;  
  108.     int count=0;  
  109.     ofstream fos;  
  110.     fos.open("c.txt");  
  111.   
  112.     while(1)  
  113.     {  
  114.         BOOL bIORet = GetQueuedCompletionStatus(CompPort,  
  115.                                                 &dwIoSize,  
  116.                                                 (LPDWORD)&pCompletionKey,  
  117.                                                 &lpOverlapped,  
  118.                                                 INFINITE);  
  119.         //失败的操作完成  
  120.         if (FALSE == bIORet && NULL != pCompletionKey)  
  121.         {     
  122.             //客户端断开  
  123.         }  
  124.         //成功的操作完成  
  125.         if(bIORet && lpOverlapped && pCompletionKey)  
  126.         {  
  127.             cout<<"count: "<<count+1<<"  "  
  128.                 <<"number: "<<dwIoSize<<endl;  
  129.             pIO = CONTAINING_RECORD(lpOverlapped,IO_OPERATION_DATA,overlapped);  
  130.             fos.write(pIO->wsaBuf.buf,10240*5);  
  131.             fos<<endl;  
  132.             if(count==99)  
  133.                 break;  
  134.             count++;  
  135.         }  
  136.   
  137.     }  
  138.       
  139.     WaitForSingleObject(hThread,INFINITE);  
  140.     cout<<"main end: "<<count+1<<endl;  
  141.     fos.close();  
  142.     Sleep(5000);  
  143.     CoUninitialize();  
  144.     WSACleanup();  
  145.     return 0;  
  146. }  
  147. DWORD WINAPI ServiceThreadProc(PVOID pParam)  
  148. {  
  149.     char (*a)[10240*5]=new char[100][10240*5];  
  150.     for(int i=0;i<100;i++)  
  151.     {  
  152.         if(i%3==0)  
  153.             memset(a[i],'a',10240*5);  
  154.         else if(i%3==1)  
  155.             memset(a[i],'b',10240*5);  
  156.         else if(i%3==2)  
  157.             memset(a[i],'c',10240*5);  
  158.     }  
  159.     DWORD   flags = 0;          //标志  
  160.     DWORD   sendBytes =0;       //发送字节数  
  161.     int count=0;  
  162.     while(count<100)  
  163.     {  
  164.         PIO_OPERATION_DATA pIO = new IO_OPERATION_DATA;   
  165.         ZeroMemory(pIO,sizeof(IO_OPERATION_DATA));  
  166.         pIO->wsaBuf.buf=a[count];  
  167.         pIO->wsaBuf.len=10240*5;  
  168.           
  169.         //Sleep(30);  
  170.         if(WSASend(sClient,&(pIO->wsaBuf),1,&sendBytes,flags,&(pIO->overlapped),NULL)== SOCKET_ERROR)  
  171.         {  
  172.             if(ERROR_IO_PENDING != WSAGetLastError())//发起重叠操作失败  
  173.             {  
  174.                 cout<<"send failed"<<endl;  
  175.             }  
  176.         }  
  177.         count++;  
  178.     }  
  179.       
  180.     cout<<"thread func:  "<<count<<endl;  
  181.     Sleep(10000);  
  182.       
  183.     return 0;  
  184. }  

 

//server.cpp

 

[cpp]  view plain  copy
  1. #include<iostream>  
  2. #include<vector>  
  3. #include<fstream>  
  4. #include<WinSock2.h>  
  5. #include<Windows.h>  
  6. #include<tchar.h>  
  7. using namespace std;  
  8. #define BUF_TIMES 10  
  9. struct CompletionKey{SOCKET s;};  
  10. typedef struct io_operation_data  
  11. {  
  12.     WSAOVERLAPPED   overlapped;             //重叠结构  
  13.     WSABUF      wsaBuf;                  //发送接收缓冲区  
  14. }IO_OPERATION_DATA, *PIO_OPERATION_DATA;  
  15. int main()  
  16. {  
  17.     HRESULT  hr=CoInitializeEx(NULL,COINIT_MULTITHREADED);  
  18.     if(FAILED(hr))  
  19.     {  
  20.         MessageBox(NULL,_T("Initialize COM failed!"),_T("error"),MB_OK);  
  21.         //cout<<"Initialize COM failed!"<<endl;  
  22.         //return false;  
  23.     }  
  24.     WORD wVersionRequest;  
  25.     WSADATA wsaData;  
  26.     wVersionRequest=MAKEWORD(2,2);  
  27.     int nErrCode=WSAStartup(wVersionRequest,&wsaData);  
  28.     if(nErrCode!=0)  
  29.     {  
  30.         //cout<<" start up error!"<<endl;  
  31.         MessageBox(NULL,_T("start up error!"),_T("error"),MB_OK);  
  32.     }  
  33.     if(LOBYTE(wsaData.wVersion)!=2||HIBYTE(wsaData.wVersion)!=2)  
  34.     {  
  35.         //cout<<" lib is not 2.2!"<<endl;  
  36.         MessageBox(NULL,_T("lib is not 2.2!"),_T("error"),MB_OK);  
  37.         WSACleanup();  
  38.     }  
  39.     SOCKET sListen=WSASocket(AF_INET,SOCK_STREAM,0,NULL,0,WSA_FLAG_OVERLAPPED);//socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);  
  40.     if(INVALID_SOCKET==sListen)  
  41.     {  
  42.         MessageBox(NULL,_T("socket error!"),_T("error"),MB_OK);  
  43.     }  
  44.       
  45.     //获取系统默认的发送数据缓冲区大小  
  46.     unsigned int uiRcvBuf;  
  47.     int uiRcvBufLen = sizeof(uiRcvBuf);  
  48.     nErrCode= getsockopt(sListen, SOL_SOCKET, SO_SNDBUF,(char*)&uiRcvBuf, &uiRcvBufLen);  
  49.     if (SOCKET_ERROR == nErrCode)  
  50.     {  
  51.         //cout<<"获取系统默认的发送数据缓冲区大小failed!"<<endl;  
  52.         MessageBox(NULL,_T("获取系统默认的发送数据缓冲区大小failed!"),_T("error"),MB_OK);  
  53.         //return false;  
  54.     }  
  55.     //设置系统发送数据缓冲区为默认值的BUF_TIMES倍  
  56.     uiRcvBuf *= BUF_TIMES;  
  57.     nErrCode = setsockopt(sListen, SOL_SOCKET, SO_SNDBUF,(char*)&uiRcvBuf, uiRcvBufLen);  
  58.     if (SOCKET_ERROR == nErrCode)  
  59.     {  
  60.         //cout<<"修改系统发送数据缓冲区失败!"<<endl;  
  61.         MessageBox(NULL,_T("修改系统发送数据缓冲区失败!"),_T("error"),MB_OK);  
  62.     }  
  63.     //检查设置系统发送数据缓冲区是否成功  
  64.     unsigned int uiNewRcvBuf;  
  65.     nErrCode=getsockopt(sListen, SOL_SOCKET, SO_SNDBUF,(char*)&uiNewRcvBuf, &uiRcvBufLen);  
  66.     if (SOCKET_ERROR == nErrCode || uiNewRcvBuf != uiRcvBuf)  
  67.     {  
  68. //      cout<<"修改系统发送数据缓冲区失败!"<<endl;  
  69.         MessageBox(NULL,_T("修改系统发送数据缓冲区失败!"),_T("error"),MB_OK);  
  70.     }  
  71.     //cout<<uiNewRcvBuf<<endl;  
  72.     HANDLE CompPort=CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0);  
  73.     if (CompPort == NULL)  
  74.     {  
  75.         MessageBox(NULL,_T("创建完成端口失败!"),_T("error"),MB_OK);  
  76.         //WSACleanup();  
  77.         //return ;  
  78.     }  
  79.     SOCKADDR_IN addrHost;  
  80.     addrHost.sin_family=AF_INET;  
  81.     addrHost.sin_port=htons(8800);  
  82.     addrHost.sin_addr.S_un.S_addr=INADDR_ANY;  
  83.     int retVal=bind(sListen,(LPSOCKADDR)&addrHost, sizeof(SOCKADDR_IN));  
  84.     if(SOCKET_ERROR==retVal)  
  85.     {  
  86.         //cout<<"bind error!"<<endl;  
  87.         MessageBox(NULL,_T("bind error!"),_T("error"),MB_OK);  
  88.         //closesocket(this->m_sListen);  
  89.         //return false;  
  90.     }  
  91.     retVal=listen(sListen,5);  
  92.     if(SOCKET_ERROR==retVal)  
  93.     {  
  94.         MessageBox(NULL,_T("listen error!"),_T("error"),MB_OK);  
  95.           
  96.     }  
  97.     sockaddr_in addrClient;  
  98.     int addrLen=sizeof(sockaddr_in);  
  99.     SOCKET sClient=accept(sListen,(sockaddr*)&addrClient,&addrLen);  
  100.       
  101.     cout<<"come in"<<endl;  
  102.     CompletionKey iCompletionKey;  
  103.     iCompletionKey.s=sClient;  
  104.     //关联完成端口  
  105.     if (CreateIoCompletionPort((HANDLE)sClient,CompPort,(DWORD)(&iCompletionKey),0) == NULL)  
  106.     {  
  107.         //出错处理。。  
  108.         MessageBox(NULL,_T("关联完成端口失败!"),_T("error"),MB_OK);  
  109.     }  
  110.     DWORD           dwIoSize=-1;        //传输字节数  
  111.     LPOVERLAPPED    lpOverlapped=NULL;  //重叠结构指针  
  112.     CompletionKey*  pCompletionKey=NULL;  
  113.     DWORD   flags = 0;      //标志  
  114.     DWORD   recvBytes =0;   //接收字节数  
  115.     PIO_OPERATION_DATA pIO=NULL;  
  116.     int count=0;  
  117.     pIO=new IO_OPERATION_DATA;  
  118.     ZeroMemory(pIO, sizeof(IO_OPERATION_DATA));  
  119.     pIO->wsaBuf.buf=new char[10240*5];  
  120.     pIO->wsaBuf.len=10240*5;  
  121.     if (WSARecv(sClient,&(pIO->wsaBuf),1,&recvBytes,&flags,&(pIO->overlapped),NULL) == SOCKET_ERROR)  
  122.     {  
  123.         if(ERROR_IO_PENDING != WSAGetLastError())  
  124.         {  
  125.             cout<<"recv failed"<<endl;  
  126.         }  
  127.     }  
  128.     vector<IO_OPERATION_DATA*> vecCache;  
  129.     ofstream fos;  
  130.     fos.open("s.txt");  
  131.     while(1)  
  132.     {  
  133.         BOOL bIORet = GetQueuedCompletionStatus(CompPort,  
  134.                             &dwIoSize,  
  135.                             (LPDWORD)&pCompletionKey,  
  136.                             &lpOverlapped,  
  137.                             INFINITE);  
  138.         //失败的操作完成  
  139.         if (FALSE == bIORet && NULL != pCompletionKey)  
  140.         {     
  141.             //客户端断开   
  142.         }  
  143.         //成功的操作完成  
  144.         if(bIORet && lpOverlapped && pCompletionKey)  
  145.         {  
  146.             pIO = CONTAINING_RECORD(lpOverlapped,IO_OPERATION_DATA,overlapped);  
  147.             if(dwIoSize<pIO->wsaBuf.len)  
  148.             {  
  149.                 vecCache.push_back(pIO);  
  150.                 int size=pIO->wsaBuf.len;  
  151.                 pIO->wsaBuf.len=dwIoSize;  
  152.                 pIO=new IO_OPERATION_DATA;  
  153.                 ZeroMemory(pIO, sizeof(IO_OPERATION_DATA));  
  154.                 pIO->wsaBuf.buf=new char[size-dwIoSize];  
  155.                 pIO->wsaBuf.len=size-dwIoSize;  
  156.                 if (WSARecv(sClient,&(pIO->wsaBuf),1,&recvBytes,&flags,&(pIO->overlapped),NULL) == SOCKET_ERROR)  
  157.                 {  
  158.                     if(ERROR_IO_PENDING != WSAGetLastError())  
  159.                     {             
  160.                         cout<<"recv failed"<<endl;  
  161.                     }  
  162.                 }  
  163.             }  
  164.             else  
  165.             {  
  166.                 if(vecCache.size()!=0)  
  167.                 {  
  168.                     char*p=new char[10240*5];  
  169.                     int size=0;  
  170.                     for(vector<IO_OPERATION_DATA*>::iterator it=vecCache.begin();  
  171.                         it!=vecCache.end();it++)  
  172.                     {  
  173.                         memcpy(p+size,(*it)->wsaBuf.buf,(*it)->wsaBuf.len);  
  174.                         size+=(*it)->wsaBuf.len;  
  175.                         //清理资源  
  176.                         delete []((*it)->wsaBuf.buf);  
  177.                         delete (*it);  
  178.                     }  
  179.                     memcpy(p+size,pIO->wsaBuf.buf,pIO->wsaBuf.len);  
  180.                     count++;  
  181.                     fos.write(p,10240*5);  
  182.                     fos<<endl;  
  183.                     vecCache.clear();  
  184.                     cout<<"count: "<<count<<endl;  
  185.                     //清理资源  
  186.                     delete [](pIO->wsaBuf.buf);  
  187.                     delete pIO;  
  188.                     delete []p;  
  189.                 }  
  190.                 else  
  191.                 {  
  192.                     count++;  
  193.                     fos.write(pIO->wsaBuf.buf,10240*5);  
  194.                     fos<<endl;  
  195.                     cout<<"count: "<<count  
  196.                         <<"  number: "<<dwIoSize<<endl;  
  197.                     //清理资源  
  198.                     delete [](pIO->wsaBuf.buf);  
  199.                     delete pIO;  
  200.                 }  
  201.                     pIO=new IO_OPERATION_DATA;  
  202.                     ZeroMemory(pIO, sizeof(IO_OPERATION_DATA));  
  203.                     pIO->wsaBuf.buf=new char[10240*5];  
  204.                     pIO->wsaBuf.len=10240*5;  
  205.                     if (WSARecv(sClient,&(pIO->wsaBuf),1,&recvBytes,&flags,&(pIO->overlapped),NULL) == SOCKET_ERROR)  
  206.                     {  
  207.                         if(ERROR_IO_PENDING != WSAGetLastError())  
  208.                         {             
  209.                             cout<<"recv failed"<<endl;  
  210.                         }  
  211.                     }  
  212.                   
  213.             }  
  214.             if(count==100)  
  215.                 break;  
  216.         }  
  217.     }  
  218.       
  219.     cout<<"main end: "<<count<<endl;  
  220.     fos.close();  
  221.     Sleep(10000);  
  222.     CoUninitialize();  
  223.     WSACleanup();  
  224.     return 0;  
  225. }  
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值