c# Socket Send Receive 边界问题?求高手解决!

peenyking 2011-12-09 02:52:37
在Socket 通信中
接收端接到第一个数据包的时候, 如果处理时间稍微长了一点。
当还在处理第一个消息的时候, 发送端又连续发送了两个数据包过来, 我把每个包设置不会大于1500, 也就是有可能数据包小于1500 但不会大于1500.

当出现这种情况的时候, 如果第一个包大小为1000, 没问题
但是如果第二个包小于1500, 例如1200, 第三个包 就随便多大,只是不大于1500,
当接收到 通过socket.Receive 接收的时候, 就把第二个和第三个合并了, 所以接收的时候, socket.Receive返回的是1500

而不是发送端 发送的1200

也就是他自己把第二个包和第三个包合并成了两个包了
成了: 第一个1500, 第二个 就成了本来的大小+(1500- 1200)了

问题好像是 socket发送的时候 没有定义界限, 所以系统合包了。

请问谁知道解决?
...全文
2790 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
peenyking 2011-12-09
  • 打赏
  • 举报
回复
唉 使用填包算了。。。。
纵横宇宙 2011-12-09
  • 打赏
  • 举报
回复
直接序列化到网络流过去,非常的方便
peenyking 2011-12-09
  • 打赏
  • 举报
回复
没有通过流传输, 直接send
1500是我自己定义的, 我把需要发送的对象, 拆成一个或多个包(包大小 最大1500)。

我看了发送的记录, 第一次发送1200, 第二次发送1300, 第三次发送1000,(发送三次是连续发送)
在这种情况下,如果在接收了第一个包 1200 后, 被断点阻塞了, 没有运行到revice上,等运行到那的时候,接受就成了1500,而且 也就收了两次。后一个就是1300+1000-1500 的大小。
Bullatus 2011-12-09
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 peenyking 的回复:]

但是这样满足不了我的需求了, 这个程序需要处理多客户端段。
你说的那种方法,把一份数据发了两个包, 一个是长度, 一个是数据本身。
但是 这样可能会在多客户端选出现问题。 可能在这两个包接收的时候, 有另外一个客户端插包进来。
那就是还要给每个包设置id。

其实我这个已经为每个包都设置了id和序列号,因为把一个对象拆包,可能是一个包也可能是多个包,而且又是客户端, 所以我都……
[/Quote]
你的数据是基于TCP协议发送的吗?
连接后通过流传输不会出现你说的那种现象,而且这并不是两个包……那1500字节也不一定被分成几个包了。
建议好好看看网络协议和.NET的网络传输。
peenyking 2011-12-09
  • 打赏
  • 举报
回复
我现在是 客户端发送消息给服务器的时候, 服务器和客户端都会产生一个socket, 而且都循环监听这个socket
这样客户端就不用使用新的端口来监听了
而且发送的时候 也可以通过这个socket来发送

所以 socket 一直是处于连接的。
peenyking 2011-12-09
  • 打赏
  • 举报
回复
但是这样满足不了我的需求了, 这个程序需要处理多客户端段。
你说的那种方法,把一份数据发了两个包, 一个是长度, 一个是数据本身。
但是 这样可能会在多客户端选出现问题。 可能在这两个包接收的时候, 有另外一个客户端插包进来。
那就是还要给每个包设置id。

其实我这个已经为每个包都设置了id和序列号,因为把一个对象拆包,可能是一个包也可能是多个包,而且又是客户端, 所以我都把包处理成最大1500的长度,不足1500的 按实际情况设置包大小。

可是现在出现了 socket 自动给我拆包了拼包, 把我本身完整的包拆乱了。 所以就是想看看 能不能在同一的传输模式的情况下, 不出现socket自动拆拼包, 而是按照我的来?
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 peenyking 的回复:]

引用 6 楼 chromev8 的回复:
据我所知,1500个字节,并非是由你来控制的。而是由于存在MTU的缘故。所以这个根本不用去控制。

你认为你一次发送的字节都会被接收端完整收到,这种想法是多数新手的误区。

你二次发送的数据可能会被接收端一次全部收到。
或者你一次发送的数据可能会被接收端分多次收到。



