50分请教TCP/IP报文发送难题!谢谢先了!

iolife 2005-08-19 05:31:00
我有两台电脑(Win2000 Server with SP4 & Windows XP with SP2), 一台创建了CAsyncSocket 的派生类对象来监听端口, 另一台来连接,使用的是SOCK_STREAM(TCP/IP).

连接建立后, 尝试从服务器端向客户端发送一个文件. 每次发送报文大小68个字节。

现在问题是:
如果我把发送缓冲区设的过大(例如2048 bytes), 只发送了很少的数据后,send就返回-1,并且 CAsyncSocket::GetLastError() == WSAEWOULDBLOCK, 然后发送程序就在那里等待。但是,在几分钟后等待程序终止,并且CAsyncSocket::OnClose(int nErrorCode) 被调用,nErrorCode=0x2745. 我统计了总共发送出去的字节数,和接收端收到的字节数,然后相减, 然而大小,我发现结果要比发送缓冲区的尺寸要大。比如,发送缓冲区为2048B, 但相减的结构总是2108。

而如果发送缓冲区的尺寸小一点,比如256B, 那么文件就能正确传输,但是速度非常的慢 。下面是我的发送代码:

> void CTestSpeedDlg::OnBnClickedButton3()
> {
> int g_nOutSocketBufferSize = 256;
> ///////////////////////////////// --------------
> int package_size = 68;
> ///////////////////////////////// --------------
>
> g_sock.SetSockOpt(SO_SNDBUF, &g_nOutSocketBufferSize,
> sizeof(g_nOutSocketBufferSize)); ///////////////// ----------
> #if 1
> BOOL nodelay = 1;
> g_sock.SetSockOpt(TCP_NODELAY, &nodelay, sizeof(nodelay), IPPROTO_TCP);
> BOOL noroute = 1;
> g_sock.SetSockOpt(SO_DONTROUTE, &noroute, sizeof(noroute));
> #endif
>
> // browse file
> CFileDialog dlg(TRUE);
> if (dlg.DoModal() == IDOK)
> {
> CString path = dlg.GetPathName();
> // open file and transfer file
> CFile file(path, CFile::modeRead);
> int len = file.GetLength();
> BYTE* p = new BYTE[len];
> file.Read(p, len);
> file.Close();
>
> // now, transfer begins
> int n = 0;
> while (n < len)
> {
> int m = g_sock.Send(p + n, package_size);
> if (m != -1)
> {
> n += m;
>
> // log
> SYSTEMTIME st;
> ::GetLocalTime(&st);
> CString str;
> str.Format(_T("[%02d:%02d:%02d] send out %d"), st.wHour, st.wMinute,
> st.wSecond, m);
> g_list.AddString(str);
> g_list.UpdateWindow();
>
> // log
> str.Format(_T("%d"), n);
> g_edit.SetWindowText(str);
> g_edit.UpdateWindow();
> }
> else
> {
> int err = CAsyncSocket::GetLastError();
> if (err == WSAEWOULDBLOCK)
> {
> g_sock.m_bFree = false;
> // wait for socket free, uses message-pump
> MSG msg;
> while (true)
> {
> if (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
> {
> if (!::TranslateMessage(&msg)) ::DispatchMessage(&msg);
> }
> ::Sleep(5);
> if (g_sock.m_bFree)
> {
> break;
> }
> }
> }
> else
> {
> CString prompt;
> prompt.Format(_T("Socket Error : %08xh"), err);
> MessageBox(prompt);
> break;
> }
> }
> }
> delete []p;
> }
> }
>
>
下面是接收代码?
>
> void CDataSocket::OnReceive(int nErrorCode)
> {
> static int count = 0;
>
> BYTE buf[1024];
> if (nErrorCode == 0)
> {
> while (true) // read all data
> {
> int n = Receive(buf, 1024);
> if (n <= 0)
> {
> break;
> }
> else
> {
> SYSTEMTIME st;
> ::GetLocalTime(&st);
> // log
> CString str;
> str.Format(_T("[%02d:%02d:%02d] Received %d characters"), st.wHour,
> st.wMinute, st.wSecond, n);
> g_list.AddString(str);
>
> // log
> count += n;
> g_second_received_size += n;
>
> str.Format(_T("%d"), count);
> g_edit.SetWindowText(str);
> g_edit.UpdateWindow();
> }
> }
> }
> else
> {
> CString prompt;
> prompt.Format(_T("Socket Error, with OnReceive(%08xh)"), nErrorCode);
> MessageBox(NULL, prompt, _T("Socket Error"), MB_OK | MB_ICONSTOP);
> }
> }
>
>

非常诚恳的希望哪位朋友可以为我指点一二,或者共同讨论讨论,非常感谢!
...全文
162 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
iolife 2005-08-22
  • 打赏
  • 举报
回复
谢谢楼上的各位, 最后调试发现原来是因为端口号设的太大,网关对大端口号作了限制,呵呵
masterz 2005-08-20
  • 打赏
  • 举报
回复
Simple CAsyncSocket server and client
http://www.fruitfruit.com/vc/network/asyncsocket_test.cpp.txt
Practise_Think 2005-08-19
  • 打赏
  • 举报
回复
直接使用API会比用MFC的封装类会更好,更灵活!!
iolife 2005-08-19
  • 打赏
  • 举报
回复
楼上的各位,先说明一下,周末没空来测试这个,因此不能及时给大家发分,星期一再说啊, 先谢谢你们了!!!

另外,哪些朋友有好的想法或建议也可以继续讨论啊 :)
dirdirdir3 2005-08-19
  • 打赏
  • 举报
回复
BOOL nodelay = 1;
g_sock.SetSockOpt(TCP_NODELAY, &nodelay, sizeof(nodelay), IPPROTO_TCP);

你的传输应该没有粘包的问题,试试不要上面的这两句。
yzkzero 2005-08-19
  • 打赏
  • 举报
回复
在OnSend()里应该是这种形式:

while (已经发送数 < 需要发送数)
{
int dwBytes;

if ((dwBytes = Send((LPCTSTR)m_sendBuffer + 已经发送数,
需要发送数 - 已经发送数)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK) break;//继续接收
else
{
//这里是出错处理
}
}
else
{
已经发送数 += dwBytes;
}
}
if (已经发送数 == 需要发送数)
{
//发送完毕
}
CAsyncSocket::OnSend(nErrorCode);
yzkzero 2005-08-19
  • 打赏
  • 举报
回复
MFC的socket类从来不用,不太熟悉

CAsyncSocket::GetLastError() == WSAEWOULDBLOCK

估计是说明你的发送缓冲区满了,此时应该继续循环发送,除非返回SOCKET_ERROR且GetLastError()不是WSAEWOULDBLOCK才说明出错了。

请贴出OnSend()才能看出你的问题。

18,356

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 网络编程
c++c语言开发语言 技术论坛(原bbs)
社区管理员
  • 网络编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