导航:
论坛 -> 网络通讯
斑竹:liumazi,sephil
作者:
2022/9/18 12:48:34
标题:
Windows socket 半包 顺序错位 求助!
浏览:1793
加入我的收藏
楼主:
我在delphi 发送一个长包到c++ 服务端程序在api接口拿到了 半包+顺序错乱 发送 起始符HelloWorld结束符号 接收 World结束符号 起始符Hello 如此顺序错位了该怎么解决呢?? 单机测试 偶尔会出现这种情况 服务端放网~络上 几乎十次 没出一次。 搜索 也没看到关于 长包达到顺序不一样的说法。。。。(难道我用错关键词了?)
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/9/19 0:36:38
1楼:
TCP ? 如果是 TCP 出现这样的情况是不可能的,唯一可能是应用层代码本身有 BUG。 这个 BUG 也许是 Delphi 这边的,也许是 C++ 那边的。 如果是 UDP,一个包就是一个包,包如果错误了,基本上应用层会收不到,也就是丢包。收到的,基本上不会错。 如果是 TCP,就没有包的概念,长包是个什么鬼?
----------------------------------------------
-
作者:
2022/9/19 5:37:35
2楼:
TCP 与 UDP 都是一个一个包的. TCP 包头资讯多很多, 因此所载包内资料较少, 传送时会互相沟通检测错误与处理掉包等问题, 资料还原有可靠性. UDP 包头资讯简单, 所载包内资料也就多了, 没有什么检测也不怎沟通, 错误与掉包发生了就算, 适合那些高流量富时间性但错了就算的工作, 例如直播源.
----------------------------------------------
-
作者:
2022/9/19 5:45:14
3楼:
UDP 本身不会为包包作排序, 在互联网的工作原理上, 每一个包的传送时间受多种因素所干扰. 如果码奴采用 UDP, 那就要自己为排序错误编写自己的处理方式. 当然, 楼主发生什么问题, 本人是不了解.
----------------------------------------------
-
作者:
2022/9/19 7:13:16
4楼:
说得随便过了, UDP 也有包内的检测码的.
----------------------------------------------
-
作者:
2022/9/19 11:25:13
5楼:
delphi 端 send(FSocket, Buf, Count, 0); 打印 buf: 起始符HelloWorld结束符号 c++端 char recvBuff[8192] = ""; int ret = Recv(recvBuff, 8190, 0);//这里用8190 没问题吧? 打印 recvBuff: 1. World结束符号 2. 起始符Hello Recv 2次后才得到 1 2 但是顺序反了。。。。。 而且是随机发生 并非100% 出现。。。。。。 就很奇怪 不然也不开帖子问了。
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/9/19 11:42:21
6楼:
FSocket是怎么初始化的? 印象中应该是socket()函数的参数怎么给的. 个人以往的经验是总使用有数据包头哪怕只有一个network int32长度的头来指定数据长度并且拆分比较大的包.
----------------------------------------------
-
作者:
2022/9/19 14:04:04
7楼:
再次说一下,TCP 没有包的概念。千万不要以为 TCP 有包的概念。 TCP 底下的 IP 层,是一个一个的 IP 包。但 TCP 是在 IP 层之上,对于使用 TCP 的应用层来说,TCP 把 IP 包完全封装了,不需要知道 IP 包。对应用层来说,TCP 就是流,一个你想多大就多大的流。
----------------------------------------------
-
作者:
2022/9/19 14:05:58
8楼:
5 楼,你的问题是,你直接用 WinSock,这个默认是异步的。 你是想异步,还是想同步? 如果是同步模式,顺序就不会错。如果是异步,那就不好说了。 这个就是【同步】和 【异步】这两个单词的真正意思。
----------------------------------------------
-
作者:
2022/9/20 9:47:52
9楼:
感谢答复。 目前用 sendStream 方法解决问题 观察下来 还没出问题。 虽然没有达到 6楼: 说的应用层 每个包 带 包信息 也算是自动拆长包分批次发送了 8楼: 不是很明白异步同步 代码是 select(搜索了下名看到有说这个是异步??) 如果还有问题我就上开源的diocp算了。
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/9/20 10:53:17
10楼:
这个和 diocp 有啥关系?IOCP 说的是服务器端。你现在做的是客户端。你的服务器端是你说的 C++ 的代码。 如果是 TCP,你完全没有必要把一个100M 的数据拆成 1M 一个包,还给每个包加上包头信息,除非你有其它的业务还要在同一个 TCP 上跑。 看看 FTP 的协议吧。传一个大文件几百M,也就是一个 TCP 流。哪里有包的概念?
----------------------------------------------
-
作者:
2022/9/20 11:21:02
11楼:
delphi 端是服务端 c++是客户端 在delphi返回给客户端的时候 超常 包(流)会乱序 。 现在用 sendStream 让他自己拆了去发。
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/9/20 11:33:35
12楼:
Delphi 是服务器端,如果使用 TCP 发送,那也同样没有问题。是不是 IOCP 没关系。 这个是 TCP 协议决定的,由操作系统的 TCP/IP 协议栈的代码执行,不是你的应用层代码决定的。 你发送流也好,发送字节也好,都一样。至于【拆包】,这个不是你要考虑的,也不是应用层代码管得到的。对于应用层代码来说,你发送的就是个字节流,不管你用什么函数,函数的参数是 TStream 还是 TBytes 还是一个 Buffer 的指针。 所以,如果接收端出现所谓的【乱序】,其实是接收端自己没处理好异步的问题导致的。 所谓同步,就是程序按顺序执行,那就不会出现乱序。 所谓异步,就是程序有多个线程在同时运行,多个线程之间,哪个线程跑到了前面,没法确定也没法预测。 所以,你可以试试,接收端你用 Indy 的 TCP 控件来写,这个玩意是同步的。你可以每次只收 1 个字节,也可以每次收4个字节或者随便多少个字节,把每次收到的字节按接收端顺序摆一起,肯定不会乱。因为它是同步的代码,顺序执行的。
----------------------------------------------
-
作者:
2022/9/20 14:04:54
13楼:
12楼: c++那边用的一个第三方lib 回头看看吧。。
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/9/30 19:58:35
14楼:
问题很久没重现了,确定的是在软件层拆包导致出现这个问题。 @pcplayer @pp0123 @newbuyer
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/10/1 14:58:42
15楼:
TCP不存在包,TCP链接是一个数据流,在逻辑上,TCP链接每次收发以1个字节为单位,如果你假定一次收发的数据大小多于一个字节,后果自负,操作系统和硬件都不会给你保证不出问题。
----------------------------------------------
-
作者:
2022/10/2 11:42:23
16楼:
15 楼,我在本群科普 TCP 是流不是包,已经很多回了。可惜大家就是没看见。
----------------------------------------------
-
作者:
2022/10/2 12:21:08
17楼:
顺便复习一下 TCP 挺好的
----------------------------------------------
-
作者:
2022/10/4 17:21:36
18楼:
tcp 是流不是包,串口数据也是流不是包。所有的流你在处理的时候都应该假设会在任意一个字节触发你的接收处理程序,而不会自动等到接收完成。 UDP是虽然是包,但不保证顺序,也不保证包内的内容。 为什么我一听到“分包”这个词我就头大,无论是串口还是TCP还是其它。 “分包”、“粘包”这样的词都是怎么来的?这些本不应该出现的词。 楼主真的找到症结所在了吗?你用sendstream实现上是TCP给你实现了一个简单的流处理,所以不出错了。 就像UDP虽然不保证无错,但是在网——络条件很好的情况下,出现错误的概率极低,虽然有的程序代码并没有处理,但也工作得很好,但这并不表示代码这样做就是正确的。而在讨论中不断的出现“分包”、“粘包”这样的词的代码中,多半是有隐患的。
----------------------------------------------
我和我追逐的梦,擦肩而过
作者:
2022/10/4 19:12:09
19楼:
to 18楼: 好吧, 应用层的包 进入tcp字节流 。 4K长度 转由 sendstream 发送 。 该问题 目前未再重现。 可能为了给出解决方法学名关键词这么定义了?
此帖子包含附件: 大小: 143.4K
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/10/5 2:09:24
20楼:
18 楼说得非常对。 19 楼的图示,我不管你的图里面的内容,如果是用 TCP,你还在【沾包】,那就是一定还没搞懂 TCP。没搞懂的情况下写的代码,正如 18 楼所说,有隐患。 做应用层的程序,只要你是使用 TCP,不管用什么语言,不管代码怎么写,没有包的概念,当然也就不存在沾包的概念。 如果你以为有包,接收端还要【沾包】,那你的代码一定是错误的。 如果非要说有【包】,那么,TCP 的一个包,就是一个字节。 如果你非要【沾包】,那就是收到一个字节,就和前面的字节凑一起。凑齐了你要的数据长度,就是把 N 个字节【沾】到一起了。 沾包,这个说法,好土!计算机专业不会有这样的说法,虽然我也不是计算机专业毕业的。
----------------------------------------------
-
作者:
2022/10/5 20:58:18
21楼:
char recvBuff[8192] = ""; 这不是真代码吧?
----------------------------------------------
-
作者:
2022/10/6 10:12:11
22楼:
to 21楼:遇到问题了就调大点。 to 20楼: 就先这样跑着吧 ,出问题再说
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/
作者:
2022/10/6 22:07:52
23楼:
呃, char recvBuff[8192] = ""; 是不是等于 char recvBuff[8192] = {0};
----------------------------------------------
Bye bye DDRFAN...
作者:
2023/3/15 10:44:40
24楼:
问题解决了 客户端锁的位置不对导致的。 测试方法 大量塞入数据包。。。各种打log。。 感谢楼上各位回复。
----------------------------------------------
[alias] co = clone --recurse-submodules up = submodule update --init --recursiveupd = pullinfo = statusrest = reset --hard懒鬼提速https://www.cctry.com/ >http://qalculate.github.io/downloads.htmlhttps://www.cctry.com/