java游戏服务端实现

上传人:无*** 文档编号:100085828 上传时间:2022-06-02 格式:DOC 页数:8 大小:50.50KB
收藏 版权申诉 举报 下载
java游戏服务端实现_第1页
第1页 / 共8页
java游戏服务端实现_第2页
第2页 / 共8页
java游戏服务端实现_第3页
第3页 / 共8页
资源描述:

《java游戏服务端实现》由会员分享,可在线阅读,更多相关《java游戏服务端实现(8页珍藏版)》请在装配图网上搜索。

1、java游戏服务端实现一个多人在线的棋牌类网络游戏的项目临近尾声,我参与了该项目的整个设计流程,并且完成了90%的核心代码。关于这个项目,有很多地方值得聊一聊。本系列不打算把这个项目将得多么详细规范,那是设计文档应该描述的,我打算只说说一些值得注意的地方。这个项目的一个特别之处是,客户端是手机,用户通过移动网络与服务器通信。和PC相比,手机的处理能力极弱,而且网络流量费用昂贵。因为除了要考虑普通网络游戏的一些问题之外,这两点也需要在设计中充分考虑。 首先是开发语言的选择,由于服务器是Linux的环境,MS的技术直接排除,至于MONO嘛,我实在不放心。可供选择的是C+和Java,Java胜 在网

2、络能力强大,开发周期短,有众多框架和开源库的支持,要写出烂得不可接受的代码也不容易;C+则胜在速度快。综合各方面因素,C+更容易把这个项 目变成一堆代码噩梦,我们选择了Java。一、网络网络游戏,首先面临的问题当然是如何进行网络通信。首先考虑的是HTTP协议,因为所有的J2ME手机都支持这个,我们当然想尽可能的兼容用户。而且HTTP协议封装程度已经非常高了,不用去考虑线程、同步、状态管理、连接池,不过HTTP协议有两个不爽的地方: 协议无状态,这个问题已经困扰过很多人很多次了。我曾考虑过的解决办法是改造HTTP协议,在数据传输完成之后不关闭socket,但是这样做工作 量非常大,在项目周期中,

3、基本上就是Missionimpossible,不予考虑。那么客户也就只能通过轮询的方式向服务器请求数据。 网络流量过大。就这个项目来说,网络间传递的只是指令,但是每次传递都要加上一堆毫无用处的HTTPHead,再加上客户端需要做轮询,这个流量 对于手机来说简直恐怖,经简单测试,按照0.03元/K的GPRS网络费用计算,一局牌居然要消耗1元多的费用(每秒轮询),实在不可接受。也许我们可以 采用流量费包月的资费方式,不过这个话题与技术无关。以上问题导致我们选择了Socket,这意味着我们将没有一个web环境,很多东西都要靠自己去实现:线程管理、客户状态监控、对象池、控制台. 网络部分打算采用Jav

4、aNIO来实现,这是一种新的网络监听方式,基于事件的异步通信,可以提高性能。每个客户端连接之后,会有一个独立的 SocketChannel与它通信,这个SocketChannel会在用户的整个生存周期中存在。用户如果断开连接,服务器会得到-1,并且会抛出 Connectionreset异常,通过捕获这两个特征,可以在用户意外断开连接后清理相关的资源。由于NIO是异步通信的,所以没有复杂的线程管 理。二、通信协议这个项目并没有复杂的通信指令,命令数量很有限,但是还是有个关键问题需要关注:流量。为 了尽量减小流量,我们使用字节代替字符串来保存系统指令,这样可以使流量减少一半,比如使用一个字节来保存

5、一张扑克牌,字节高位表示花色,字节低位表示数 字,如果0代表黑桃,那么黑桃三就应该是0x03,这个需要靠位操作来实现:1. intm=0;2. intn=3;3. bytecard=(byte)(m)4)|(byte)n;/m左移四位,然后与n左或操作游戏中需要传递用户的积分,这是一个大整数,使用四个字节来保存比较保险,将整数转换为四个字节的操作如下:1. publicstaticbytetranslateLong(longmark)2. 3. byteb=newbyte4;4. for(inti=0;i(24-i*8);7. 8. returnb;9. 将四个字节转回来的操作如下:1. pu

6、blicstaticlongtranslateByte(byteb)2. 3. intmask=0xff;4. inttemp=0;5. intres=0;6. for(inti=0;i4;i+)7. 8. resConnectionFactory;4. importmons.dbcp.java.html target=_blankBasicDataSource;5. importmons.dbcp.java.html target=_blankDataSourceConnectionFactory;6.7. privatestaticBasicDataSourcebds=newBasicDa

7、taSource();8. privatestaticConnectionFactoryfac=null;9.10. /初始化连接池11. bds.setDriverClassName(“org.postgresql.Driver”);/数据库驱动程序12. bds.setUrl(“jdbc:postgresql:/localhost:5432/myDB”);/数据库url13. bds.setUsername(“postgres”);/dba帐号14. bds.setPassword(“XXXXXXXX”);/密码15. bds.setInitialSize(100);/初始化连接数量16.

8、 bds.setMaxIdle(10);/最大idle数17. bds.setMaxWait(1000*60);/超时回收时间18.19. fac=newDataSourceConnectionFactory(bds);/得到连接工厂20. java/sql/Connection.java.html target=_blankConnectionconn=fac.createConnection();/从池中获得连接21. conn.close();/释放连接,回到池中22.23. /销毁连接池24. bds.close();25. bds=null;26. fac=null;请自行处理操作中

9、的各种异常。四、扑克牌的生成游戏中需要为用户生成随机的扑克牌,首先我们需要初始化一副牌,放到一个Hashmap中,每张牌以一个字节表示,高为代表花色,的为代表数字,生成整副牌:1. privatestaticHashMapcards=newHashMap();2.3. inttmp=0;4. for(inti=0;i4;i+)5. for(intm=0;m13;m+)6. tmp=(byte)(i)Integer(i*13+m),newjava/lang/Byte.java.html target=_blankByte(byte)tmp);8. 9. 10.11. cards.put(newj

10、ava/lang/Integer.java.html target=_blankInteger(53),newjava/lang/Byte.java.html target=_blankByte(byte)0x4d);/大王12. cards.put(newjava/lang/Integer.java.html target=_blankInteger(54),newjava/lang/Byte.java.html target=_blankByte(byte)0x4e);/小王 如何随机地得到其中的N张牌呢?我们的做法是生成一个0-55的随机数,用这个随机数作主键从Hashmap中获得对象,

