TCP/IP是可靠性传输协议,它能保证数据能按顺序的方式到达目的地.看到以上描述在写TCP/IP应用的时候似乎就可以放心了,只要程序不出意外就数据输传就是正确.但最近在做一个文件传输工作的时候确得到的结果并不是这样,发现网络环境和一次发送数据大会影响整个输传结果.以下是这两晚的测试情况
测试内容描述:
每个文件块信息包大概是120k左右
采用异步5连接输传,双方的Socket.SendBufferSize和Socket.ReceiveBufferSize都设置为64K
测试服务器分别有:
局域网:ServerA
在美国机房:ServerB 延时高,Ping有时会超时
测试client一台,通过ADSL上网.
以下是Client从Sever下载文件的情况:
- 服务器8K SendBuffer,客户端是8K ReceiveBuffer
从ServerA下载文件,分别下载多个文件几M到几百M不等,下载后文件正确.
从ServerB下载文件,分别下载多个文件,几M或更小的文件有部分正确,大文件基本都是错误.两端记录的发送的字节数和接收的字节相等,符合文件大小,程序也没有跟踪到数据接收异常导致的协议分解错误.
- 服务器4K SendBuffer,客户端8K ReceiveBuffer
从ServerA下载文件,分别下载多个文件几M到几百M不等,下载后文件正确.
从ServerB下载文件,分别下载多个文件,文件的正确率比较高,不过还是大文件相对错误比较多.当开启迅雷下载后情况就开始变坏,大部分接收到的文件都出问题,两端记录的发送的字节数和接收的字节相等,符合文件大小,程序也没有跟踪到数据接收异常导致的协议分解错误
- 服务器2K SendBuffer,客户端8K ReceiveBuffer
从ServerA下载文件,分别下载多个文件几M到几百M不等,下载后文件正确.
从ServerB下载文件,分别下载多个文件,下载结果没有发现错误文件.当开启迅雷下载后还是有个别文件错误,两端记录的发送的字节数和接收的字节相等,符合文件大小,程序也没有跟踪到数据接收异常导致的协议分解错误
- 服务器1K SendBuffer,客户端8K ReceiveBuffer
从ServerA下载文件,分别下载多个文件几M到几百M不等,下载后文件正确.
从ServerB下载文件,分别下载多个文件,下载结果没有发现错误文件.当开启迅雷下载后没有发现文件错误.
测试文件发送到Server和下载的情况基本差不多,这说明了在网络不好的情况处理发送大数据包似首容易产生错误,但看TCP/IP协议讲解这情况似乎不存在,因为当一个发送数据超过某个值的时候,TCP会划分块进行传输并保证其顺序.但网络不好的情况测试结果接收的数据有错误,但处理的数据大小是正确的,也并没影响整个协议的分解.由于对CP/IP协议、低层和路由处理的不了解,暂没找到具体原因。。。不排除程序存在还没发现的错误,打算给发送的文件数据加上校验再测试一下看情况
补充一下
以上测试只修改了一个属性
TcpUtils.SendBufferLength = 1K,2K,4K,8K
但只有1K的测试结果奇怪地没出现文件错误,其了几中均出现仅仅是对ServerB,对ServerA来说没有出现,2K,4K也只是开启迅雷的时候错误情况多.
发布bee网络文件管理工具
Bee是基于c#编写免费的网络文件管理工具,分别有服务端和客户端;主要功能包括:多线程文件上传、下载、续传,在线压缩、解压等功能,还具备同时对多个服务进行操作.
文件上传下载流程设计
最近在写一个文件上传下载的服务端和客户端,在开发之前把交互流程大概设计了一下顺便分享出来,流程主要包括验证,交口端口验证,文件上和文件下载等功能.之于文件删除,在线压缩和解压等流程相对简单所以就不列出来了.
登陆和交互端验证
其实很多网络通讯应用中登陆和数据交互都是分开端口服务的,这样就存在一个数据交互连接合法性的验证,以下是针对这验证的流程设计.
上传文件流程
上传文件主要的工作是服务验证用户是否有权,客户端提交上传文件信息,然后把文件分割成N个小数据包,通过多线程+队列的方式实现多线程上传.把分割信息存到文件或数据库我们就能实现续传了
文件下载
文件下载和上传原理差不多,先从服务器检测文件获取文件信息.客户端根据文件信息分割信息块存放到队列中(多队列+线程实现多线程下载方式),文件分割信息存放文件或数据后同样也可以实现续传.
到这里流程设计就结束,顺便共享一个文件分割类
延时拼包机制让c# socket实现海量数据包广播吞吐
之前已经简单的测试了c# socket的数据吞吐处理能力,结果虽然比较理想;但以这样的数据包处理量在某些场景下是远远不够用的,在某些应用场景中每秒要处理的数据包不是1,2W个可能几W,上10W或更多的数据包吞吐。在一个游戏场景中同场景存在100用户,每个用户的变更都会通知其他199的用户,如果每个用户平均每秒变更3次,那服务端每秒接收转发的数据包就是100x100x3=3w个。如果是200个用户同场景,那所每秒所面对的处理包会是200x200x3=12W个,想c# socket提供这么密集的IO处理是不太可能的事情,即使是可以那也要很不错的硬件支撑。
从软件上去解决这问题那只能选择减少IO操作,之前的测试表明SendAsync这相的IO操作是非常损耗资源。既然问题已经知道发生在什么地方,我们可以采用减少SendAsync又不影响交互性来达到这一点。大家知道网络访问存在一个延时的系数,通过在可接受的延时区间可以把发送的A的N个数据包打包到一个buffer里,然后进行一次SendAsync操作,原本在这一时间段时有100个消息包发给A,那可以打包成一个这样SendAsync的操作就可以从原来的100次变成一次;那些这节省是相当可观的,当然这个设计尽可能根据当前调度情况来确定,调度空闲的情况下不合拼,调度存在压力的时候进行一个合拼处理。
以下是针对这个设计的测试结果:
测试硬件:
server:Core2 4300 1.8G 2G win2003
client1:Core i7 Q740 1.7G 4G win764
client2:P4 2.4G 1G WIN2003
测试逻辑:
每个client程序开启50个连接,每个连接秒产生3次座标变化告诉服务端,由服务端专发给其他client.
定期为每个client发送ping包,检测服务器处理和回发的延时时间。
数据结构:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
public class ChangePostion:IMessage { public int X { get ; set ; } public int Y { get ; set ; } public string ID { get ; set ; } public void Save(BufferWriter writer) { writer.Write(X); writer.Write(Y); writer.WriteBlock(ID); } public void Load(BufferReader reader) { X = reader.ReadInt32(); Y = reader.ReadInt32(); ID = reader.ReadBlock(); } private static Random ran = new Random(); public static ChangePostion GetPoint() { ChangePostion cp = new ChangePostion(); cp.X = ran.Next(1, 399); cp.Y = ran.Next(1, 399); return cp; } } public class Ping : IMessage { public string ID { get ; set ; } public DateTime Ticks { get ; set ; } public void Save(BufferWriter writer) { writer.WriteBlock(ID); } public void Load(BufferReader reader) { ID = reader.ReadBlock(); } } |
100人同场景测试
服务端程序情况:
client情况
测试情况来看每个client每秒接收1.6w个数据包,两个client接收大概3.2W个数据包,服务端的下行带宽是2MB/秒,每秒处理3.2W对象写入缓冲发送。
200人同场景测试
服务器端情况
客户端情况
测试情况来看每个client每秒接收3.2w个数据包,4个client接收大概13W个数据包,服务端的下行带宽是8MB/秒,每秒处理13W对象写入缓冲发送
注意
当使用了拼包的时候就要考虑一下Socket.NoDelay是否需要开启,还有client的ReceiveBufferSize是否需要加大,在测试过程中当存在大量数据包接收的时候有个别client连接接收到的数据不正常,之于这个问题是.net的内置缓冲问题还是程序设计上的缺陷还在追查中(查明原因后会编写文章讲述问题情况)。
下载测试程序
BeetleTest20111127.rar (935.91 kb)
跑测试程序最好把client分布在不同机器上
通过上面的测试可以让想用C# Socket做应用的朋友更进一步了解它的处理能力到底怎样。对于想要源码的朋友就不需要问了,对于些问题的分析可以访问:www.henryfan.net
10 2011 档案
网络数据处理缓冲区和缓冲池实现
posted @ 2011-10-31 10:06 smark 阅读(1654) | 评论 (2) 编辑
缺省数据库描述对象的数据库访问模式
posted @ 2011-10-19 11:02 smark 阅读(250) | 评论 (0) 编辑
Smark.Data 开源数据访问组简介
posted @ 2011-10-17 12:02 smark 阅读(1088) | 评论 (18) 编辑
C#运算符重载实现动态SQL生成
posted @ 2011-10-15 10:01 smark 阅读(1096) | 评论 (13) 编辑
C#实现一个简单的工作队列调度器
posted @ 2011-10-14 13:00 smark 阅读(1187) | 评论 (2) 编辑
VsSingleFileGenerator插件创建,安装和使用
posted @ 2011-10-13 16:16 smark 阅读(692) | 评论 (2) 编辑
安装和使用Smark.Data.I2MGenerator
posted @ 2011-10-13 11:27 smark 阅读(77) | 评论 (0) 编辑
通过VS2010性能分析来查找代码中那些地方最损耗资源
posted @ 2011-10-12 00:47 smark 阅读(3902) | 评论 (28) 编辑
11 2011 档案
延时拼包机制让c# socket实现海量数据包广播吞吐
posted @ 2011-11-28 10:17 smark 阅读(1679) | 评论 (19) 编辑
C# Socket Tcp 性能测试
posted @ 2011-11-21 10:01 smark 阅读(1847) | 评论 (17) 编辑
c#编写高性能Tcp Socket应用注意事项
posted @ 2011-11-14 12:27 smark 阅读(4443) | 评论 (42) 编辑
构造BufferWriter和BufferReader实现高效的对象序列化和反序列化
posted @ 2011-11-02 12:16 smark 阅读(1124) | 评论 (3) 编辑