还是关于send返回值的问题

qingfeng_happy2 2008-02-20 09:20:54
刚刚看过《windows 网络编程技术》,按照上面的说法,当调用send(sock,buf,nMax,0)发送长度为nMax的数据时,可能一次只能拷贝一部分数据len1,其长度len1<nMax,为了将所有的数据都拷贝完成,只能多次调用send发送。当再次调用send(sock,buf,nMax-len1,0)发送剩余的数据时,此时如果send返回socket_error,则说明拷贝失败,关闭套接字,那此时系统缓冲区中只有数据len1,下次我再调用send函数时,怎么才能将剩余的(nMax-len1)发送出去呢?

BOOL MySend(...)
{
int nMax=100
char Buff[nMax];
char *ptr=Buff;
...
...
while(nMax > 0)
{
int nLen = send(sock,ptr,nMax,0);
if(nLen==socket_error)
{
//发送错误
closesocket(sock);
return false;
}
nMax-=nLen;
ptr+= nLen ;
}
return ture;
}

在很多资料中都看到过,为了将数据发送出去,都是像上面那样操作的,可很奇怪,那些例子中都没有介绍过当调用send发送数据,一次没将缓冲区中的数据发送完,而接下来在继续发送剩余的数据时出现错误,该怎么处理剩余的未发送数据。还是这种情况并不会出现?但我想网络连接中断是无法预料的,应该有出现这种情况的可能。那当第二次调用send返回socket_error时,该怎么处理剩余数据?
在前一帖子中我一直以为当多次调用send发送nMax长度的数据过程中,当第一次拷贝一部分数据而第二次失败时,tcp为保证数据的完整性,会将已拷贝的len1长度数据丢弃,现在看来这种理解是错误的。
...全文
3421 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
Squall_zy 2010-05-11
  • 打赏
  • 举报
回复
一般,反送端都希望同步发送,而接收端都希望异步接收。

我对这个问题的理解是:

做一个同步发送的函数。内容大概为:

while( nLeft>0 )
{
WSASend(pBuf,nLeft,..,..);
if( WSAGetLastError() == WSAEWOULDBLOCK )
{
//等待 FD_WRITE 事件、或消息、或。。。。。
}
else
{
//返回失败或其他
}
}

其实,你去看看MFC的做法。看看CSocket类的Send()是如何处理的。相当牛啊。
int CSocket::Send(const void* lpBuf, int nBufLen, int nFlags)
{
if (m_pbBlocking != NULL)
{
WSASetLastError(WSAEINPROGRESS);
return FALSE;
}

int nLeft, nWritten;
PBYTE pBuf = (PBYTE)lpBuf;
nLeft = nBufLen;

while (nLeft > 0)
{
nWritten = SendChunk(pBuf, nLeft, nFlags);
if (nWritten == SOCKET_ERROR)
return nWritten;

nLeft -= nWritten;
pBuf += nWritten;
}
return nBufLen - nLeft;
}

int CSocket::SendChunk(const void* lpBuf, int nBufLen, int nFlags)
{
int nResult;
while ((nResult = CAsyncSocket::Send(lpBuf, nBufLen, nFlags)) == SOCKET_ERROR)
{
if (GetLastError() == WSAEWOULDBLOCK)
{
if (!PumpMessages(FD_WRITE))
return SOCKET_ERROR;
}
else
return SOCKET_ERROR;
}
return nResult;
}

