社区
网络编程
帖子详情
发送大数据量,是否要用CSocket?我用CAsyncSocket,当Client数据量大时,会循环Send,导致OnSend不停的触发,并且Server的OnReceive不停触发,接收不到数据。
ttnewday
2009-02-14 10:31:04
发送大数据量,是否要用CSocket?我用CAsyncSocket,当Client数据量大时,会循环Send,导致OnSend不停的触发,并且Server的OnReceive不停触发,接收不到数据。
...全文
335
12
打赏
收藏
发送大数据量,是否要用CSocket?我用CAsyncSocket,当Client数据量大时,会循环Send,导致OnSend不停的触发,并且Server的OnReceive不停触发,接收不到数据。
发送大数据量,是否要用CSocket?我用CAsyncSocket,当Client数据量大时,会循环Send,导致OnSend不停的触发,并且Server的OnReceive不停触发,接收不到数据。
复制链接
扫一扫
分享
转发到动态
举报
写回复
配置赞助广告
用AI写文章
12 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
ttnewday
2009-02-15
打赏
举报
回复
CAnsiMemFile 改为 CMemFile,编译才能通过的。
ttnewday
2009-02-15
打赏
举报
回复
怎样改都改不成正确的,Receive老是收不完正确的内容。帮忙看看哪里应该要修改。
m_send是stl的string,从其他地方对这个变量赋值;Server的接收内容放在C:\test.txt,需要事先在C盘建一个test.txt文件。
Client端:
OnSend:
void CCliOprSocket::OnSend(int nErrorCode)
{
CAnsiMemFile file;
file.Write(m_send.c_str(), m_send.length()+1);
file.SeekToBegin();
int len = 0;
BYTE* pByte = NULL;
int sendLength = file.GetLength();
int dataLength, cbLeftToSend;
BYTE* sendData = NULL;
dataLength = sendLength;
dataLength = htonl(dataLength);
cbLeftToSend = sizeof(dataLength);
/*发送内容长度*/
do
{
int cbBytesSent;
BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) - cbLeftToSend;
cbBytesSent = Send(bp, cbLeftToSend);
if(cbBytesSent == SOCKET_ERROR)
{
int iErr = ::GetLastError();
TRACE("客户端发送内容长度时出现sock错误。\n"
"已发送字节数:%d\n"
"上次错误:%d\n", cbBytesSent, iErr);
goto PreReturnCleanup;
}
cbLeftToSend -= cbBytesSent;
}
while(cbLeftToSend > 0);
sendData = new BYTE[SEND_BUFFER_SIZE];
cbLeftToSend = sendLength;
/*发送内容*/
do
{
int sendThisTime, doneSoFar, buffOffset;
sendThisTime = file.Read(sendData, SEND_BUFFER_SIZE);
buffOffset = 0;
do
{
doneSoFar = Send(sendData + buffOffset, sendThisTime);
if(doneSoFar == SOCKET_ERROR)
{
int iErr = ::GetLastError();
TRACE("客户端发送内容时出现sock错误。\n"
"已发送字节数:%d\n"
"上次错误:%d\n", doneSoFar, iErr);
goto PreReturnCleanup;
}
buffOffset += doneSoFar;
sendThisTime -= doneSoFar;
cbLeftToSend -= doneSoFar;
m_send.erase(0, doneSoFar);
}
while(sendThisTime > 0);
}
while(cbLeftToSend > 0);
PreReturnCleanup:
delete[] sendData;
file.Detach();
file.Close();
CAsyncSocket::OnSend(nErrorCode);
}
Server端:
OnReceive:
void CSrvOprSocket::OnReceive(int nErrorCode)
{
CAnsiMemFile file;
int len = 0;
BYTE* pByte = NULL;
CStdioFile f;
f.Open("C:\\test.txt", CStdioFile::modeReadWrite);
f.SeekToEnd();
int dataLength, cbBytesRet, cbLeftToReceive;
BYTE* recdData = NULL;
/*获取内容长度*/
cbLeftToReceive = sizeof(dataLength);
do
{
BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) - cbLeftToReceive;
cbBytesRet = Receive(bp, cbLeftToReceive);
if(cbBytesRet == SOCKET_ERROR || cbBytesRet == 0)
{
int iErr = ::GetLastError();
TRACE("服务端接收内容长度时出现socket错误。\n"
"\t接收字节数(0代表连接已关闭):%d\n"
"\t上次错误:%d\n", cbBytesRet, iErr);
goto PreReturnCleanup;
}
cbLeftToReceive -= cbBytesRet;
}
while(cbLeftToReceive > 0);
/*获取内容*/
dataLength = ntohl(dataLength);
recdData = new BYTE[RECV_BUFFER_SIZE];
cbLeftToReceive = dataLength;
do
{
int iGet, iRecd;
iGet = cbLeftToReceive < RECV_BUFFER_SIZE ? cbLeftToReceive : RECV_BUFFER_SIZE;
iRecd = Receive(recdData, iGet);
if(iRecd == SOCKET_ERROR || iRecd == 0)
{
int iErr = ::GetLastError();
TRACE("服务端接收内容时出现socket错误。\n"
"\t接收字节数(0代表连接已关闭):%d\n"
"\t上次错误:%d\n", cbBytesRet, iErr);
goto PreReturnCleanup;
}
file.Write(recdData, iRecd);
}
while(cbLeftToReceive > 0);
PreReturnCleanup:
len = file.GetLength();
//AfxMessageBox(CString(file.GetPtr()));
if(len>0)
{
pByte = file.Detach();
f.Write(pByte, len);
}
len = 0;
f.Close();
delete[] pByte;
delete[] recdData;
file.Close();
AsyncSelect(FD_READ);
CAsyncSocket::OnReceive(nErrorCode);
}
arong1234
2009-02-14
打赏
举报
回复
你的设计思想要完全改变才行,你不能指望在一次OnSend调用中把file内容完全发送出去。你需要一个内部数据结构保存你要发送的数据,在不同的OnSend调用中发送他
基本思想是:
1. 首先要建立一个队列,保存你需要发送的数据
2. 如果Socket当前处于阻塞状态,直接退出发送,等待下次OnSend
3. 循环发送队列中的消息,每次完全发送成功,则移出队列,如果只是部分成功,则记录这次发送成功到第几个字节。这样循环发送直到你遇到阻塞错误,一旦遇到WSAEWOULDBLOCK,立刻标记socket为阻塞状态,并退出OnSend,如果遇到其他错误,应该立刻关闭socket,重新建立socket,从头发送
第三步中OnSend会不停重复,直到你完全发送完成
至于每次发送的报文,由于报文必然会被网络分包,你必须在发送的开始告诉对方这个报文到底有多大,然后由服务端接收时根据长度信息,通过多次receive进行拼接
[Quote=引用 9 楼 ttnewday 的回复:]
Client的OnSend事件。
帮忙看看。
#define SEND_BUFFER_SIZE 4096
void CCliOprSocket::OnSend(int nErrorCode)
{
CMemFile file;
file.Write(m_send.GetBuffer(0)+'\0', m_send.GetLength()+1);
file.SeekToBegin();
int sendLength = file.GetLength();
int dataLength, cbLeftToSend;
BYTE* sendData = NULL;
dataLength = sendLength;
dataLength = htonl(dataLength);
cbLeftToSend = …
[/Quote]
ttnewday
2009-02-14
打赏
举报
回复
Client的OnSend事件。
帮忙看看。
#define SEND_BUFFER_SIZE 4096
void CCliOprSocket::OnSend(int nErrorCode)
{
CMemFile file;
file.Write(m_send.GetBuffer(0)+'\0', m_send.GetLength()+1);
file.SeekToBegin();
int sendLength = file.GetLength();
int dataLength, cbLeftToSend;
BYTE* sendData = NULL;
dataLength = sendLength;
dataLength = htonl(dataLength);
cbLeftToSend = sizeof(dataLength);
/*发送内容长度*/
do
{
int cbBytesSent;
BYTE* bp = (BYTE*)(&dataLength) + sizeof(dataLength) - cbLeftToSend;
cbBytesSent = Send(bp, cbLeftToSend);
if(cbBytesSent == SOCKET_ERROR)
{
int iErr = ::GetLastError();
TRACE("客户端发送内容长度时出现sock错误。\n"
"已发送字节数:%d\n"
"上次错误:%d\n", cbBytesSent, iErr);
goto PreReturnCleanup;
}
cbLeftToSend -= cbBytesSent;
}
while(cbLeftToSend > 0);
sendData = new BYTE[SEND_BUFFER_SIZE];
cbLeftToSend = sendLength;
/*发送内容*/
do
{
int sendThisTime, doneSoFar, buffOffset;
sendThisTime = file.Read(sendData, SEND_BUFFER_SIZE);
buffOffset = 0;
m_send.Delete(0, file.GetLength()>sendThisTime?sendThisTime:file.GetLength());
do
{
Sleep(20);
doneSoFar = Send(sendData + buffOffset, sendThisTime);
if(doneSoFar == SOCKET_ERROR)
{
int iErr = ::GetLastError();
TRACE("客户端发送内容时出现sock错误。\n"
"已发送字节数:%d\n"
"上次错误:%d\n", doneSoFar, iErr);
goto PreReturnCleanup;
}
buffOffset += doneSoFar;
sendThisTime -= doneSoFar;
cbLeftToSend -= doneSoFar;
}
while(sendThisTime > 0);
}
while(cbLeftToSend > 0);
PreReturnCleanup:
delete[] sendData;
file.Close();
CAsyncSocket::OnSend(nErrorCode);
}
arong1234
2009-02-14
打赏
举报
回复
这不是被覆盖了,而是TCP报文总是把大报文分成小报文发送的,你发送2k字节,可能你要分三次才能接收完整,这是著名的“粘包”问题。
[Quote=引用 6 楼 ttnewday 的回复:]
就是将大的文件分段发送,所以才不停的触发OnSend。
我把Server的OnReceive接收到的数据保存到文本里,不知为什么,就是接收不完全,可能少了次数,或者这次没收完,下次的已经来了,导致数据被覆盖了。
[/Quote]
arong1234
2009-02-14
打赏
举报
回复
你的问题在于:你用的是异步模型,但是使用模型的方法确实同步模型的循环发送,这当然是有严重问题的。异步模型要善用其中的事件,不能使用蛮力不停的循环发送
ttnewday
2009-02-14
打赏
举报
回复
就是将大的文件分段发送,所以才不停的触发OnSend。
我把Server的OnReceive接收到的数据保存到文本里,不知为什么,就是接收不完全,可能少了次数,或者这次没收完,下次的已经来了,导致数据被覆盖了。
arong1234
2009-02-14
打赏
举报
回复
谁告诉你要定义一个超大buffer的?即使你buffer再大也没有用啊?!socket报文最大也就1460字节
但是不让你一次发完也不是让你循环发送啊?!当你send已经发送失败时,你再坚持发送只是浪费时间和CPU,你应该在这个时候用一个数据结构(一般是队列)把你待发报文保存起来,等下次网络允许你发送时(也就是OnSend触发时)再发送,这适合应该再OnSend里进行发送
gwemail2003
2009-02-14
打赏
举报
回复
send时应设置缓冲区,将大的文件分段发送。
ttnewday
2009-02-14
打赏
举报
回复
Send有个buffer,我设了buffer大小为4096,所以超过4096的数据,就会分次Send了。
难道数据长度为10000时,buffer的大小也要设为10000?
好像buffer的长度有限制,我试过数据量很大时,大概有100K,buffer设了100*1024,但Server接收不到。
arong1234
2009-02-14
打赏
举报
回复
OnSend/OnReceive被触发是异步通讯的本质特征,不知道你为什么把他当作一个“异常问题”,为什么会因为这个原因要换CSocket.
arong1234
2009-02-14
打赏
举报
回复
Send不应该循环发,当你遇到Send发送失败,且GetLastError=WSAEWOULDBLOCK时,你应该停止发送,直到OnSend被触发,你再在OnSend里继续发
OnReceive被触发但是接收不到数据是异常的,他只在有数据时才被触发
MFC疑难注解:
CA
sync
Socket
及C
Socket
记得你的
Send
WSAEWOULDBLOCK了,待
发送
的
数据
会
写入
CA
sync
Socket
内部的
发送
缓冲区,并
会
在不忙的 时候自动调用On
Send
,
发送
内部缓冲区里的
数据
。 3、部分完成,0<
Send
(pBuf,nLen),
导致
这种情况的原因是,你的
发送
...
MFC
Socket
目 录 第1章 同步TCP通讯 1 1.1 同步通讯与异步通讯 1 1.2 同步通讯类 1 1.3 同步TCP通讯客户端 4 1.3.1 界面 4 1.3.2 界面类声明 4 1.3.3 界面类构造函数... 1.3.5 写
数据
异步
socket
相关的操作
在网络通讯的编程中我们经常使用到
Socket
, 这种情况下我们往往需要长期的监听某个端口, 以获得相应的
Socket
, 然后再利用它进行相关操作. 但是这样的话, 主线程就
会
被阻塞.无法对其他时间做出相应. 其实在.Net的...
MFC 网络编程
1. IP地址 2. 客户端/服务器模式 ...9.
CA
sync
Socket
与...用户可以使用 WSPSelect()函数注册感兴趣的事件,则当
接收
到相应的网络事件,系统
会
为程序
发送
事件通知,程序可以再根据自己的需要进行
数据
处理。...
c++面试题(网络通信篇)
当程序是要尽快地传输尽可能多的信息时,可以使用 UDP。TCP它是通过三次握手建立的连接,它在两个服务之间始终保持一个连接状态,目的就是为了提供可靠的
数据
传输。许多程序使用单独的TCP连接和单独的UDP连接,比如...
网络编程
18,356
社区成员
64,214
社区内容
发帖
与我相关
我的任务
网络编程
VC/MFC 网络编程
复制链接
扫一扫
分享
社区描述
VC/MFC 网络编程
c++
c语言
开发语言
技术论坛(原bbs)
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章