如何让客户端知道服务器真正接收成功(Socket TCP) ACK? 本帖最后由 VisualEleven 于 2010-12-27 14:34:04 编辑 解决方案 » 免费领取超大流量手机卡,每月29元包185G流量+100分钟通话, 中国电信官方发货 还加一个问题 服务器有静态IP 外网,内网IP 如 192.168.2..... 服务器接收时要怎么才能知道是内网的哪个IP发来的数据??? connect成功 是成功了的,Send 也是成功了的,你原来也说过,send 返回成功,并不代表服务器接收成功 ACK?这个底层已经做了。 3次握手你不需要关心。 客户端如果发送出去了, 一般服务器就接收到了。 除非发送失败 connect成功,就表示服务器accept了连接了,send成功是表示将要发送的数据copy到系统发送缓冲区剩余的空间中,然后协议稍后才将数据发送 你的客户端是用外网IP链接的,那服务器获得的就是外网IP;客户端用内网IP链接的,服务器获得的就是内网IP 我做了测试的,客户端是发送成功的,服务器,Recv的时候是失败.而且是阻塞方式.开的一个单线程做接收 嗯,是的,你原来说服务器发一个ACK包回来,怎么发? 一般.. 那说明服务器还是有可能会接收失败的,同时有可能会有1000个并发的Send 给服务器. 对。如果是重要的控制信令,可以在应用层回传确认。如果是传输数据,可以在应用层做CRC校验。 如果是重要的控制信令,可以在应用层回传确认。如果是传输数据,可以在应用层做CRC校验。如何实现?还是用Send Recv吗? 对,就用send/recv 相当于在应用层自己搞一个协议来确认 就是发一个 if(SOCKET_ERROR==recv(sockConn,recvBuf,1000,0)) { TRACE("失败原因是=%s \n",GetLastError()); TRACE("失败!%d\n",htons(addrClient.sin_port)); if(SOCKET_ERROR==send(sockConn,"服务器接收失败",strlen("服务器接收失败")+1,0)) { pParam->m_ListError.InsertItem(0,"服务器接收请求失败 返回客户端 发送失败\n"); } else { pParam->m_ListError.InsertItem(0,"服务器接收失败 返回客户端 发送成功\n"); } } else//接收成功 {.................................是不是这样?如果服务器告知,客户端,即色部分.那是不是客户端又得问服务器有没有成功接收呢?那不是一需要一个循环来做双方是否接收成功? 你可以仿造TCP的重传机制做一个发送队列,每个数据包都有个编号,如果接收方回传了编号就说明发送成功了,否则超时了就重发。当然还可以进一步改进。 还是有传输不完整的,定时检查,好像有点不现实,数据太多,客户端也很多.服务器给了客户端数据,客户端一定要成功的把结果返回给服务器.试验了近一个月没有一个完美的解决方案.....ACK返回客户端如何接收?如果客户端没收到就重新发.多长时间重新发?会不会重复? 上面说了一大堆的东西,就看了3条.按照我的思路给你说一下.首先connect成功表示3次握手成功了send成功返回,正常情况下(SO_SNDBUF不为0)表示数据被投递到了发送缓冲,此时并不意味着已经发送给了服务端,并且回应ACK了,何时真正发送过去,你并不知道,因为TCP都一套控制机制.如果发送缓冲区为0,那么send返回,表明你的数据确实已经发送到了服务端上,并且它已经回应了ACK,你也成功确认了,但一般来说不会把发送缓冲设置为0,除非有特殊需求.因此你如果想确定服务端已经收到,最好的方式是通过你的应用级别,进行确认,也就是一旦你发送了某个指令,则必须服务端回发一个数据给你,表示确认成功. 现在是,Send数据后就等待 if(SOCKET_ERROR==recv(sockClientResult,recvBuf,1000,0)) 有一个问题,如果服务器Send回来的数据客户端并没有recv 即上面的 服务器端send失败.当然此处说的失败,不是程序已经知道send失败,send成功不一定就客户端就收到了Recv会一直等待.造成线程一直等待 recv怎么让它超时,如果没有超时的设定,线程里很容易一直recv处等待服务器返回 服务器接收成功的确定信息 是不可能做这个确认的:客户端只能确认自己的消息是成功发出去 但是服务器是否收到客户端是无法得知的如果客户端需要服务端告诉自己收到了前面那个消息 那服务端又怎么知道自己send成功后客户端是否收到呢?关于这个可以看个小故事:http://blogold.chinaunix.net/u3/114095/showart_2343652.html 就是如果客户端recv一直等待到一定时间后就失败。又重新发送数据到服务器。服务器也可以判断是否是重复数据。一直到发送成功为止这样好像效率并不高。。有其它更保险的方法吗? 在应用层上实现:和服务端确定在收到客户端的一定消息后需要发回相应的确认,这个时候客户端再去recv这个信息就可以了这样就可以让客户端确认服务端收到了这个消息 上面我已经把原理说了一遍,不知道你有没仔细看.你如果要超时:1.使用setsockopt的SO_RCVTIMEO选项,在recv前设置,具体查MSDN,它只对阻塞有效.2.使用select模型,里面有超时参数可以设置,查MSDN3.使用异步IO模型,如大家常喜欢说的IOCP模型,就不会有阻塞问题了. 服务器不知道内网IP。之所以内网和服务器能通讯,因为在内网网关上做了NAT。 这个已经解决,只需要把自己的IP传到服务器就知道内网IP了 用了一个工具 进程加速 请大家帮忙 关于用MFC如何实现停止,继续和分部执行按钮 一个关于数据类型的问题,郁闷了我一个晚上,请教各位。 弱弱的问:如何清除picturebox里的图像啊? CDib的问题 在VC中如何实现哈希表操作数据库? 在VC里怎样能注册一个自己定义的新类呢? SOS !!!! 送分。 (UP有分) ado的返回记录集问题 我水,我可以问。大家快来呀! 这样的网络程序怎样写?(急需) 任务栏闪烁的不解
客户端如果发送出去了, 一般服务器就接收到了。 除非发送失败
嗯,是的,你原来说服务器发一个ACK包回来,怎么发?
对。
如果是重要的控制信令,可以在应用层回传确认。
如果是传输数据,可以在应用层做CRC校验。
如果是传输数据,可以在应用层做CRC校验。如何实现?还是用Send Recv吗?
对,就用send/recv 相当于在应用层自己搞一个协议来确认
就是发一个 if(SOCKET_ERROR==recv(sockConn,recvBuf,1000,0))
{
TRACE("失败原因是=%s \n",GetLastError());
TRACE("失败!%d\n",htons(addrClient.sin_port));
if(SOCKET_ERROR==send(sockConn,"服务器接收失败",strlen("服务器接收失败")+1,0))
{
pParam->m_ListError.InsertItem(0,"服务器接收请求失败 返回客户端 发送失败\n");
} else
{
pParam->m_ListError.InsertItem(0,"服务器接收失败 返回客户端 发送成功\n");
}
}
else//接收成功
{
.................................是不是这样?如果服务器告知,客户端,即色部分.那是不是客户端又得问服务器有没有成功接收呢?那不是一需要一个循环来做双方是否接收成功?
你可以仿造TCP的重传机制做一个发送队列,每个数据包都有个编号,如果接收方回传了编号就说明发送成功了,否则超时了就重发。当然还可以进一步改进。
send成功返回,正常情况下(SO_SNDBUF不为0)表示数据被投递到了发送缓冲,此时并不意味着已经发送给了服务端,并且回应ACK了,何时真正发送过去,你并不知道,因为TCP都一套控制机制.如果发送缓冲区为0,那么send返回,表明你的数据确实已经发送到了服务端上,并且它已经回应了ACK,你也成功确认了,但一般来说不会把发送缓冲设置为0,除非有特殊需求.
因此你如果想确定服务端已经收到,最好的方式是通过你的应用级别,进行确认,也就是一旦你发送了某个指令,则必须服务端回发一个数据给你,表示确认成功.
if(SOCKET_ERROR==recv(sockClientResult,recvBuf,1000,0))
有一个问题,如果服务器Send回来的数据客户端并没有recv 即上面的
服务器端send失败.当然此处说的失败,不是程序已经知道send失败,send成功不一定就客户端就收到了
Recv会一直等待.造成线程一直等待
客户端只能确认自己的消息是成功发出去 但是服务器是否收到客户端是无法得知的
如果客户端需要服务端告诉自己收到了前面那个消息 那服务端又怎么知道自己send成功后客户端是否收到呢?
关于这个可以看个小故事:
http://blogold.chinaunix.net/u3/114095/showart_2343652.html
和服务端确定在收到客户端的一定消息后需要发回相应的确认,这个时候客户端再去recv这个信息就可以了
这样就可以让客户端确认服务端收到了这个消息
你如果要超时:1.使用setsockopt的SO_RCVTIMEO选项,在recv前设置,具体查MSDN,它只对阻塞有效.
2.使用select模型,里面有超时参数可以设置,查MSDN
3.使用异步IO模型,如大家常喜欢说的IOCP模型,就不会有阻塞问题了.
服务器不知道内网IP。之所以内网和服务器能通讯,因为在内网网关上做了NAT。
这个已经解决,只需要把自己的IP传到服务器就知道内网IP了