BOOL CSocket::PumpMessages(UINT uStopFlag)
{
// The same socket better not be blocking in more than one place.
ASSERT(m_pbBlocking == NULL);

_AFX_SOCK_THREAD_STATE* pState = _afxSockThreadState;

ASSERT(pState->m_hSocketWindow != NULL);

BOOL bBlocking = TRUE;
m_pbBlocking = &bBlocking;
CWinThread* pThread = AfxGetThread();

// This is not a timeout in the WinSock sense, but more
// like a WM_KICKIDLE to keep message pumping alive
UINT_PTR nTimerID = ::SetTimer(pState->m_hSocketWindow, 1, m_nTimeOut, NULL);

if (nTimerID == 0)
AfxThrowResourceException();

BOOL bPeek = TRUE;

while (bBlocking)
{
TRY
{
MSG msg;
if (::PeekMessage(&msg, pState->m_hSocketWindow,
WM_SOCKET_NOTIFY, WM_SOCKET_DEAD, PM_REMOVE))
{
if (msg.message == WM_SOCKET_NOTIFY && (SOCKET)msg.wParam == m_hSocket)
{
if (WSAGETSELECTEVENT(msg.lParam) == FD_CLOSE)
{
break;
}
if (WSAGETSELECTEVENT(msg.lParam) == uStopFlag)
{
if (uStopFlag == FD_CONNECT)
m_nConnectError = WSAGETSELECTERROR(msg.lParam);
break;
}
}
if (msg.wParam != 0 || msg.lParam != 0)
CSocket::AuxQueueAdd(msg.message, msg.wParam, msg.lParam);

bPeek = TRUE;
}
else if (::PeekMessage(&msg, pState->m_hSocketWindow,
WM_TIMER, WM_TIMER, PM_REMOVE))
{
break;
}

if (bPeek && ::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
{
if (OnMessagePending())
{
// allow user-interface updates
ASSERT(pThread);
pThread->OnIdle(-1);
}
else
{
bPeek = FALSE;
}
}
else
{
// no work to do -- allow CPU to sleep
WaitMessage();
bPeek = TRUE;
}
}
CATCH_ALL(e)
{
TRACE(traceSocket, 0, "Error: caught exception in PumpMessage - continuing.\n");
DELETE_EXCEPTION(e);
bPeek = TRUE;
}
END_CATCH_ALL
}

::KillTimer(pState->m_hSocketWindow, nTimerID);

if (!bBlocking)
{
WSASetLastError(WSAEINTR);
return FALSE;
}
m_pbBlocking = NULL;

::PostMessage(pState->m_hSocketWindow, WM_SOCKET_NOTIFY, 0, 0);

return TRUE;
}
mrnian2008 2008-10-24
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 qingfeng_happy2 的回复:]
众说纷纭啊!
看过很多帖子,好像大家都没做这种处理,但我想当发送大量数据时还是可能会出现这种情况的。

哪位能不能给我个准信:当send第二次发送失败时,那第一次调用send拷贝到系统缓冲区中的数据会不会被丢弃?TCP不是有维护数据完整性的功能吗?(我倒是希望它丢弃:))
[/Quote]
用send(sock,ptr,nMax,0)会丢弃;
用send(sock,ptr,nMax,MSG_PEEK)则不会丢弃;
mrnian2008 2008-10-24
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 qingfeng_happy2 的回复:]
众说纷纭啊!
看过很多帖子,好像大家都没做这种处理,但我想当发送大量数据时还是可能会出现这种情况的。

哪位能不能给我个准信:当send第二次发送失败时,那第一次调用send拷贝到系统缓冲区中的数据会不会被丢弃?TCP不是有维护数据完整性的功能吗?(我倒是希望它丢弃:))
[/Quote]
用send(sock,ptr,nMax,0)会丢弃;
用send(sock,ptr,nMax,MSG_PEEK)则不会丢弃;
singing1001 2008-10-23
  • 打赏
  • 举报
回复
写的好像都不对,发送失败原因是很多的
flinming 2008-02-23
  • 打赏
  • 举报
回复
//////////////////////////////////////////////////////////////////////////
// 发送数据 //
// 返回值: -1 未连接 //
// -2 发送值超过最大 //
//////////////////////////////////////////////////////////////////////////
int Server_Socket_Send(SOCKET hSocket,char *m_Data,DWORD m_DataSize)
{
int m_LastError = 0;
int m_SendLeng = m_DataSize;

while (m_SendLeng > 0)
{
int m_Re = send(hSocket,m_Data,m_SendLeng,0);
if(m_Re > 0)
{
m_Data += m_Re;
m_SendLeng -= m_Re;
}
else if(m_Re == 0)//断开
{
m_LastError = WSAGetLastError();
OnSocketClose(hSocket,0);

return -1;
}
else if(m_Re == SOCKET_ERROR)
{
m_LastError = WSAGetLastError();
if(m_LastError != WSAEWOULDBLOCK)//不是正常数据阻塞,断开连接
{
OnSocketClose(hSocket,0);
return -2;
}
}
}

return m_DataSize;
}
qingfeng_happy2 2008-02-21
  • 打赏
  • 举报
回复
自己顶一下。
lwykj 2008-02-21
  • 打赏
  • 举报
回复
建议 看看 <<TCP/IP协议详解>>
lwykj 2008-02-21
  • 打赏
  • 举报
