游戏开发论坛

 找回密码
 立即注册
搜索
查看: 12570|回复: 24

谈谈网络游戏中的“网络”编程

[复制链接]

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
发表于 2004-7-31 01:29:00 | 显示全部楼层 |阅读模式
谈谈网络游戏中的“网络”编程

近段时间总是有不少人问我关于完成端口模型的一些资料,很多时候其实我很郁闷,为什么大家会选择使用完成端口呢?或者说很多时候他们竟为了使用完成端口,而使用WINDOWS作为网络游戏服务器平台,还一开口罗列出一堆使用WINDOWS平台的网络游戏案例。有些兄弟跟我一直争论“Windows 2003 Server很猛的,效率很高的”,这句话的正确性暂且不讨论,先说Windows 2003 Server多少钱一张授权?降低成本不就等于多赚钱嘛。放着免费且高效的Linux不用,篇篇要花钱买贵的?而且性能还低得一塌糊涂?

不要着急,放心,我说的是对的,下面来看看IBM的一些研究者对Linux和Windows下编程的性能比较。

首先来看看线程创建的速度比较:


当然,也许你会说,现在都用线程池了,都是在开始的时候创建好线程,然后运行的时候直接拿来用就好了,恩,那么再来看看SOCKET的速度。



不用脸红脖子粗,这个只是简单的测试,不过有小道消息说Windows在对于本地127.0.0.1地址传输的时候,速度会提高很多,那么到底是不是呢?我们来看看下面这张测试结果:



其中带叉叉的线就是在针对127.0.0.1这个地址的情况下的传输速度,看得出来,那个小道消息确实是真的,Windows2000在对于本机地址传输的时候确实要快很多。那么Windows和Linux相比,还有什么缺点呢?Windows在线程方面还有个特点,叫Thread Creation Decay,什么意思呢?就是指随着运行时间的越来越长,刚刚启动的时候创建线程的速度和启动了一段时间之后,线程的创建速度会不一样,这也就是为什么一台Linux服务器可以几年都不重启,而Windows操作系统则不行。我这里并不是否认Windows,我在这里只是想说,Windows系统由于它所提供的Built-in GUI,导致内核在处理各个系统调用的时候,或多或少会有些损耗。

好像有点跑题了,这些和网络都没什么关系,那么我们回过头来看网络编程,首先我们来讨论一下网络的根本,根本是什么?是IO。接收一些数据,发送一些数据,在C/S模式下,又根据接收发送行为的不同,而分成了服务器和客户端两种程序模型。那么究竟该如何处理这些IO呢?我们来看看目前几种常见的方法:
Blocking Read-Write
关于这个最常见的模型就是:
while (size = read(fd, buf, max_size, 0) )
        ProcessMessage(buf, size);
用这种模型几乎无法处理面对多个用户连接的情况,因为在这种情况下,read的操作是阻塞的,会一直等到有消息到达才会返回。于是大家为了让这种模型适用于多个用户连接,就想了一个办法,那么就是:

Multi Threading Blocking IO
就是为每个用户连接,开启一个线程来跑上面的那个循环。但是,随着用户人数的增加,线程数量越来越多,虽然大部分时间都消耗在阻塞上,但是操作系统却为此付出了相当大的用户级线程间切换的代价。


IOCP (I/O Completion Port)
这就是很多人都津津乐道的完成端口,的确,在Windows平台下,它是最完美的关于IO的解决方案,不仅效率高,而且占用资源也相对较少,对于在Windows平台下编写网络相关的操作,用它肯定是没错了。其原理就类似车站的售票窗口一样,有固定,有限的几个窗口来处理所有的请求。

Asynchronous IO
那么什么又是AIO呢?这是一个和以上三者不同的一个概念,或者说只是一种定义,不像上面,都是特定的看得到的结构模型。而这里所谓的AIO的定义是为了使在更大限度上对操作系统IO带宽的利用,从而产生的一种高效率的IO处理结构。这只是一个定义,而事实上对AIO的实现是多种多样的。一般来讲,真正的AIO,也就是按照AIO的思想来实现的,我们叫真AIO,比如Windows下的WSAASync系列的API,和Linux下POSIX AIO系列的API,其原理是在执行IO的时候立刻返回,然后让操作系统在处理完IO以后呼叫其回调函数。所以,对于用其他方法,达到AIO目的的方法,我们叫假AIO,因为假AIO从AIO的定义出发,到达的效果基本和真AIO一样,典型的方法就是select/poll/epoll配合非阻塞IO读写的来实现的假AIO。事实上呢,关于AIO的争论很多,Linux的内核对AIO的支持的实现方法也几乎在每个版本都有改动。有一些对AIO的PATCH甚至几乎和完成端口是一样的模型,但是仍然被称为是AIO。

好,谈到这里,希望大家对目前一些主流的IO处理方式有所了解了,那么我们再来看看如何根据不同的需求来选择不同的IO处理方案。

首先考虑到的显然是效率问题,就像刚刚在介绍IOCP时中说的一样,IOCP毫无疑问是任何情况下Windows来解决IO问题的最佳方案,那么Linux下呢?对于Linux下IO操作的选择应该有些取舍,其关键在于对select/poll/epoll配合非阻塞IO模拟的假AIO和POSIX系列的真AIO API之间的取舍。

