#define MAX_BUFFER_SIZE 10240 dwFlags = 0;
dwRecvBytes = 0;
perIOData->wsDataBuf.buf = perIOData->pBuffer;
perIOData->wsDataBuf.len = MAX_BUFFER_SIZE;
ZeroMemory(&(perIOData->overLapped), sizeof(OVERLAPPED));
WSARecv(perHandleData->sock, &perIOData->wsDataBuf, 1, &dwRecvBytes, &dwFlags,&perIOData->overLapped, NULL);
我用完成端口
客户端 WSARecv 接收服务器发过来的时候
为什么有的时候 服务器发过来的数据 perIOData->wsDataBuf.len 小于 MAX_BUFFER_SIZE;
BOOL ret = GetQueuedCompletionStatus(pThis->m_hIOCP, &dwTransferByte,
(LPDWORD)&perHandleData, (LPOVERLAPPED*)&perIOData, INFINITE);
它得到的dwTransferByte会等于10240呢? 这个是什么问题呀
解决方案 »
- 在一个派生自CWnd的类创建CButton
- 对话框运行出现错误..
- 如何实现服务器程序点击右下角的图标弹出窗口功能? 如右键点击右下角SQL server 2000的服务图标,然后点击“选项”,弹出SQL Server服务器管理选项功能。
- 关于调用私用成员的问题
- 谁能提供对话框控件的学习资料,要详细的
- 关于GetProcessMemoryInfo
- 出错信息为Fist_Change exception in DBFODBC.exe(udp.dll):OxC0000005:Access Violation
- vc初学者!咨询个简单问题
- 关于CreateFont参数nHeight的疑问
- 重绘问题
- 基于对话框的MFC程序,如何改变窗口大小。
- 内嵌Flash控件的ActiveX控件在IE中收不到FSCommand吗?
一般自定义一个协议,在数据前设个字段,表示数据的长度
一个连接只允许一个线程收 这样处理实在是太慢了 要求当然要多线程啦我发送数据前面有弄个
typedef struct _CMD_PACK_INFO
{
int nCMD; //包命令
int nID; //包ID
int nPos; //包位移
short sDataSize; //包大小
}CMD_PACK_INFO, *LPCMD_PACK_INFO;
可是有的时候 判断包命令都错误 就别说下面了
{
int nCMD; //包命令
int nID; //包ID
int nPos; //包位移
short sDataSize; //包大小
}CMD_PACK_INFO, *LPCMD_PACK_INFO;
我要看的是你的数据流的格式,不是结构体的格式。
可是时间就慢了很多 没sleep 包就有错误 这个是怎么回事呢
问题是
我客户端请求下载文件
客户端会突然就没反应了 但是服务器那边有把数据发送完
服务端是按块发送的 块发送完 客户端接收完 会给服务器一个反馈 服务器接收到反馈后才会继续发送数据
可是 客户端停住了 服务器还是会继续发 我跟踪又发现不了 问题 所以我考虑 让它sleep一下 sleep100 我就没发现原来那个问题
测了好几次 都没问题
可是sleep传输文件实在是太慢了
各位大侠们 帮帮忙 看看这个是怎么回事分我加了 不够可以继续加
-----IoSend
-----IoRecv
dwTransferByte = 18
-----NP_SC_FILEINFO
-----IoSend
-----IoRecv
dwTransferByte = 7314
-----NP_NC_FILEDATA
dwFileMapviewUsed = 7300 --- dwFileMapview =65536
-----IoRecv
dwTransferByte = 7314
-----NP_NC_FILEDATA
dwFileMapviewUsed = 14600 --- dwFileMapview =65536
-----IoRecv
14是包头大小 7300是内容
一、 WSAENOBUFS 错误问题。
这个问题通常很难靠直觉发现,因为当你第一次看见的时候你或许认为是一个内存泄露错误。假定已经开发完成了你的完成端口服务器并且运行的一切良好,但是当你对其进行压力测试的时候突然发现服务器被中止而不处理任何请求了,如果你运气好的话你会很快发现是因为WSAENOBUFS 错误而影响了这一切。
每当我们重叠提交一个send或receive操作的时候,其中指定的发送或接收缓冲区就被锁定了。当内存缓冲区被锁定后,将不能从物理内存进行分页。操作系统有一个锁定最大数的限制,一旦超过这个锁定的限制,那么就会产生WSAENOBUFS 错误了。
如果一个服务器提交了非常多的重叠的receive在每一个连接上,那么限制会随着连接数的增长而变化。如果一个服务器能够预先估计可能会产生的最大并发连接数,服务器可以投递一个使用零缓冲区的receive在每一个连接上。因为当你提交操作没有缓冲区时,那么也不会存在内存被锁定了。使用这种办法后,当你的receive操作事件完成返回时,该socket底层缓冲区的数据会原封不动的还在其中而没有被读取到receive操作的缓冲区来。此时,服务器可以简单的调用非阻塞式的recv将存在socket缓冲区中的数据全部读出来,一直到recv返回 WSAEWOULDBLOCK 为止。
这种设计非常适合那些可以牺牲数据吞吐量而换取巨大并发连接数的服务器。当然,你也需要意识到如何让客户端的行为尽量避免对服务器造成影响。在上一个例子中,当一个零缓冲区的receive操作被返回后使用一个非阻塞的recv去读取socket缓冲区中的数据,如果服务器此时可预计到将会有爆发的数据流,那么可以考虑此时投递一个或者多个receive来取代非阻塞的recv来进行数据接收。(这比你使用1个缺省的8K缓冲区来接收要好的多。)
总结:
解决方法一:
投递使用空缓冲区的 recevie操作,当操作返回后,使用非阻塞的recv来进行真实数据的读取。因此在完成端口的每一个连接中需要使用一个循环的操作来不断的来提交空缓冲区的receive操作。
解决方法二:
在投递几个普通含有缓冲区的recevie操作后,进接着开始循环投递一个空缓冲区的recevie操作。这样保证它们按照投递顺序依次返回,这样我们就总能对被锁定的内存进行解锁。
我在网上也看到关于这个的技术文章 看了还是解决不了
http://tech.ddvip.com/2008-12/122855295598098.html
服务器是发送端 客户端是接收端
如果单线程没问题而多线程有问题,就可能是互斥或者数据访问的随机导致的问题.你说"客户端停住了 服务器还是会继续发",这个你描述的不清楚,因为你说"客户端接收完 会给服务器一个反馈 服务器接收到反馈后才会继续发送数据",所有你说的情况理论上是不会发生的,如果发生了,那就是你程序的逻辑根本就没实现"服务器接收到反馈后才会继续发送数据".至于那位仁兄说"原则上在一个连接上同一时间只能存在一个WSARecv请求",我觉得投递几个WSARecv请求没有问题,我写的程序都是投递5个WSARecv请求,此后每完成一个就再投递一个WSARecv请求.但是每个socket都有一个lock,这样每个socket每次只能处理一个WSARecv请求.
现在我仍然没有找到解决方法,上面有位仁兄说"投递一个字节为数0的包",不知道可不可以解决,以后试一下看看.
单线程尝试过了 还是不行 就是文件小的时候可以成功 大的文件发到一半就不发了
是呀 客户端接收完一块后 会给服务器一个反馈 服务器才继续下一块 可是
客户端 收到2883584
-----BLOCK OK
-----dwFileOffset = 2883584
-----IoSend
-----IoRecv
dwTransferByte = 7314
-----NP_NC_FILEDATA
而服务器 已经到了3866624
-----dwFileOffset = 3866624
-----IoSend
-----IoSend
-----IoSend
-----IoSend
我如果把发送反馈的屏蔽掉 服务器下面就不发了
所以这个我感觉很纳闷
你这样,一个连接上投递了多个WSARecv之后,又加了锁与投递一个有什么区别呢?
你看下 服务器那边数据发送完的是 =-=-这个标识
而客户端接收完的标识是 Down OK
1.运气好 就OK 下载都成功
2.服务器那边打印出来的是数据都传完 而客户端到一半就没打印了 要不就是提示客户端接收到的信令错误
3.服务器和客户端 中途就没打印了
到我跟踪的时候 好像要都没问题 如果加上sleep100的 大部分就都下载成功 有的时候也错误
winxp 双核 2G Fat32
加锁只是在对接收到的数据进行处理的时候加锁
你看看下面的帖子,就了解了。
http://www.cppblog.com/sherrylso/archive/2008/06/23/30858.html
dwTransferByte = 7314 currThreadID = 2280
perPackInfo->nCMD ERROR!
-----IoRecv
dwTransferByte = 7314 currThreadID = 2348
perPackInfo->nCMD ERROR!
-----IoRecv
dwTransferByte = 2830 currThreadID = 2280
perPackInfo->nCMD ERROR!
就是有些时候 会出现这样 包乱了
包乱了 就不怎么好处理了
我试都会出现这个问题 纳闷呀
你要看客户端是否出现了 Down OK 这个 是的话就说明下载OK
我福州的
服务端发送数据 客户端接收数据
包乱是客户端接收到 提示perPackInfo->nCMD ERROR
你可以到代码里面查找一下
OutputDebugString("perPackInfo->nCMD ERROR!\r\n");
这个是完成端口接收到数据 解析信令 可是信令是错的还的时候 就是我不是有把收到的数据信息 打到DEBUG里面吗
用那个跟踪 有的时候发到一半就不打印了 可是网络还是通的 你怎么都没出现这个问题 我跟踪了几次都有这个现象 难道是RP问题?下载成功一个文件是 服务器那边数据发送完是OutputDebugString("=-=-=-=-\r\n");
客户端是 Down OK
perPackInfo = (LPCMD_PACK_INFO)perIOData->pBuffer;
char temp[256] = {0};
sprintf(temp, "dwTransferByte = %d \r\n", dwTransferByte);
OutputDebugString(temp); switch(perPackInfo->nCMD)
{
case NP_SC_FILEINFO:
{
OutputDebugString("-----NP_SC_FILEINFO\r\n");
BOOL bRet = pThis->DealFileInfo(perHandleData, perPackInfo);
if (!bRet)
{
break;
}
}
break;
case NP_NC_FILEDATA:
{
OutputDebugString("-----NP_NC_FILEDATA\r\n");
BOOL bRet = pThis->DealFileData(perHandleData, perPackInfo);
if (!bRet)
{
break;
}
}
break;
default:
{
OutputDebugString("perPackInfo->nCMD ERROR!\r\n");
}
break;
} dwFlags = 0;
dwRecvBytes = 0;
perHandleData->recvIO->wsDataBuf.buf = perHandleData->recvIO->pBuffer;
perHandleData->recvIO->wsDataBuf.len = MAX_SEND_SIZE + nStructSize;
ZeroMemory(&(perHandleData->recvIO->overLapped), sizeof(OVERLAPPED));
WSARecv(perHandleData->sock, &perHandleData->recvIO->wsDataBuf, 1, &dwRecvBytes, &dwFlags,
&perHandleData->recvIO->overLapped, NULL);
}
break;
肯定不对的。你还是接收了一次,要判断dwTransferByte,如果小于预定的值就不要处理,继续接收才对。直到接收达到预定的值再处理。
我这天被老板催了紧 就只能细节的先来 都不知道对不对 烦!
UDP是基于数据报模式,不存在一次发送多次接受问题,但不保证数据的正确性,所以每个包都要做正确性的校验
因此TCP拼包,udp正确性校验是做网络通讯必不可少的步骤。
先接收sizeof(CMD_PACK_INFO)个字节?
重新设置BUF与LEN 这个要怎么设置呀 应该按什么来设置呢?
我的数据是一个包整体发过去了 是 命令+数据 再+上一些偏移什么的呢
如果可以的话 代码直接贴出来吧 那样更好理解
1). 取消MTU限制
2). 修改TCP协议栈默认窗口大小(window size)
3). 扩大发送和接收缓冲区3. 事实上,如果想好好地利用带宽而不受业务处理的影响,就是当WSARecv在GetQueuedCompletionStatus返回之后对接收数据的缓冲队列加锁,然后立即起发起WSARecv操作,然后再存到队列当中,如此就可以保证后面Recv到的数据受队列锁的限制而排到了后续,从而保证顺序,并且可以由多线程而达到更高的网络利用。4. 如果觉得这些还不够,那么就采用WSARecv的Routine模式,让所有的Recv完成操作排到同一个线程当中,如此你就针对某一个Socket保证全部WSARecv都在同一个线程当中发起即可,发起多个也不会影响到达的顺序,处理时采APC切换(SleepEx)。
要解决问题先从根本上解决问题.另一个是,我只能假定除了逻辑上面的问题,其它编码上你的代码是没有问题的,要不然问题就更难定位.完成端口说难也不难,说简单也不简单.之所以说不难,是因为它就那么几个函数,几个逻辑;说它难,是因为很多人被它的特性给套住其中,特别是其封性以及多个线程的并发性等导致了一些隐蔽性的问题.个人建议,对于初次使用的时候,先不要弄啥多线程,就一个线程处理GetQueuedCompletionStauts事件,并且所有需要发送的数据都通过PostQueuedCompletionStatus投递到该线程当中,并由该线程发起WSARecv操作等.先保证"流数据"的连续性和准确性,然后再解决报文边界问题,当这些问题解决了之后,再考虑使用多线程.特别要明白的是,对于单个连接在IOCP当中强加于同一个连接的并行Receive是没有太多性能提升的.重要的仍然在于处理,对于服务器程序则重点在于让多个连接产生高并发操作而提升网络IO能力.
你说的分片 我就是用内存映射来处理的
每次数据过来我都是有判断它的ID 然后再来处理它的
对几个api函数的理解不够!希望上面的帖子对楼主有所帮助!
{
int nCMD; //包命令
int nID; //包ID
int nPos; //包位移
short sDataSize; //包大小
}CMD_PACK_INFO, *LPCMD_PACK_INFO;