首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > JAVA > J2SE开发 >

多个进程怎么共享同一个socket

2012-03-04 
多个进程如何共享同一个socket需求:为了使游戏平台和具体的游戏,比如QQ游戏大厅和地主,杀人,放火游戏进程

多个进程如何共享同一个socket
需求:为了使游戏平台和具体的游戏,比如QQ游戏大厅和地主,杀人,放火游戏进程分离,但是却有要共享同一个socket连接

C\C++实现:在windows c下编程实现可以用复制SOCKET句柄WSADuplicateSocket或共享内存的方式,但在java中不知用何种方式,或者类似的方式,我search了一下,似乎JOMP说的是共享内存,但却不知如何使用。还有真的有必要用这种方式实现游戏平台和具体的游戏分离吗,有什么更好的实现方式呢?

[解决办法]
JVM据我所知,没有什么高效的进程间的通信、共享机制。
因为,不同的操作系统,其进行间的通信、共享机制都有所不同,那么,
对于跨平台,可移植性,确实是一种挑战。

一般来讲,常见的Windows和Unix系统,都是基于线程的操作系统。
也就是说,CPU的时间片会按照系统的策略分配给每一个线程,而非进程。
那么,在没有什么特殊需求的情况下,我们都会选择多线程技术来编程,而非多进程技术。

还是说点有用的吧:
我想,楼主说的问题,应该是针对服务端的程序开发。
不知道,楼主对FTP协议是否有所了解。
我指的是,控制指令与实际文件传输使用不同Socket来传输。
(这样会使程序设计简单,逻辑会比较清晰)
所以,我当然也会推荐楼主采用这种思想,来设计游戏大厅与具体游戏的关系。

实际情况下,如果游戏大厅和具体的游戏采用同一个Socket传输,那么,具体游戏的增删,会影响到通信协议的修改。
而且,客户端的编程,也会比较复杂。
Java的进程间通信,一般都是用TCP、UDP或者RMI之类的东西来实现的。所以,Socket共享,好象不太现实。
这种情况下,大厅服务器会起到类似Socket代理服务器的作用。(也就是说,如果是游戏的数据,它会转发到对应的游戏服务器上)

我推荐的程序架构是这样的:
大厅服务器与客户端采用一个Socket进行通信,各游戏采用各自的Socket进行通信(因为不同的游戏,通信数据不同,协议也不尽相同)。
大厅服务器上存放一些跟游戏服务器的相关信息(比如服务器状态,服务器IP,游戏端口之类的)
客户端的开发就比较结构清晰了。
首先,开发和大厅服务器的程序。
其次,当有新游戏要添加至大厅的时候。只要在大厅服务器上添加相关的信息就可以了。
因为,游戏的客户端程序与游戏服务器程序,本身可以相对独立的成为一个系统。

不知道我这样解释,楼主是否明白。
没有解决楼主的问题,实在不好意思。

[解决办法]
先提一点:java有进程这种机制吗?就像linux一样,伪进程

------------------------
你还是没有建立在OO的基础上思考你的设计

只要你是OO的,你就能区分游戏大厅和各类游戏,因为你有大厅类,各种游戏类

然后做好分工,你的每个类负责干一些什么事情

具体到你的需求

类的生成和分配

程序运行后肯定首先有大厅类的实例,然后根据用户选择,大厅类生成对应的游戏类实例,让其运行

你完全可以大家同用一个socket

先生成socket,再生成大厅,把socket传给大厅
大厅生成socket的时候,大厅再把socket传给游戏类

你也可以各自使用自己的socket
这样socket就由类自己去创建

你还可以创建一个socketHelper
专门处理数据的收发

然后是分工
划分好那些数据应该由那些类负责处理
你所说的玩家进入、退出、逃跑等消息,这时应该是大厅类所负责处理的
如果每个游戏都需要"知晓" "这类"消息,那就由大厅根据需要去通知每个游戏类





[解决办法]
另外,我不是太明白你为什么强调用进程而不能用线程?
是因为你要求分离,并把程序分成不同的文件包吧,然后大厅运行游戏的时候大厅excus()一个jar?



[解决办法]

探讨
引用:
我要反问一下,设想一下,QQGame一开始运营的时候只有5个游戏,比如,双扣,杀人,放火,抢劫,偷窃;后来因为需求的原因想再加入另外四个游戏,但却不想去改动原先的代码(最多只在某个文件配置一下,告诉server我们又多了另外几个game),而在client,各个游戏和游戏大厅相互独立的,互相完全解耦,共享的是socket连接等,从扩展性角度来考虑,当然是这种方式好了,而你说的设计方式是把大厅和具体的游戏逻辑都捆绑在一起了,以后要扩展,加入游戏,就必须改动这些代码,这样的设计合理吗?