所以我就是想 让他实现 发一次 收一次哦
[/Quote]

可以这样做,发送端发送完成数据后,就关闭socket连接就可以了,就像http通讯一样。
接收端,你一直读,直到读到-1时,就知道发送端关闭了。
Bullatus 2011-12-09
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 peenyking 的回复:]

引用 3 楼 bunliney 的回复:
引用 2 楼 peenyking 的回复:

Socket.Send(buffers[i], 0, buffers[i].Length, SocketFlags.None);

调这个方法, 第三个参数就是指定发送字节数组长度了吧。 但是没用

不是这样的。
试试这么做

C# code

Socket.Send(BitConve……
[/Quote]
你用我的这个方法绝对不会合并包啊
Bullatus 2011-12-09
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 peenyking 的回复:]

msdn 上说 new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
SocketType.Stream 不会给包分界线, 所以我怀疑就是因为没有界线 所以接受的时候,如果服务器挂住一下会儿没有receive,当一次接受两个包时才会合包。
[/Quote]
通过流长度来判断接收的,只可能带来杯具的结果
peenyking 2011-12-09
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 chromev8 的回复:]
据我所知,1500个字节,并非是由你来控制的。而是由于存在MTU的缘故。所以这个根本不用去控制。

你认为你一次发送的字节都会被接收端完整收到,这种想法是多数新手的误区。

你二次发送的数据可能会被接收端一次全部收到。
或者你一次发送的数据可能会被接收端分多次收到。
[/Quote]


所以我就是想 让他实现 发一次 收一次哦
  • 打赏
  • 举报
回复
据我所知,1500个字节,并非是由你来控制的。而是由于存在MTU的缘故。所以这个根本不用去控制。

你认为你一次发送的字节都会被接收端完整收到,这种想法是多数新手的误区。

你二次发送的数据可能会被接收端一次全部收到。
或者你一次发送的数据可能会被接收端分多次收到。

peenyking 2011-12-09
  • 打赏
  • 举报
回复
msdn 上说 new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp );
SocketType.Stream 不会给包分界线, 所以我怀疑就是因为没有界线 所以接受的时候,如果服务器挂住一下会儿没有receive,当一次接受两个包时才会合包。
peenyking 2011-12-09
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 bunliney 的回复:]
引用 2 楼 peenyking 的回复:

Socket.Send(buffers[i], 0, buffers[i].Length, SocketFlags.None);

调这个方法, 第三个参数就是指定发送字节数组长度了吧。 但是没用

不是这样的。
试试这么做

C# code

Socket.Send(BitConvert.ToInt16((short)buffe……
[/Quote]


我这个要处理多客户端的,而且 我已经为每个数据包都编了号的, 但是现在socket 自动给我合包了, 所以 我在处理的时候, 还得先把接受到的包 重新拆包,然后再拼包。 这样就很麻烦了。
所以我就是看看 能不能在 使用tcp 传输的情况下, 每次客户端发送包, 服务器接受的时候,不会合并包。。
Bullatus 2011-12-09
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 peenyking 的回复:]

Socket.Send(buffers[i], 0, buffers[i].Length, SocketFlags.None);

调这个方法, 第三个参数就是指定发送字节数组长度了吧。 但是没用
[/Quote]
不是这样的。
试试这么做
Socket.Send(BitConvert.ToInt16((short)buffers[i].Length), 0, 2, SocketFlags.None);
Socket.Send(buffers[i], 0, buffers[i].Length, SocketFlags.None);

这样,在发送实际数据之前,先传送了2个字节表示该次传输的长度。
在接收时,先接收两个字节,然后将这两个字节转回short,就可以知道之后的数据有多长了。
peenyking 2011-12-09
  • 打赏
  • 举报
回复
Socket.Send(buffers[i], 0, buffers[i].Length, SocketFlags.None);

调这个方法, 第三个参数就是指定发送字节数组长度了吧。 但是没用
Bullatus 2011-12-09
  • 打赏
  • 举报
回复
这种情况,我给你的建议是,在每个包的前发送该包的完整长度,这样就不会被合并了。
至于长度的发送,既然你每个包都小于1500,可以用2个字节表示(比如short转成的byte[])

110,500

社区成员

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

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

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