11、取得之后,把该对象从队列中删 除,以免重复取得。由于java中的随机数是根据时间生成的,所以有可能导致用户得到的牌不够散,每个用户都摸到一条龙岂不是笑话?所以在生成随机数的时 候我们加入了一个大素数来作运算:1. longcardId=newjava/lang/Long.java.html target=_blankLong(java/lang/Math.java.html target=_blankMath.round(java/lang/Math.java.html target=_blankMath.random()*87)%55).intvalue();通过修改这个大素数,可以控制某个

12、用户的牌比较好。五、线程 实际上本系统并没有复杂的线程管理,但是我想提供一个控制台让管理员可以管理游戏主线程,可以让它停止、中段、恢复、重启动,本来的设计是管理员通过与 线程A打交道,通过A去管理主线程B,但是熟悉java线程的朋友都知道,线程互相管理基本上就是不实际的,举个最简单的例子,A如何销毁B?也许你会说 调用B的destroy()方法就好了,网上很多讲解java线程的资料也确实是这么说的,但是他们都是鬼扯的,自己去看看java源代码 吧,Thread.destroy()方法的实际代码如下:1. publicvoiddestroy()2. 3. thrownewjava/lang/No

13、SuchMethodError.java.html target=_blankNoSuchMethodError();4. 事实真相是,Thread.destroy()方法自始至终就没有被实现过。所有写文章,教别人用这个方法销毁线程的人,都去撞墙吧,丢人丢大了。最好的办法是A负责生成一个B并且启动它,然后B自己管理生存周期,A和B通过使用可共享的方法来通信,这是sun推荐的做法。六、异步消息 用户玩牌的过程中,有很多东西需要记录下来,比如记录用户的积分、等级变化,记录玩牌日志供数据统计等,当用户数量很多的时候,在数据库中记录这些信息 会很耗费资源,用户玩了一局之后会可能会等待很长时间。解决这个

14、问题的方法是利用J2EE的消息bean来提供异步通信的机制,需要记录数据的时候,系统 会封装一个值对象,发送给J2EE容器,这个操作是很快的,完成之后就返回,用户可以继续操作,不用关心消息何时被处理。J2EE的消息框架具备如下特征:消息一定会被阅读,而且只阅读一次。JMS框架有自己的算法,把消息缓冲到硬盘,就算J2EE服务器死掉,消息也不会丢失。系统采用点对点的Queue消息队列,可以保证同等优先级的消息先进先出。 在Jboss4.0中,部署消息Bean和Queue队列,都比weblogic8.1来的容易,只需要在jboss.xml中声明消息目的地,如 果jboss发现该目的地不存在的话,会自

15、动建立一个,实在很简单。关于消息bean的开发与部署,我有专门的文章描述(参见我的 blog:)。七、启动与退出为了让系统具备让 人满意的性能,应该尽量多的重用对象,减少创建新对象。比如上面提到的消息发送,我们的操作是提供一个静态类,在系统启动的时候就初始化,保持与JMS服 务器的连接,系统发送消息的时候,不用再去查询JNDI和生成QueueConnectionFactory,这样可以提高系统响应速度。 在数据库连接池的问题上,我们也采用同样的操作,启动的时候初始化N个连接。但是如果在关闭进程的时候不做任何操作,会导致JMS抛出socket异 常,虽然没什么大的影响,但总显得不专业,而且池中的

16、连接不被释放的话,也可能导致问题。最好能够让系统像jboss等控制台程序一样,ctrl+c之后 能够执行操作,释放资源再退出。我们可以通过给进程/线程加上一个Hook来实现,windows程序员应该对这个非常熟悉。Hook应该是一个线程方法,如下:1. publicclassHookextendsjava/lang/Thread.java.html target=_blankThread2. 3. publicvoidrun()4. 5. /释放数据库连接,销毁连接池6. /关闭与JMS的连接7. 8. 在主线程中加入:1. java/lang/Runtime.java.html target=_blankRuntime.getRuntime().addShutdownHook(newHook();那么进程/线程会在退出的时候执行Hook的run方法,清理资源。

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!