[解决办法]
添加游戏也只需要把编译好的类文件down下来放在合适的目录
然后把配置文件(游戏名-游戏类文件的对应关系)修改一下
大厅读取配置需要类文件new一个实例运行就可以了

(这里应该用到java的Class.load("xxx.class").newInstands()来创建实例)
[解决办法]
探讨
理解的很对,我们想把具体游戏和大厅完全独立开来,做到正真的解耦,以后新添加游戏的话,最多在大厅的配置文件里加入这个游戏的名单就行.当然server端和client端的设计又有所区别。

[解决办法]
我试了一下,我说的方法完全可行

######################## 游戏大厅工程 ###########
两个文件

1.接口,既大厅和游戏间建立的规则

Java code
public interface iGame {    public void gameLogic();}
[解决办法]
探讨
我试了一下,我说的方法完全可行

######################## 游戏大厅工程 ###########
两个文件

1.接口,既大厅和游戏间建立的规则


Java codepublic interface iGame {
public void gameLogic();
}



2.大厅程序


Java codeimport java.io.File;

public class Room {

private String[] myGames;

public Room()
{
File gameClassDir=new File("d:/games");




[解决办法]
也可以 大厅服务器代理 其他游戏服务器。


消息由大厅服务器转发给其他游戏服务器,这样 客户维护与大厅的Socket, 大厅维护与游戏服务器的Socket。

彼此隔离, 逃跑什么的很自然的监视到了。
[解决办法]
55楼的方法可行,但是有2个问题

1。Lib目录类冲突,潜在危机。
这个问题是这样的在各个游戏的lib目录中都使用了一个组建A,组建A中都有一个类org.test.Text类的start方法,该方法有2个参数签名。在以后的维护过程中这个组建3个方法签名,我们很自然的把新版本的包放置在新游戏的Lib目录中。但是一个问题暴露出来了,JVM在你2个版本的A组建中它只会装载1个,而且是首次找到的哪个。也就是说classpath中如果把新的配置到前面,就意味着所有使用老版本组建的游戏全部瘫痪,如果配置在后面,那么使用新版本的游戏将瘫痪,解决这个问题就是同名类隔离,也就是分别装载每个游戏各自的Lib目录。

2。部署/卸载,代价大。
这个问题是这样的,由于55楼的方法使用的是扩增classpath路径来装载游戏类路径,这个属性的生效是在JVM启动时,如果新增一个游戏到大厅中就需要重新启动整个游戏程序,此时就涉及到其他玩家必须强行下线,这样的情况我们况且认为能接受。但是如果是维护某一个游戏的一个小模块时。我们仍然需要重新启动整个游戏服务器。哪怕是更新一个没有人玩的游戏。都要引发整个游戏服务器重新启动。
这样频繁重新启动服务器对于玩家而言可能就不能接受了,随着时间推移游戏内容必然增加,问题1,问题2的潜在危机必然危机到游戏服务器。尤其在大量游戏服务出现时。
 问题2出现的原因很清楚是因为JVM装载类时候出现,查阅JVM类装载机智发现JVM类装载器有4部分:

根(Bootstrap) 装载器:该装载器没有父装载器,它是JVM实现的一部分,从sun.boot.class.path装载运行时库的核心代码。 
扩展(Extension) 装载器:继承的父装载器为根装载器,不像根装载器可能与运行时的操作系统有关,这个类装载器是用纯Java代码实现的,它从java.ext.dirs (扩展目录)中装载代码。 
系统(System or Application) 装载器:装载器为扩展装载器,我们都知道在安装JDK的时候要设置环境变量(CLASSPATH ),这个类装载器就是从Java.class.path(CLASSPATH 环境变量)中装载代码的,它也是用纯Java代码实现的,同时还是用户自定义类装载器的缺省父装载器。 
小应用程序(Applet) 装载器: 装载器为系统装载器,它从用户指定的网络上的特定目录装载小应用程序代码。 

对于我们游戏Lib目录没有相应的类装载器实现,如果热部署一个游戏时,java.ext.dirs扩展目录显然是新增加的,对于JVM不知道有新增加的类路径,这就需要重新启动JVM,部署代价很大。

相关类装载问题你可以去参看其他资料,我在69楼发了个地址是类装载这方面的问题你可以看看。

这里我只是提出了2点可能出现的潜在问题。
[解决办法]
探讨
55楼的方法可行,但是有2个问题

1。Lib目录类冲突,潜在危机。
这个问题是这样的在各个游戏的lib目录中都使用了一个组建A,组建A中都有一个类org.test.Text类的start方法,该方法有2个参数签名。在以后的维护过程中这个组建3个方法签名,我们很自然的把新版本的包放置在新游戏的Lib目录中。但是一个问题暴露出来了,JVM在你2个版本的A组建中它只会装载1个,而且是首次找到的哪个。也就是说classpath中如果把新的配置到前面,…

[解决办法]
每当添加一个game,是否都要添加这个组件lib,比如d:/games/ChuDaDi.jar进classpath呢,能否动态加载? 

不需要每个jar都加进classpath,因为我加的是games/* 也就是games下的所有jar


[解决办法]
已经解决了新加入游戏不需要重启大厅程序

使用URLClassLoader 来加载jar


更改过后的Room 程序


Java code
import java.io.File;import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;public class Room {    private String[] myGames;    private String[] myGamesClassNames;    private String[] myGamesJarAbsolutePath;            public Room()    {                    }        private void flushGames()    {                //这里的配置关系可以从配置文件中读取                File gameClassDir=new File("d:/games");        File[] gameClassFiles=gameClassDir.listFiles();        this.myGames=new String[gameClassFiles.length];        this.myGamesClassNames=new String[gameClassFiles.length];        this.myGamesJarAbsolutePath=new String[gameClassFiles.length];                for(int i=0 ;i<gameClassFiles.length;i++)        {            myGames[i]=gameClassFiles[i].getName().replaceAll(".jar", "");            myGamesClassNames[i] = gameClassFiles[i].getName().replaceAll(".jar", "");            myGamesJarAbsolutePath[i] = gameClassFiles[i].getAbsolutePath();        }            }        private void startGame(int index) throws InstantiationException, IllegalAccessException, ClassNotFoundException, MalformedURLException    {        String name=myGames[index];        String classNames=myGames[index];        String jarAbsolutePath=myGamesJarAbsolutePath[index];        URL jarUrl=new URL("file:/"+jarAbsolutePath);         URLClassLoader loader = new URLClassLoader(new URL[]{jarUrl});//加载对应的jar        Class c = loader.loadClass(classNames);        //用加载了jar的loader来加载对应的游戏类文件        iGame game=(iGame)c.newInstance();        game.gameLogic();    }        public void test()    {        System.out.println("游戏有:");        for(int i=0;i<myGames.length;i++)        {            System.out.println(i+" - "+myGames[i]);        }        int selected = Integer.parseInt(System.console().readLine());                try {            startGame(selected);        } catch (InstantiationException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IllegalAccessException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (ClassNotFoundException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (MalformedURLException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }        public static void main(String[] args)    {        Room r=new Room();        r.flushGames();        r.test();                r.flushGames();        r.test();                r.flushGames();        r.test();                r.flushGames();        r.test();            }} 


[解决办法]
这样也不需要配classpath了

只需要"java Room"即可

-------------------测试步骤

第一次d:/games里只放双扣

D:\workspace\sometest\room\bin>java Room

游戏有:
0 - ShuangKou

(先不要选,把其他两个游戏放进games目录)

0
this is ShuangKou Game running.......

(更新的游戏显示出来了,显示是当然的)

游戏有:
0 - ChuDaDi
1 - GongZhu
2 - ShuangKou

1

this is GongZhu Game running.......

(成功运行!!)


游戏有:
0 - ChuDaDi
1 - GongZhu
2 - ShuangKou
2
this is ShuangKou Game running.......
游戏有:
0 - ChuDaDi
1 - GongZhu
2 - ShuangKou


[解决办法]
另外

经过测试,已经加载过的游戏,再删除就不行了,因为文件被使用

不过我想如果是使用配置文件的
可以通过配置文件来设置成下次大厅运行时删除

---------------------------
另:
用URLClassLoader+配置文件的话,游戏的文件管理起来就更加方便了

游戏名 - 游戏类名 - 游戏jar文件绝对路径
[解决办法]
game工程能否应用到room下的组件lib? 

能用到,game用room的lib里的jar就像用java常用jar包一样,import进来就可以了

热点排行
Bad Request.