因为有比较大的数据需要传送,所以我采取把大数据拆分了发,先使用Send发送,遇到缓冲区满了后再使用Onsend继续发,但是每次总是在Send工作一会儿发了几匹数据包以后,Send返回WSAEWOULDBLOCK 后,就再也不触发OnSend消息了,真是百思不得其解,觉得CAsyncSocket问题太多了,难道是BUG?
部分发送代码如下
BOOL CClientSocket::SendCmd()
{
//如果缓冲区数据尚未发送完毕,直接返回
if(m_cSendBuffer.size() == 0)
return TRUE; CString strText;
strText.Format("Send发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
while (m_nBytesSent < m_cSendBuffer.size())
{
int dwBytes = Send(m_cSendBuffer.GetBuffer() + m_nBytesSent,
m_cSendBuffer.size() - m_nBytesSent);
int dwError = GetLastError(); strText.Format("Send发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
if (dwBytes == SOCKET_ERROR)
{
if (dwError == WSAEWOULDBLOCK) break;
else
{
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}
}
else
{
m_nBytesSent += dwBytes;
m_timeLast = CTime::GetCurrentTime();
}
}
if (m_nBytesSent >= m_cSendBuffer.size())
{
m_nBytesSent = 0;
m_cSendBuffer.clear(); strText.Format("Send发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
} return TRUE;
}void CClientSocket::OnSend(int nErrorCode)
{
CString strText;
strText.Format("OnSend发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); while (m_nBytesSent < m_cSendBuffer.size())
{
int dwBytes = Send(m_cSendBuffer.GetBuffer() + m_nBytesSent,
m_cSendBuffer.size() - m_nBytesSent);
int dwError = GetLastError();
strText.Format("OnSend发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); if (dwBytes == SOCKET_ERROR)
{
if (dwError == WSAEWOULDBLOCK) break;
else
{
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}
}
else
{
m_nBytesSent += dwBytes;
}
}
if (m_nBytesSent >= m_cSendBuffer.size())
{
m_nBytesSent = 0;
m_cSendBuffer.clear(); strText.Format("OnSend发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
}
m_timeLast = CTime::GetCurrentTime();
CAsyncSocket::OnSend(nErrorCode);
}这是记录的日志
2009-03-20 18:21:28.901 Send发送数据
2009-03-20 18:21:28.901 Send发送了-1个数据
2009-03-20 18:21:32.926 OnSend发送数据
2009-03-20 18:21:32.926 OnSend发送了58012个数据
2009-03-20 18:21:32.926 OnSend发送完毕
2009-03-20 18:21:33.097 Send发送数据
2009-03-20 18:21:33.097 Send发送了-1个数据
2009-03-20 18:23:07.362 OnSend发送数据
2009-03-20 18:23:07.362 OnSend发送了50056个数据
2009-03-20 18:23:07.362 OnSend发送完毕
2009-03-20 18:23:07.432 Send发送数据
2009-03-20 18:23:07.432 Send发送了-1个数据然后就再也收不到Onsend消息了。
部分发送代码如下
BOOL CClientSocket::SendCmd()
{
//如果缓冲区数据尚未发送完毕,直接返回
if(m_cSendBuffer.size() == 0)
return TRUE; CString strText;
strText.Format("Send发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
while (m_nBytesSent < m_cSendBuffer.size())
{
int dwBytes = Send(m_cSendBuffer.GetBuffer() + m_nBytesSent,
m_cSendBuffer.size() - m_nBytesSent);
int dwError = GetLastError(); strText.Format("Send发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
if (dwBytes == SOCKET_ERROR)
{
if (dwError == WSAEWOULDBLOCK) break;
else
{
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}
}
else
{
m_nBytesSent += dwBytes;
m_timeLast = CTime::GetCurrentTime();
}
}
if (m_nBytesSent >= m_cSendBuffer.size())
{
m_nBytesSent = 0;
m_cSendBuffer.clear(); strText.Format("Send发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
} return TRUE;
}void CClientSocket::OnSend(int nErrorCode)
{
CString strText;
strText.Format("OnSend发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); while (m_nBytesSent < m_cSendBuffer.size())
{
int dwBytes = Send(m_cSendBuffer.GetBuffer() + m_nBytesSent,
m_cSendBuffer.size() - m_nBytesSent);
int dwError = GetLastError();
strText.Format("OnSend发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); if (dwBytes == SOCKET_ERROR)
{
if (dwError == WSAEWOULDBLOCK) break;
else
{
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}
}
else
{
m_nBytesSent += dwBytes;
}
}
if (m_nBytesSent >= m_cSendBuffer.size())
{
m_nBytesSent = 0;
m_cSendBuffer.clear(); strText.Format("OnSend发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
}
m_timeLast = CTime::GetCurrentTime();
CAsyncSocket::OnSend(nErrorCode);
}这是记录的日志
2009-03-20 18:21:28.901 Send发送数据
2009-03-20 18:21:28.901 Send发送了-1个数据
2009-03-20 18:21:32.926 OnSend发送数据
2009-03-20 18:21:32.926 OnSend发送了58012个数据
2009-03-20 18:21:32.926 OnSend发送完毕
2009-03-20 18:21:33.097 Send发送数据
2009-03-20 18:21:33.097 Send发送了-1个数据
2009-03-20 18:23:07.362 OnSend发送数据
2009-03-20 18:23:07.362 OnSend发送了50056个数据
2009-03-20 18:23:07.362 OnSend发送完毕
2009-03-20 18:23:07.432 Send发送数据
2009-03-20 18:23:07.432 Send发送了-1个数据然后就再也收不到Onsend消息了。
解决方案 »
- 关于C++优缺点的讨论,新手老手都可以来看看,欢迎讨论补充
- 关于单文档CFormView的一个问题
- KeySwap这个软件是怎样实现改变按键的..或者大家有什么好的方法实现按键修改(在vc中)!!!![→→→→→→标题要长→→→→→→→→→→→]
- #define RUNTIME_CLASS(class_name) \ (&class_name::class##class_name)中的"\"是什么意思?
- 我想给自己的exe以及dll加密,请问大家都有什么办法
- 谁能解释一下这些代码的含义?
- 要写个锁屏工具
- 屏幕取词用的是什么技术?
- new了一个自己写的类对象,报链接错误,为什么
- 启动了SQL SERVER进行使用后,用VC#便不能做web应用程序,该如何重新配置IIS???
- 发送字节映射表,接收字节映射表是干什么用的?
- 高手们来帮帮小弟啊~真的想的头要暴了
这里不要break,可以换为
if (dwError == WSAEWOULDBLOCK) {Sleep(0);continue;}
BOOL CClientSocket::SendCmd()
{
while (m_nBytesSent < m_cSendBuffer.size())
{
int dwBytes = Send(...);
......
if (dwBytes == SOCKET_ERROR)
{
if (dwError == WSAEWOULDBLOCK)
{
//break;
Sleep(10) ; //把这里这样改下试试
continue; //把这里这样改下试试
}
else
{
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}
}
}
......
return TRUE;
}
void CClientSocket::OnSend(int nErrorCode)
{
CString strText;
strText.Format("OnSend发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);//调试的加上,以后可去掉,不用考察此函数
}
我这可是服务器端程序,需要给几百人服务的,按照楼上写法,能因为一个用户阻塞全部其他用户的服务?
如此说至少要用[重叠IO 完成例程]
最好用IOCP(完成端口)
增加一些信息,block后,程序在哪里阻塞了
1. 不要用while()循环, 因为Send()会触发OnSend(), 所以它已经有了内在的循环机制.
2. 对大数据,只要标记上次发送的结束位置,就可以做到分段发送了.
你程序现在的状态根本不是阻塞(专指sokcet阻塞,不是水龙头阻塞)的问题,这点我可以很负责任地告诉你。
你现在的问题是出错了,5L6L说了调试的2个办法
我给你加2点
把CAsyncSocket::OnSend(nErrorCode);//这行去掉,同时看下行
接收端只接收,不任何处理,把接收端处理数据发生错误的可能性排除,socket通常2端一起测的
10L 是说如果调试都没问题,可能问题出在这了
现在需要先知道消息循环是否正常,还有你的程序在执行了SendCmd之后还有没有其它操作。
我刚才把客户端由CAsyncSocket换成了CSocket,发现问题更严重了,接收服务器几个数据包后,就再也收不到OnReceive消息了,线程也没死,因为客户端发送给服务器的消息服务器还能够收到,MFC的消息机制,就是垃圾一个,没办法
错误的很明显的了.void CClientSocket::OnSend(int nErrorCode)
{
CString strText;
strText.Format("OnSend发送数据");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); while (m_nBytesSent < m_cSendBuffer.size())
{
int dwBytes = Send(m_cSendBuffer.GetBuffer() + m_nBytesSent,
m_cSendBuffer.size() - m_nBytesSent);
int dwError = GetLastError();
strText.Format("OnSend发送了%d个数据",dwBytes);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText); if (dwBytes == SOCKET_ERROR)
{
if (dwError == WSAEWOULDBLOCK) break;
else
{
strText.Format("Send发送出现错误%d",dwError);
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
break;
}
}
else
{
m_nBytesSent += dwBytes;
}
}
if (m_nBytesSent >= m_cSendBuffer.size())
{
m_nBytesSent = 0;
m_cSendBuffer.clear(); strText.Format("OnSend发送完毕");
LOG_DEBUG_INFO( g_strNetworkLogPath, strText);
}
m_timeLast = CTime::GetCurrentTime();
CAsyncSocket::OnSend(nErrorCode);
}
上面代码,
if (dwError == WSAEWOULDBLOCK)出现这样错误,程序已经告诉你系统缓冲区满,你不能再发送.但代码最后你又出来个CAsyncSocket::OnSend(nErrorCode);
出现缓冲区满的错误时,你是什么都不做,直接返回.然后等程序接收到FD_WRITE的消息,这是系统告诉你的程序,"缓冲区有空间了,你可经继续发送数据",这时侯才是你继续调用onsend()的时侯.
// CMyAsyncSocket is derived from CAsyncSocket and defines the
// following variables:
// CString m_sendBuffer; //for async send
// int m_nBytesSent;
// int m_nBytesBufferSize;void CMyAsyncSocket ::OnSend(int nErrorCode)
{
while (m_nBytesSent < m_nBytesBufferSize)
{
int dwBytes; if ((dwBytes = Send((LPCTSTR)m_sendBuffer + m_nBytesSent,
m_nBytesBufferSize - m_nBytesSent)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK) break;
else
{
TCHAR szError[256];
wsprintf(szError, "Server Socket failed to send: %d",
GetLastError());
Close();
AfxMessageBox (szError);
}
}
else
{
m_nBytesSent += dwBytes;
}
}
if (m_nBytesSent == m_nBytesBufferSize)
{
m_nBytesSent = m_nBytesBufferSize = 0;
m_sendBuffer = "";
}
CAsyncSocket::OnSend(nErrorCode);
}