TCP协议下大数据传输IOCP乱序问题
毕业后稀里糊涂的闭门造车了两年,自己的独立博客也写了两年,各种乱七八糟,最近准备把自己博客废了,现在来看了下这两年写的对我来说略微有点意义的文章只此一篇,转载过来以作留念。
写的很肤浅且凌乱,请见谅。
我的服务器主要完成一个内网音视频实时转发功能,以及其他一些业务。设计大概如下:
服务器上分为接收线程,业务处理线程,发送线程。接收线程socket绑定到完成端口。业务处理线程是采用多线程的模拟完成端口,发送线程也是多线程采用模拟完成端口。这样做的目的是想业务处理线程阻塞并不影响发送和接收。
客户端业务层需要发送一个数据,我视为大包数据,传输层把大包数据进行拆分,变成小包发送到服务器。服务器收齐一个大包后,加入接收队列。业务处理线程从接收队列获取大包数据,抛给业务层。服务器业务层处理后把需要转发的数据放到发送队列。发送线程从发送队列取出数据转发给需要接收数据的客户端。
此时接收客户端收到乱序,起初我怀疑是多线程传输导致的乱序。认为采用了异步传输,又多条线程发送,那么可能有的包先到有的包后到。但是!采用的TCP传输协议理论上是不会乱序的。
一、排除SEND,WSASEND导致乱序的问题
要知道如果采用的是send,TCP协议下,只要我们保证调用send是有序的,那么数据拷贝到send缓冲就是有序的,TCP协议会保证数据的顺序性到达。即便是WSASend,采用TCP原理都一样,只是WSA是非阻塞等待,它也会保证按顺序拷贝进socket的send缓冲区。所以WSASend基于TCP协议就是顺序到达的。所以,如果你的程序设计上是以小包发送为单位,发生了乱序,那一定是你设计的问题。
二、检查服务器接收数据是否乱序
这个看个人项目怎么设计了,我这里打日志是已经排除了服务器接收数据乱序的可能。
三、排除多线程发送导致的乱序
每条线发送线程从发送队列取大包数据,如果发送队列本身是顺序的,那么取出来发送这个过程就应该是顺序的。如果队列里存的是一次send能允许的最大小包,那么也应该是顺序到达(结合问题一来思考)。
四、那我的问题在哪里
答案还是多线程发送,以及多条业务处理线程。刚刚问题三虽然我否定了多线程发送导致的乱序,但是请仔细看我说的前提,是以小包为单位。
在我这个程序里,设定的是以大包为单位,大包是由小包组成的,IOCP完成端口能监控到IO完成情况,也就是小包的完成情况,但是并不能监控大包完成情况。我的各种设定只是保证了取大包这一刻是有序的。如果大包ID=1是由100个小包组成,大包ID=2是由1个小包组成,在实际发送的时候就会出现:
线程1 获取大包ID=1
线程2获取大包ID=2
线程1 发送ID=1的第一个小包
线程1 发送ID=1的第二个小包
…….线程1 发送ID=1的第n个小包
线程2发送ID=2的第1个小包
…..线程1 发送ID=1的第m个小包
客户端就先收集齐了大包ID=2的所有小包,反馈给业务层或者加入接收队列,所以业务层或者接收队列看到的数据就是乱序的。
除了发送线程,业务处理线程也是多线程,业务处理线程会把处理后的数据add到发送队列,这个add过程本身就不能保证是有序的。也就是说在send前,数据其实已经可能存在乱序了。
五、小结
如果要严格来说,TCP下IOCP本身不是导致乱序的原因,WSASend只要顺序调用也不存在乱序一说,真正导致乱序的是自己设计的问题。
题外话:
回顾这两年自己闭门造车的过程,各种尝试与猜测,哈,终究只是在浪费时间。大学一直在搞asp.net,实习搞java和android,毕业了却在做c++,哈,各种折腾到现在没有一项觉得做的深入的。从0基础开始搞c++从0开始搞传输,走了很多弯路进了很多坑,人又笨,掉进去了半天都怕不上来。。
最后这个服务器转发的传输协议坑了6个大的版本后,在第7个版本,终于经过测试能跑满千兆带宽,6核12线程的cpu消耗5%左右。不得不吐槽一下IOCP真的很厉害。
TCP协议下大数据传输IOCP乱序问题的更多相关文章
- tcp协议下的Socket
import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net ...
- TCP协议传输大文件读取时候的问题
TCP协议传输大文件读取时候的问题 大文件传不完的bug 我们在定义的时候定义服务端每次文件读取大小为10240, 客户端每次接受大小为10240 我们想当然的认为客户端每次读取大小就是10240而把 ...
- TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q
TCP协议下的服务端并发,GIL全局解释器锁,死锁,信号量,event事件,线程q 一.TCP协议下的服务端并发 ''' 将不同的功能尽量拆分成不同的函数,拆分出来的功能可以被多个地方使用 TCP服务 ...
- TCP协议下Socket的基础编程类型
套接字的基本操作有: 创建(socket).命名(bind).侦听(listen).连接(accept).关闭(shutdown).发送(send).接受(recv). 下面逐个分析: 一.创建(so ...
- 基于tcp协议下粘包现象和解决方案,socketserver
一.缓冲区 每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区.write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送 ...
- 《java入门第一季》之tcp协议下的网络编程
tcp协议相对于udp更加安全. 首先看一下需求:服务器端开启,多个客户端同时向服务器发送数据,看哪个客户端先到达. 说明:这里我开启三个电脑实验,一台电脑写服务器端的程序,两台电脑开客户端的程序.服 ...
- 在TCP协议下的数据传送
本人小白菜逼一枚,,,,刚建立博客,也写不了太深入的,就写点上课的笔记什么的.有错误希望广大博友指出,我一定虚心学习接收改正. 我的新浪邮箱:liudaohui0805@sina.com 我的QQ邮箱 ...
- tcp协议下粘包问题的产生及解决方案
1 tcp有粘包及udp无粘包 - TCP 是面向连接的,面向流的可靠协议:发送端为了将多个发往接收端的包,更有效的发到对方,使用了优化方法(Nagle算法),将多次间隔较小且数据量小的数据, 合并成 ...
- 基于TCP协议的大文件传输(粘包问题处理)
基于TCP的大文件上传服务端实现 # 服务端 # -*- coding: utf-8 -*- from socket import * import json, struct server = soc ...
随机推荐
- 【BZOJ】3028: 食物
http://www.lydsy.com/JudgeOnline/problem.php?id=3028 题意: 每种食物的限制如下:汉堡:偶数个:可乐:0个或1个鸡腿:0个,1个或2个蜜桃:奇数个鸡 ...
- js,html,css注释大集合
1.js注释: 单行注释,在注释内容前加符号 “//” <script type="text/javascript"> document.write("单行注 ...
- PHP面向对象学习四 类的关键字
1.关键字:final 用来定义类和方法的一个重要关键字,当定义类的时候该类将不能被继承, 当用来定义方法的时候该方法将不能被重载 2.关键字:static 用来定义类的静态属性或方法,可以在类未被实 ...
- ios面试(2015.10.30)
今天去深圳市丰泰瑞达实业有限公司面试,面试分为笔试和面试两部分,结果非常不理想,不过学到很多.面试题记录如下: 1.tableview的三个常用方法的实现 - (NSInteger)numberOfS ...
- SpringMVC从Controller跳转到另一个Controller
1. 需求背景 需求:spring MVC框架controller间跳转,需重定向.有几种情况:不带参数跳转,带参数拼接url形式跳转,带参数不拼接参数跳转,页面也能显示. 本来以为挺简单的一件事 ...
- 关于Autoit上传文件的问题
Autoit上传文件需要安装两个软件: 使用这个做文件上传时:在代码中需要添加的代码如下: Runtime.getRuntime().exec("d:/zhpg.exe"); D盘 ...
- 数位DP bzoj1026
1026: [SCOI2009]windy数 Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 5809 Solved: 2589[Submit][Sta ...
- Spring 定时器
<!-- 对定时任务进行引用 --> <bean id="schedulerFactory" class="org.springframework.sc ...
- wxpython更新
.configure时候检查不到gtk+ 使用 apt-get install gnome-core-devel
- 温故而知新 OOP
设计原则1: 找出应用中可能需要发生改变的地方,把它们独立出来,不要和那些不需要变化的代码混在一起换句话说,如果每次新的需求一来,都会使某方面的代码发生变化,此时你就可以确定,这部分代码属于不稳定代码 ...