回复
tcp传输控制协议是一个 TCP/IP 组中能够实现可靠数据传送的传输层协议,并通过顺序响应能实现对应用程序的的虚拟连接服务,在必要的时候进行包转发。与 IP 协议相结合,TCP 代表了网络协议的核心。

  大多数网络应用程序是在相同的机器上运行的,计算机上必须能确保目的地的正确软件应用程序从源地址处获得数据包,以及源计算机上的正确应用程序的回复获得选择路经。这一过程是通过使用 TCP 的“端口号”完成的。网络IP地址和端口号的连接要达到唯一的标识,我们称之为“套接字”或“端点”。为了可靠通信,TCP 在端点间建立了连接或虚拟电路。

  TCP 服务提供了数据流传输、可靠行、有效流控制、全双工操作和多路复用技术等。

  关于数据流传输,TCP 发送一个由序列号定义的无结构的字节流。这对应用程序有利,因为在被送出 TCP 之前应用程序不需要划分成块,TCP 可以将字节整合成字段,然后发送给IP。

  TCP 是面向连接的端到端的可靠协议,并保证传送数据包的顺序,而顺序是用一个响应序号来保证的,这个响应序号告诉接收者发送者期望的下一个包。如果在规定时间内,没有收到关于这个包的确认响应,则需要重新发送此包。TCP 的可靠机制允许设备处理丢失、删除及读错的包。暂停机制允许设备监测丢失包并请求重发。

  TCP 提供了有效流控制。当向发送者返回发送确认响应,接收 TCP 进程就会暗示最高序列号,它能接收并保证不会发生溢出。

mr.zhoux 2008-02-21
  • 打赏
  • 举报
回复
没必要这么做,直接一次性发送完算了?

哪有那么好的事情。首先,中途出错是谁都无法避免的事情,也就是说,如果你传个很大的报文,几十次总会出现几次失败。
报文越大,中途出现socket_error的可能性越大。一个大报文如果中途断了,一般情况下都是必须从头开始传输的,分成小报文,即使重传也就是个小报文。



你发送完不会判断是否发送成功或者失败么?失败了ReSend ,这个道理都不懂? 有封装报文几M的么? 大的文件谁不会拆啊..晕


哪位能不能给我个准信:当send第二次发送失败时,那第一次调用send拷贝到系统缓冲区中的数据会不会被丢弃?TCP不是有维护数据完整性的功能吗?

你想多了,这点都不能保证的话程序员都用不着了.
qingfeng_happy2 2008-02-20
  • 打赏
  • 举报
回复
众说纷纭啊!
看过很多帖子,好像大家都没做这种处理,但我想当发送大量数据时还是可能会出现这种情况的。

哪位能不能给我个准信:当send第二次发送失败时,那第一次调用send拷贝到系统缓冲区中的数据会不会被丢弃?TCP不是有维护数据完整性的功能吗?(我倒是希望它丢弃:))
arong1234 2008-02-20
  • 打赏
  • 举报
回复
没必要这么做,直接一次性发送完算了?

哪有那么好的事情。首先,中途出错是谁都无法避免的事情,也就是说,如果你传个很大的报文,几十次总会出现几次失败。
报文越大,中途出现socket_error的可能性越大。一个大报文如果中途断了,一般情况下都是必须从头开始传输的,分成小报文,即使重传也就是个小报文。

在这种情况下,说“一次性发完就算了”是比较...的
qingfeng_happy2 2008-02-20
  • 打赏
  • 举报
回复
没必要这么做,直接一次性发送完算了.
/////
我也希望通过一个循环就将一组数据发送出去,就像我上面写的那样。只是我不清楚在循环发送过程中会不会出错,要是第一次发送就返回socket_error还好办,因为这组数据并没有被发送出去,我就担心在后续的发送过程中出错,那样子我发送出去的数据就不完整了,接受方接收到的数据也肯定是错误的。
究竟要不要考虑这种情况?
mr.zhoux 2008-02-20
  • 打赏
  • 举报
回复
一般情况下不需要做所谓的断点续传吧?要做就是将数据分成很多的小段比如10k,按照偏移量来分,记录发的片的位置比如发到第10个的时候失败了,下次再重新从第10个包发送起,接收也如此规律(协议)就好. 只是个方法.

没必要这么做,直接一次性发送完算了.
qingfeng_happy2 2008-02-20
  • 打赏
  • 举报
回复
那我在程序中怎么记录剩余的数据,并把它们保留起来,等待重新连接,再将它们发送出去?如果要是将这些剩余数据保存起来后,重新恢复连接的过程中应用程序关闭了,那岂不是这些数据就丢失了?这怎么办?
  • 打赏
  • 举报
回复
通常发送失败之后需要在重新连接
你只需要知道,你还要发的数据,然后发送就可以了,再说很多时候断开的话只能从头发

18,356

社区成员

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

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