异步TCP Sokcet丢包的问题

facky904 2010-07-25 11:23:01
现在在做的项目用到了异步Socket,采用TCP
自己定义了一个结构体进行数据的封装和传输(这里简称 MyStr吧,目前大小是275字节)
服务器端程序有一个客户端Socket的列表(ClientList),存储联接进来的Socket
服务器只要接收到一个MyStr后,就会foreach访问ClientList里面的Socket把接收到的数据马上分发到其余的客户端,如下所示
foreach(SocketObject so in ClientList)
{
so.Sock.Send(sendBuf); //调用Socket的同步send方法
}
目前同时最多有16个客户端连接进服务器,就是接收到一次数据以后,会调用15次的Send来分发到其他客户端
对每一个从服务器分发出去的包添加了一个序列号,从1递增
客户端接收到包的时候会比较 本次接收的包的序列号 与 上一次接收到的包的序列号是否一递增1的关系,如果不是说明中间丢包了,就会要求服务器重发丢掉的包

测试过程发现有出现丢包的现象,通过重发能够解决

问题
1. 采用TCP Socket应该是可靠的连接,查了相关资料都说TCP保证不丢包,不用去关注这些,但是不保证接收端正确接收,请问这是什么意思。

2.上面我的那种情况是丢包吗?为什么会出现这种情况呢?

3.上面我的那种情况我发现好像是在通信比较频繁的时候会出现得比较多,是否和通信的频率有关

4.我这种回发的机制是不是 不是很好,是的话如何改进?

5.丢包(或者说是接收不正确)是否与缓冲区设置的大小有关?我用的是默认值8192
...全文
3474 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
hyblusea 2010-08-09
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 dancingbit 的回复:]
1.自己负责数据的正确性。
2.并不是一次Send就是一个包,你调用一次Send,TCP/IP协议栈并不一定就会立刻将数据发送出去,可能会进行数据的重组,导致你的多次发送被端重组为一次接收。
3.通信频率高的时候重组的可能性加大。
4.自己在接收数据后的缓冲区中进行检测,进行数据的重组。
5.TCP/IP自己有丢包重发的检测,不用你操心。
[/Quote]
+1

TCP是可靠传输,几乎不会存在丢包的, 不知道楼主判断丢包的标准是什么? 会不会是因为Socket将多个包组为一个包发送了? 如果你发送的包小于8K, Socket协议是有可能将多个包组为一个包发送, 所以接收端需要检查是否粘包
dancingbit 2010-08-09
  • 打赏
  • 举报
回复
至于说Connected,并不能及时准确地反映网络连接的情况,参考而已。
dancingbit 2010-08-09
  • 打赏
  • 举报
回复
TCP的数据可视作一个流,即使你把数据组织好,然后调用Send,但TCP并不一定立即就发送出去,有可能等到下一次Send甚至若干次Send之后才真正地从网络接口把数据发送出去,或许还存在底层的分片。而接收方在读这个流的时候,每次Receive的时候,都是读网络接口已经到达并且按照顺序重组好的分片,而分片的到达与重组我们无法预测无法控制,TCP只保证正确的顺序,你Receive就是从流中读取它能够提供给你的数据,然而与发送方的Send没有绝对对应关系。

假设,你调用两次Send,数据如下:
前导序号1 数据..........
前导序号2 数据..........
它真正发送的时候,有可能是按照你的组织形式发送的,也有可能是如下形式:
前导序号1 数据..........前导序号2 数据..........
甚至是:
前导序号1 数据..........前导序号2 数据..
........
任何一种形式都是有可能的,而接收方接收的形式就有更多的可能了。这种情况下,因为你找不到第二次Send的时候指定的序号,虽然数据已经接收到了,但你没有能够正确地提取,才有了你所谓的丢包问题。
facky904 2010-08-09
  • 打赏
  • 举报
回复
没有人帮顶吗?还有没有人能解答我的问题啊??
foreverpk 2010-08-09
  • 打赏
  • 举报
回复
提示一种计算的情况

比如你发送了3个包,分别是

11 11 11 11 11 11
22 22 22 22 22 22
33 33 33 33 33 33

如果你只是简单的一条一条的接受,有可能会接受到这样几个包

11 11 11 11 11 11 22 22
22 22 22 22 33 33
33 33 33 33
foreverpk 2010-08-09
  • 打赏
  • 举报
