udp通信多网卡环境udp发包工具被丢弃,该怎么处理

游戏服务器:到底使用UDP还是TCP - 文章 - 伯乐在线
& 游戏服务器:到底使用UDP还是TCP
在编写网络游戏的时候,到底使用UDP还是TCP的问题迟早都要面对。
一般来说你会听到人们这样说:“除非你正在写一个动作类游戏,否则你就用TCP吧” 或者是 “你能够在MMO游戏中用TCP,因为魔兽世界就用的TCP!”
遗憾的是,这些观点都没有反映这个问题的复杂性。
首先,说明一下,我之前主要是用TCP进行网络编程。我曾为一个流行的在线纸牌游戏编写服务器了好几年,在高峰期我们的每台服务器能够承受个连接(同一台物理机器上有多个服务器进程在跑)都没有问题。在我来看,TCP是一种安全而且常见的选择。
尽管如此,我们最新的项目却是使用UDP协议,而且我们的项目无法通过任何方式在TCP下工作。事实上,项目一开始使用的TCP,但是后来发现我们使用TCP无法达到我们需求的连接数量时,我们只能换成UDP了。
在使用中TCP表现怎么样呢
从原理上,TCP的优势有:
简单直接的长连接
可靠的信息传输
数据包的大小没有限制
任何一个和TCP打过交道的人都知道,要实现一个稳定的TCP网络连接,需要处理各种隐藏的坑,比如断线检测、慢速客户端响应阻塞数据包,对开放连接的各种dos攻击,阻塞和非阻塞IO模型等等。
除了上面列出的这些问题外,一个好的TCP模块确实不好编码实现。
但是,TCP最糟糕的特性是它对阻塞的控制。一般来说,TCP假定丢包是由于网络带宽不够造成的,所以发生这种情况的时候,TCP就会减少发包速度。
在3G或WiFi下,一个数据包丢失了,你希望的是立马重发这个数据包,然而TCP的阻塞机制却完全是采用相反的方式来处理!
而且没有任何办法能够绕过这个机制,因为这是TCP协议构建的基础。这就是为什么在3G或者WiFi环境下,ping值能够上升到1000多毫秒的原因。
为什么不用UDP
UDP相对TCP来说既简单又困难。
举个例子来说,UDP是基于数据包构建,这意味着在某些方面需要你完全颠覆在TCP下的观念。UDP只使用一个socket进行通信,不像TCP需要为每一个客户端建立一个socket连接。这些都是UDP非常不错的地方。
但是,大多数情况下你需要的仅仅是一些连接的概念罢了,一些基本的包序功能,以及所谓的连接可靠性。可惜的是,这些功能UDP都没有办法简单的提供给你,而你使用TCP却都可以免费得到。
这也是人们为什么经常推荐TCP的原因。在用TCP的时候你可以不考虑这些问题,直到你需要同步连接的数量级达到500以上的时候。
所以,是的,UDP没有提供所有的解决方法,但是就像你看到的那样,这也正是UDP好用的地方。在某种意义上来说,TCP对UDP就好比是Hibernate和手写SQL的区别。
使用TCP失败的地方
人们经常给你建议,让你去使用TCP,比如“TCP跟UDP一样快”或者“游戏X用TCP如此成功,所以TCP当然是首选”,然而,他们完全没有理解为什么在那个特定的游戏中TCP是有效的,为什么UDP不按照顺序发送数据包呢?
那么为什么魔兽世界采用TCP呢?首先我们需要解释这个问题。这个问题其实是“为什么魔兽世界有的时候1000毫秒以上的延迟还能够运行?”这是TCP的性质决定的,在发生丢包的时候,会产生巨大的延迟,因为TCP首先会去检测哪些包发生了丢失,然后重发所有丢失的包,直到他们都被接收到。
可靠的UDP也是有延迟的,但是由于它是在UDP的基础之上建立的通信协议,所以可以通过多种方式来减少延迟,不像TCP,所有的东西都要依赖于TCP协议本身而无法被更改。
就这一点来讲,一些人要开始提到Nagle算法了,实际上它是你在实现任意一个对延迟敏感的TCP模型时首先需要禁止使用的。
那么魔兽世界以及其他的一些游戏是怎么处理延迟问题的呢?
方法也很简单,他们能够隐藏掉延迟带来的影响。
在魔兽世界中,玩家和玩家是无法碰撞的:因为这类碰撞是无法通过一些预测来处理的,但是玩家和环境之间的碰撞却是可以通过预测来处理的,所以这里使用TCP是没有问题的。
我们来看一下魔兽世界的战斗就会发现,玩家的攻击指令发送给服务器的操作是放在比如“attack_entity(entity_id)”或者”cast_spell(entity_id, spell_id)“的接口中来做的,换句话说,瞄准操作是独立于进行的。如此一来,一些类似发起攻击动作和释放技能特效就能够在没有收到服务器确认的情况下就直接执行,比如展现冰冻技能的效果就可以在服务器没有返回数据前在客户端就做出来。
客户端直接开始进行计算而不等待服务端确认是一种典型的隐藏延迟的技术。
几年前,我为一个叫“Five Card Jazz”的纸牌游戏编写过客户端。它使用的是http协议,它比直接的TCP协议连接的延迟更加严重。
我们用简单的纸牌绘制和抽牌的动画来掩盖延迟的问题,所以延迟的问题只在非常糟糕的连接下才会被看出来。这种方法也非常的典型:发送请求的同时开始播放牌桌的动画,一直播放翻动最后一张牌直到接收到了服务端传回来的数据为止。魔兽世界的战斗特效就是使用类似的原理。
这也意味着,我们到底是使用TCP还是UDP取决于我们能否隐藏延迟。
TCP在什么时候失效
一个采用TCP的游戏必须能够处理好突发的延迟问题(纸牌客户端就很典型,对突发性的一秒的延迟,玩家也不会产生什么抱怨)或者是拥有缓解延迟问题的好方法。
但是如果你运行的是一个无法使用任何减缓延迟措施的游戏呢?玩家对玩家的动作类游戏通常就属于这个范畴,但是这也不仅仅限于动作类游戏。
举个例子:
我目前正在写一个多人游戏(War Arcana)。
一种常见的操作是,你快速的移动你的角色通过一张充满战争迷雾的世界地图,但是一旦你探索过,迷雾就会被打开。
为了确保游戏的规则,防止玩家作弊,服务器只能显示玩家当前位置附近的信息。这意味着不像魔兽世界,玩家无法在没有得到服务器响应的情况下,做出完整的动作。和Five Card Jazz相比,我们即使允许500毫秒的延迟,也已经非常困难了。
在实现了游戏的原型后,在局域网内一切都进行的非常顺利,但当我们在WiFi环境下测试时,操作会间歇性的卡起来或者延迟高起来。写了一些测试程序之后发现,WiFi环境下偶尔会发生丢包行为,每当发生丢包的时候,服务器的响应速度就从100-150毫秒上升到毫秒。
没有任何办法可以绕过TCP的这个设置来避开这个问题。
我们替换了TCP的代码,用了自定义的可靠的UDP来实现,把大量的丢包产生的延迟降到了仅仅只有50毫秒,甚至比以前TCP不丢包的情况一个来回的延迟还要小。当然,这只可能建立在UDP之上,这样我们才对可靠性拥有完全的掌控力。
困惑:可靠的UDP只是TCP的一种简单的实现?
你有没有听过这种说法:“可靠的UDP就像TCP一样,所以还是用TCP吧”。
问题是这种说法是错误的。可靠的UDP一点也不像TCP,要去实现一个特殊的阻塞控制。事实上,这也是你使用可靠UDP代替TCP的最大的原因,避免TCP的阻塞控制。
另一个重点是可靠的UDP的可靠性是如何保证的。这里有很多种方法去实现。我非常喜欢Quake3网络库代码里的一些想法,它们也激发了我在War Arcana中使用UDP协议。
你也可以使用许多支持可靠通信的UDP库,当然,这样在可靠性方面,相比自己手动实现全部的代码而言,可能会更加通用而失去了一些性能优势。
那么到底是用UDP还是TCP呢?
如果是由客户端间歇性的发起无状态的查询,并且偶尔发生延迟是可以容忍,那么使用HTTP/HTTPS吧。
如果客户端和服务器都可以独立发包,但是偶尔发生延迟可以容忍(比如:在线的纸牌游戏,许多MMO类的游戏),那么使用TCP长连接吧。
如果客户端和服务器都可以独立发包,而且无法忍受延迟(比如:大多数的多人动作类游戏,一些MMO类游戏),那么使用UDP吧。
这些也应该考虑在内:你的MMO客户端也许首先使用HTTP去获取上一次的更新内容,然后使用UDP跟游戏服务器进行连接。
永远不要害怕去使用最佳的工具来解决问题。
关于作者:
可能感兴趣的话题
不同意作者的观点。tcp的连接数限制有很多方法可以解决。
关于伯乐在线博客
在这个信息爆炸的时代,人们已然被大量、快速并且简短的信息所包围。然而,我们相信:过多“快餐”式的阅读只会令人“虚胖”,缺乏实质的内涵。伯乐在线内容团队正试图以我们微薄的力量,把优秀的原创文章和译文分享给读者,为“快餐”添加一些“营养”元素。
新浪微博:
推荐微信号
(加好友请注明来意)
– 好的话题、有启发的回复、值得信赖的圈子
– 分享和发现有价值的内容与观点
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 翻译传播优秀的外文文章
– 国内外的精选文章
– UI,网页,交互和用户体验
– 专注iOS技术分享
– 专注Android技术分享
– JavaScript, HTML5, CSS
– 专注Java技术分享
– 专注Python技术分享
& 2016 伯乐在线C++多线程如何实现 - C++当前位置:& &&&C++多线程如何实现C++多线程如何实现&&网友分享于:&&浏览:128次C++多线程怎么实现如题!最好有例子------解决方案--------------------下文来自于windows核心编程第6章 线程的基础知识理解线程是非常关键的,因为每个进程至少需要一个线程。本章将更加详细地介绍线程的知识。尤其是要讲述进程与线程之间存在多大的差别,它们各自具有什么作用。还要介绍系统如何使用线程内核对象来管理线程。与进程内核对象一样,线程内核对象也拥有属性,我们将要观察许多用于查询和修改这些属性的函数。此外还要介绍可以在进程中创建和生成更多的线程时所用的函数。第4章介绍了进程是由两个部分构成的,一个是进程内核对象,另一个是地址空间。同样,线程也是由两个部分组成的:o 一个是线程的内核对象,操作系统用它来对线程实施管理。内核对象也是系统用来存放线程统计信息的地方。o 另一个是线程堆栈,它用于维护线程在执行代码时需要的所有函数参数和局部变量(第1 6章将进一步介绍系统如何管理线程堆栈)。第4章中讲过,进程是不活泼的。进程从来不执行任何东西,它只是线程的容器。线程总是在某个进程环境中创建的,而且它的整个寿命期都在该进程中。这意味着线程在它的进程地址空间中执行代码,并且在进程的地址空间中对数据进行操作。因此,如果在单进程环境中,你有两个或多个线程正在运行,那么这两个线程将共享单个地址空间。这些线程能够执行相同的代码,对相同的数据进行操作。这些线程还能共享内核对象句柄,因为句柄表依赖于每个进程而不是每个线程存在。如你所见,进程使用的系统资源比线程多得多,原因是它需要更多的地址空间。为进程创建一个虚拟地址空间需要许多系统资源。系统中要保留大量的记录,这要占用大量的内存。另外,由于. e x e和. d l l文件要加载到一个地址空间,因此也需要文件资源。而线程使用的系统资源要少得多。实际上,线程只有一个内核对象和一个堆栈,保留的记录很少,因此需要很少的内存。由于线程需要的开销比进程少,因此始终都应该设法用增加线程来解决编程问题,而要避免创建新的进程。但是,这个建议并不是一成不变的。许多程序设计用多个进程来实现会更好些。应该懂得权衡利弊,经验会指导你的编程实践。在详细介绍线程之前,首先花一点时间讲一讲如何正确地在应用程序结构中使用线程。6.1 何时创建线程线程用于描述进程中的运行路径。每当进程被初始化时,系统就要创建一个主线程。该线程与C / C + +运行期库的启动代码一道开始运行,启动代码则调用进入点函数( m a i n、w m a i n、Wi n M a i n或w Wi n M a i n),并且继续运行直到进入点函数返回并且C / C + +运行期库的启动代码调用E x i t P r o c e s s为止。对于许多应用程序来说,这个主线程是应用程序需要的唯一线程。不过,进程能够创建更多的线程来帮助执行它们的操作。每个计算机都拥有一个功能非常强大的资源,即C P U。让C P U闲置起来是绝对没有道理的(如果忽略节省电能问题的话)。为了使C P U处于繁忙状态之中,可以让它执行各种不同的工作。下面是一些例子:o 可以打开Microsoft Windows 2000配备的内容索引服务程序。它能够创建一个低优先级的线程,以便定期打开你的磁盘驱动器上的文件内容并给内容做索引。若要找到一个文件,可以打开Search Result(搜索结果)窗口(方法是单击S t a r t按钮,从S e a r c h菜单中选定For Files Or Folders),再将你的搜索条件输入Containing Te x t域。这时就可以搜索到索引,相关的文件就会立即显示出来。内容索引服务程序大大改进了性能,因为每次搜索不必打开、扫描和关闭磁盘驱动器上的每个文件。o 可以使用Windows 2000配备的磁盘碎片整理软件。通常情况下,这种类型的实用程序拥有许多管理选项,一般用户可能不懂,比如该实用程序应该相隔多长时间运行一次,何时运行。使用低优先级线程,可以在后台运行该实用程序,并且在系统空闲时对驱动器进行碎片整理。o 可以很容易地设想将来版本的编译器,每当暂停键入时,它就可以自动编译你的源代码文件。输出窗口可以向你(几乎)实时显示警告和出错信息。当键入变量和函数名时出现错误时,就能立即发现。在某种程度上讲, Microsoft Visual Studio已经实现了这个功能,使用Wo r k s p a c e的C l a s s Vi e w窗格,就能够看到这些信息。o 电子表格应用程序能够在后台执行各种计算。o 字处理程序能够执行重新分页、拼写和语法检查及在后台进行打印。o 文件可以在后台拷贝到其他介质中。o We b浏览器在后台与它们的服务器进行通信。因此,在来自当前We b站点的结果输入之前,用户可以缩放浏览器的窗口或者转到另一个Web站点。这些例子中,有一个重要问题应该注意,那就是多线程能够简化应用程序的用户界面。如果每当停止键入时,编译器建立了你的应用程序,那么就没有必要提供B u i l d菜单选项。文字处理应用程序不需要Check Spelling(拼写检查)和Check Grammar(语法检查)菜单选项。在We b浏览器的例子中,注意,将不同的线程用于I / O(网络、文件或其他),应用程序的用户界面就能够始终保持工作状态。比如有一个应用程序负责给数据库记录进行排序、打印文档或拷贝文件。如果将独立的线程用于处理这个与I / O相关的任务,用户就可以在进程中继续使用应用程序界面来取消操作。设计一个拥有多线程的应用程序,就会扩大该应用程序的功能。我们在下一章中可以看到,每个线程被分配了一个C P U。因此,如果你的计算机拥有两个C P U,你的应用程序中有两个线程,那么两个C P U都将处于繁忙状态。实际上,你是让两个任务在执行一个任务的时间内完成操作。每个进程至少拥有一个线程。因此,如果你在应用程序中不执行任何特殊的操作,在多进程操作系统上运行,就能够得到许多好处。例如,可以建立一个应用程序,并同时使用文字处理程序(我常常这样做)。如果计算机拥有两个C P U,那么该应用程序就可以在一个处理器上执行,而另一个处理器则负责处理文档。另外,如果编译器出现一个错误,导致它的线程进入一个无限循环,仍然可以使用其他的进程( 1 6位Wi n d o w s和M S - D O S应用程序则不行)6.2 何时不能创建线程至今为止,一直在讨论多线程应用程序的优点。虽然多线程应用程序的优点很多,但是它也存在某些不足之处。有些开发人员认为,解决问题的方法是将它分割成多个线程。这种想法是完全错误的。线程确实是非常有用的,但是,当使用线程时,在解决原有的问题时可能产生新的问题。例如,你开发了一个文字处理应用程序,并且想要让打印函数作为它自己的线程来运行。这听起来是个很好的主意,因为用户可以在打印文档时立即回头着手编辑文档。但是,这意味着文档中的数据可能在文档打印时变更。也许最好是不要让打印操作在它自己的线程中发生,不过这种“方案”看起来有点儿极端。如果你让用户编辑另一个文档,但是锁定正在打印的文档,使得打印结束前该文档不能修改,那将会怎样呢?这里还有第三种思路,将文档拷贝到一个临时文件,然后打印该临时文件的内容,并让用户修改原始文档。当包含该文档的临时文件结束打印时,删除临时文件。如你所见,线程能够解决某些问题,但是却又会产生新的问题。在开发应用程序的用户界面时,很可能出现对线程的另一种误用。几乎在所有的应用程序中,所有用户界面的组件(窗口)应该共享同一个线程。单个线程应该创建窗口的所有子窗口。有时在不同的线程上创建不同的窗口是有用的,不过这种情况确实非常少见。通常情况下,一个应用程序拥有一个用户界面线程,用于创建所有窗口,并且有一个G e t M e s s a g e循环。进程中的所有其他线程都是工作线程,它们与计算机或I / O相关联,但是这些线程从不创建窗口。另外,一个用户界面线程通常拥有比工作线程更高的优先级,因此用户界面负责向用户作出响应。虽然单个进程拥有多个用户界面线程的情况并不多见,但是这种情况有着某种有效的用途。Windows Explorer为每个文件夹窗口创建了一个独立的线程。它使你能够将文件从一个文件夹拷贝到另一个文件夹,并且仍然可以查看你的系统上的其他文件夹。另外,如果E x p l o r e r中存在一个错误,那么负责处理文件夹的线程可能崩溃,但是仍然能够对其他文件夹进行操作,至少在执行的操作导致其他文件夹也崩溃之前,仍然可以对它们进行操作(关于线程和用户界面的详细说明,参见第2 6和2 7章)。上述内容的实质是应该慎重地使用多线程。不要想用就用。仅仅使用赋予进程的主线程,就能够编写出许多非常有用的和功能强大的应用程序。 共&4&页:
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
2015年4月 C++ Builder大版内专家分月排行榜第二
2013年12月 C++ Builder大版内专家分月排行榜第三
匿名用户不能发表回复!|
每天回帖即可获得10分可用分!小技巧:
你还可以输入10000个字符
(Ctrl+Enter)
请遵守CSDN,不得违反国家法律法规。
转载文章请注明出自“CSDN(www.csdn.net)”。如是商业用途请联系原作者。}

我要回帖

更多关于 linux udp发包程序 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信