在实施项目的过程中,一个项目一般是不会只是架构在一个服务器上,针对项目的各个部分分布在各自独立的服务器中。
例如手机网游的服务器架构:
其中架构这些服务器是一个复杂且技术含量相当高的工作,其中各个服务器之间的通信是一个很重要的部分,登录服务器与游戏服务器,log服务器之间采用socket通信。
而GM服务器与游戏服务器之间的通信科采用Http通信。本文主要介绍GM服务器与游戏服务器之间的跨服通信:
以GM服务器获取游戏服务器中角色的信息的过程为例。
游戏服务器中执行查找角色并返回角色信息的类和方法为:PlayerController.getPlayerInfo(long uid);
那么GM服务器只需通过PostCall(String serverName, String className, String methodName, Map<ClassType,Value> params);方法即可调用游戏服务器的业务逻辑处理.PostCall的过程通过配置表读取serverName的地址,并将类名,方法名和参数名通过ObjectOutStream读到流中发送对应服务器中并接受服务器返回的Object。
PostCall具体实现如下:
1 HttpURLConnection conn = null; 2 ObjectOutputStream os = null; 3 ObjectInputStream in=null; 4 try { 5 String path = GmtoolXml.getInstance().getServerPath(server); 6 System.out.println("connect server: " + server + " : " + path); 7 List<Map> params = GetParamBuffer(); 8 9 URL url = new URL(path); 10 conn = (HttpURLConnection) url.openConnection(); 11 conn.setRequestMethod("POST"); 12 conn.setReadTimeout(2000); 13 conn.setDoOutput(true); 14 15 ByteArrayOutputStream oss = new ByteArrayOutputStream(); 16 os = new ObjectOutputStream(oss); 17 os.writeUTF(className); 18 os.writeUTF(methodName); 19 os.write(params.size()); 20 for (int i = 0; i < params.size(); i++) { 21 Map param = (Map) params.get(i); 22 Object key = param.keySet().toArray()[0]; 23 os.writeObject(key); 24 os.writeObject(param.get(key)); 25 } 26 os.flush(); 27 28 OutputStream outStrm = conn.getOutputStream(); 29 outStrm.write(oss.toByteArray()); 30 31 if (conn.getResponseCode() == 500) { 32 // DataInputStream di = new 33 // DataInputStream(conn.getInputStream()); 34 // System.out.println(di.readUTF()); 35 return null; 36 } else { 37 in = new ObjectInputStream(conn.getInputStream()); 38 return in.readObject(); 39 } 40 } catch (Exception ex) { 41 try { 42 in.close(); 43 os.close(); 44 } catch (IOException e) { 45 e.printStackTrace(); 46 } 47 conn.disconnect(); 48 ex.printStackTrace(); 49 Logger.getLogger(Net.class.getName()).log(Level.SEVERE, null, ex); 50 return null; 51 } finally { 52 try { 53 in.close(); 54 os.close(); 55 } catch (IOException e) { 56 e.printStackTrace(); 57 } 58 conn.disconnect(); 59 }
至于游戏服务如何来接受和处理GM服务器传递的数据流,你可以使用Netty做架构,启用一个端口用来监听来自GM服务器的请求,解析数据,并执行对应的方法。
以下是我解析来自GM服务器的数据流,并执行对应方法的代码:
1 public void exec(HttpRequest request, HttpResponse response) { 2 // TODO Auto-generated method stub 3 ByteArrayOutputStream bos = null; 4 ObjectOutputStream oos = null; 5 try { 6 ChannelBuffer cb = request.getContent(); 7 byte[] b = cb.array(); 8 ByteArrayInputStream bis = new ByteArrayInputStream(b); 9 ObjectInputStream data = new ObjectInputStream(bis); 10 String className = data.readUTF(); 11 String methodName = data.readUTF(); 12 int count = data.read(); 13 Class c = Class.forName(className); 14 //#debug 15 System.out.println(className + "." + methodName); 16 List<Class> cl = new ArrayList<Class>(); 17 List<Object> vl = new ArrayList<Object>(); 18 for (int i = 0; i < count ; i++) { 19 cl.add((Class) data.readObject()); 20 vl.add(data.readObject()); 21 } 22 Class[] cls = new Class[cl.size()]; 23 cl.toArray(cls); 24 String mk = toMethodKey(className, methodName, cls); 25 Method m = methods.get(mk); 26 if (m == null) { 27 m = c.getMethod(methodName, cls); 28 methods.put(mk, m); 29 } 30 Object[] values = new Object[vl.size()]; 31 vl.toArray(values); 32 Object o = m.invoke(c, values); 33 bos = new ByteArrayOutputStream(); 34 oos = new ObjectOutputStream(bos); 35 oos.writeObject(o); 36 oos.flush(); 37 response.getContent().writeBytes(bos.toByteArray()); 38 cl.clear(); 39 vl.clear(); 40 } catch (Exception e) { 41 e.printStackTrace(); 42 try { 43 response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);//.setStatus(HttpStatus.SC_INTERNAL_SERVER_ERROR); 44 bos = new ByteArrayOutputStream(); 45 DataOutputStream dos = new DataOutputStream(bos); 46 dos.writeUTF(e.getClass() + "." + e.getMessage()); 47 bos.flush(); 48 response.getContent().writeBytes(bos.toByteArray()); 49 bos.close(); 50 } catch (IOException e1) { 51 // TODO Auto-generated catch block 52 e1.printStackTrace(); 53 } 54 } finally { 55 if (oos != null) 56 try { 57 oos.close(); 58 } catch (IOException e) { 59 // TODO Auto-generated catch block 60 e.printStackTrace(); 61 } 62 } 63 }
本人技术水平不足,希望各位朋友予以指点,共同进步,Eamil:zhong678*yeah.net , QQ:982925115