回复
1.tcp不会丢包,是说这边说发送成功的,那边就一定会收到了。网络故障会断掉,socket会有错误显示。接收端是否正确接受是指你的应用层是否处理好这些数据包

2.tcp会把你连续发的碎包顺序组合成一个大包发出,也会把一个大包拆分成顺序的小包发出。
你发出的不同包之间要有分割的方法。比如数据用Base64或其变形算法,包头包尾用一些标点符号分割就好。

3.上面2就是原因。

4.我感觉连接数不是很多,包也不是很碎时没问题。如果连接数很多,且包很碎。可能用线程控制好一些。
比如每100ms检查一次是否需要处理数据,然后就可以一次性处理5个包,只需要一次线程启动停止
而异步的情况可能会让你在100ms内进行5次的线程启动停止
每次线程启动和停止,都是需要花费一点点时间的,具体我忘记了,好像几毫秒。

5.和缓冲区没什么关系,如果你cpu负载过大,可能造成丢包重发。还有网络层的问题。比如路由符合过高,会主动把一些包丢掉,或者断掉一些连接。
facky904 2010-08-02
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 dancingbit 的回复:]
1.自己负责数据的正确性。
2.并不是一次Send就是一个包,你调用一次Send,TCP/IP协议栈并不一定就会立刻将数据发送出去,可能会进行数据的重组,导致你的多次发送被端重组为一次接收。
3.通信频率高的时候重组的可能性加大。
4.自己在接收数据后的缓冲区中进行检测,进行数据的重组。
5.TCP/IP自己有丢包重发的检测,不用你操心。
[/Quote]

谢谢dancingbit
我大只明白你的意思

我的服务端每一次调用send,都是发送一个struct,struct再发送前会先转换为byte,就是每次发送的字节数都是固定的,是我自定义的struct的大小。
客户端接收的时候(调用Beginreceive的时候buf的大小刚好是我自己定义的struct的大小),会偶尔出现漏接收了一个struct的情况,目前我只能给每个struct一个序号,+1递增,客户端每次接收到以后会和上一次接收到的struct的序号对比,如果是+1的关系就没错,否则要求服务器重发没有接收到的struct。

我想知道这种错误情况具体可能是怎么产生的呢,是跟你说的包重组有关吗?


还有一个问题
Socket的Conneted属性到底什么时候返回true,什么时候返回false
msdn的解释是:
如果 Socket 在最近操作时连接到远程资源,则为 true;否则为 false。
Connected 属性获取截止到最后的 I/O 操作时 Socket 的连接状态。当它返回 false 时,表明 Socket 要么从未连接,要么已断开连接。

我不是很明白。

到底在调用Socket的Send方法前要不要先判断Connected属性为true先,我发现当Connected未fasle,依然能够发送成功。但是我看网上的好多例子,都在发送前先判断一下if(Connected)
qiuxin425 2010-07-27
  • 打赏
  • 举报
回复
我也遇见TCP丢包的现象,是和我的机子的配置有关,不知道你那个是不是,可以换一个好点的试试。
你可以在read时判断一下包的大小,如果不够再read一下,知道达到你的长度,一般read一下就可以了,但不保证,可以用while循环一下即可。
dancingbit 2010-07-26
  • 打赏
  • 举报
回复
1.自己负责数据的正确性。
2.并不是一次Send就是一个包,你调用一次Send,TCP/IP协议栈并不一定就会立刻将数据发送出去,可能会进行数据的重组,导致你的多次发送被端重组为一次接收。
3.通信频率高的时候重组的可能性加大。
4.自己在接收数据后的缓冲区中进行检测,进行数据的重组。
5.TCP/IP自己有丢包重发的检测,不用你操心。
wangyue4 2010-07-26
  • 打赏
  • 举报
回复
tcp一般不会丢包,udp会有丢包现象。
你应该是每个连进服务器的客户端都应该有一个socket
服务器发送客户端要用其对应的socket去send()。
这样应该不会错的
cheng20100915 2010-07-26
  • 打赏
  • 举报
回复
哥们不懂,先帮你顶起来
josxhn 2010-07-26
  • 打赏
  • 举报
回复
纯粹帮顶
gxingmin 2010-07-26
  • 打赏
  • 举报
回复
tcp连接一般不会丢包,但数据有时候确实不能保证全部正确,所以传送数据时要加头尾等校验规则,接收时校验通过就认为是正确的

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

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