在Linux 2.5版本之前,POSIX AIO几乎没什么特有的优势,因此几乎所有的基于Linux的网络应用都使用的select/poll/epoll配合非阻塞模拟来实现高效的IO处理方案,但是在Linux 2.5的内核中,对AIO的支持改进非常大,从而导致使用POSIX AIO的可能。但是缺点也是显而易见的,由于在内核中对AIO的支持是由和操作系统相关十分紧密一系列操作系统级的系统调用组成的。导致兼容性上会出现一定的问题,所以,这里的建议是,如果不太理解POSIX AIO的,最好别贸然选择使用POSIX AIO,而是老老实实的用select/poll/epoll配合非阻塞的IO处理方法吧,尽管两者之间的性能差别在目前来说还不算很大,但是我想随着不断更新的Linux内核,POSIX AIO会变得越来越好。

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2004-7-31 09:30:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

我用的FedoraCore2(kernel 2.6.7),我在info里看到,AIO只能用于那些能进行seek操作的文件描述符,所以终端之类的就不能用AIO,我想网络操作似乎也不能seek吧?那么怎么用AIO??

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2004-7-31 11:16:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

另外请问,使用AIO进行write和进行非阻塞write相比有什么区别吗?

1

主题

11

帖子

11

积分

新手上路

Rank: 1

积分
11
发表于 2004-7-31 15:20:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

请问下关于以上这些IO知识可以在哪里找到具体的详细的讲解。

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
 楼主| 发表于 2004-7-31 15:36:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

回4楼的,去Internet上搜。

回3楼的,POSIX的AIO write在Linux下应该是aio_write()这个函数。

回2楼的,AIO和那些没关系的。

29

主题

99

帖子

104

积分

注册会员

Rank: 2

积分
104
发表于 2004-8-6 16:25:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

楼主文章中的几个问题:
1 ,“Multi Threading Blocking IO,就是为每个用户连接,开启一个线程来跑上面的那个循环。” 傻子才会这么做,很多人不知道为什么需要线程和线程要注意的问题,这样做目的既不好,又极浪费资源,完成端口根本无须要为每一个用户连接创建线程而是把完成端口上完成的连接投递给服务器工作者线程GetQueuedCompletionStatus函数以进行持续的I/O操作而无须中断,包括后面将要在完成端口上产生的读和发送。完成端口用建一个叫单句柄数据结构的东西来对待每一个连接。可以和服务器建立上千的连接,而接收线程甚至只有一个,至于阻塞完全可以用setsocketopt函数来确定在某一个和完成端口绑定的acceptsocket上的WSAresv或WSAsend的时间。
2 ,非阻塞虽然可以使线程不会因为对某一个用户的接收没有返回而阻塞(在正常的通信中宽带中tcp的阻塞其实并不多见)但带来另一个问题,即非阻塞当用户调用send和recv的时候,函数一执行就立刻返回而不管有没有收到数据数据是否完整,这就需要进行消息包的整合校验,而这同样耗费时间,而且造成消息何时结束不好判断。

至于用windows还是linux我认为更多的不是看通信,而要看很多其他的因素,毕竟一个大型的应用通信只是一部分。

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
 楼主| 发表于 2004-8-6 19:59:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

呵呵,关于第一个问题。
我只是列出这种模型,N年以前,当大家还没有发明IOCP和AIO的时候,都在使用这种方法。另外,你是不是没仔细看我的帖子啊,我一直都说完成端口是WINDOWS下最完美的网络解决方案。

关于第二个问题,楼上的是不是没写过网络程序呢?对于非阻塞的SOCKET,自古以来的方法都是自己定义一个消息结构来进行解释,这也没什么问题。

对消息包整和消耗时间?我想看看你是怎么看待这个问题的,给出测试数据来?消耗多少时间?你看过MYSQL的代码没?看过POSTGRESQL的代码没?一堆GNU的软件都是在LINUX下写的,同样的WEB服务器是IIS快还是APACHE快?

说到服务器,我看还是LINUX的下的软件比较多吧,虽然都是支持多平台,不看看WEBSPHERE,ROXEN,APACHE,各种数据库,等等,楼上的别把无知当个性,发帖的时候也别动不动说人傻子。

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2004-8-8 06:55:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

tarkey,哪有epoll()函数用法的中文介绍?英文的info我看得晕乎晕乎的……
另外epoll()和poll()相比有什么不同?
另外我搜到一些资料,发现目前linux2.6上的AIO还不能用于socket操作……

149

主题

4981

帖子

5033

积分

论坛元老

Rank: 8Rank: 8

积分
5033
QQ
发表于 2004-8-8 07:07:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

tarkey,我看到你在OGDEV发的帖子:
恩,我以前写过,跨平台的,当时考虑到兼容性,统一使用的select,如果专门是Linux下的话,改成poll系统调用会提高一些效率。有C语言和C ++语言两种版本,有两套接口,一套服务器端用的接口,一套客户端用的接口,需要配套使用,因为底层自己弄了些协议。如果需要的话,可以联系我,免费开原提供~:)不过写了很久了,有些地方需要改改才能用的,不过结构上肯定是没问题的。

可以给我发一份吗?谢谢了先~~~
我的email:
sjinny@163.com
sjinny@sohu.com
再次感谢~~

59

主题

1104

帖子

1199

积分

金牌会员

Rank: 6Rank: 6

积分
1199
 楼主| 发表于 2004-8-8 09:08:00 | 显示全部楼层

Re:谈谈网络游戏中的“网络”编程

默认的LINUX2.6不支持AIO的SOCKET,要打个patch就可以了。。

epoll估计国内用到这个的不多,大概的意思和poll和select差不多,但是是一个新的接口,/dev/epoll,拷贝数据的时候CPU循环次数比poll更少,需要更少的内存。但是,有一点需要注意的是,它和以前的poll/select最大的区别是他只是在拷贝数据的时候才会通过mmap()绑定IO描叙符。

你要的东西我发给你了。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-26 05:43

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表