Socket的入门案例(中)
2018-01-11 16:19
435 查看
上一篇[《Socket的入门案例(上)》](http://blog.csdn.net/demoaop/article/details/78961746)讲到的是最简单的一个通信模型。即:客户端发送简单的字符串到服务器端,服务器端接收到字符串后再简单处理一下,返回给客户端加工后的数据。上一篇的重点在于了解Socket通信的基本模型和一些模板代码,此篇的案例进一步展开和深入。 客户端传递的信息可以从没有含义的字符串变成一个有意义的字符串,比如:类名“com.aishang.socket.Computer”以及一个方法的签名“add(3,5)”,当客户端把类名和方法的签名通过Socket流传递到服务端后,服务器端先处理一下从这个字符串中切分出来类名:“com.aishang.socket.Computer”、方法名“add”和参数列表:“3,5”。而在服务器端其实是有这个业务类和方法的声明的:
package com.aishang.socket; public class Computer { //加法计算 public int add(int a,int b){ return (a+b); } }
服务器端从Socket流中获得类名 “com.aishang.socket.Computer”后,利用反射技术构造一个类的实例:
Class clazz = Class.forName(className); Object obj = clazz.newInstance();
然后再从这个类的字节码文件对象中获得到方法对象
Method method = clazz.getMethod(methodName, int.class,int.class);
最后通过反射的方式调用上面的Method对象
Object retValue = method.invoke(obj, Integer.parseInt(parameterList[0]), Integer.parseInt(parameterList[1]));
最后将调用的结果发回到客户端。总结一下:客户端其实只是向服务器端发送了一堆字符串,这堆字符串不是普通的字符串,是包含了调用服务器端的类名、方法名、实参列表信息的有价值的文字,当服务器端利用Socket流接收到这些信息后,反射调用服务器上的方法。为何要用反射?其实传递过来的都是字符,这个时候只有反射能解决这个问题。其实这就是远程消息调用的雏形。
以下是完整的代码:
服务器端代码:ServerService.class
public class ServerService { public static void main(String[] args) throws IOException { // 创建一个ServerSocket,绑定到服务器的3366端口上 ServerSocket server = new ServerSocket(); server.bind(new InetSocketAddress("localhost", 3366)); System.out.println("服务器开启了"); //服务器一直等着接受客户端的接入请求 while (true) { //Socket.accept()方法是一个阻塞方法,会一直等待客户端 Socket socket = server.accept(); //当有客户端请求,启动服务器上的线程去执行任务,此时服务器继续等待客户端接入 System.out.println("启动了一个线程负责通信"); new Thread(new ServerTask(socket)).start(); } } }
线程任务:ServerTask.class
public class ServerTask implements Runnable { Socket socket ; InputStream in=null; OutputStream out = null; public ServerTask(Socket socket) { this.socket = socket; } @Override public void run() { try { //从socket连接中获取到与client之间的网络通信输入输出流 in = socket.getInputStream(); out = socket.getOutputStream(); //1.从网络通信输入流中读取客户端发送过来的数据 //将Socket输入流中的数据(客户端发送过来的数据在in中)用BufferedReader重新包装一下 //这样可以利用BufferedReader的方法按行读取 BufferedReader br = new BufferedReader(new InputStreamReader(in)); //注意:socketinputstream的读数据的方法都是阻塞的 //阻塞的意思:没有接受到数据的时候,服务端这个线程任务什么也不做,一直等待 //做点事情,获取客户端发送过来的信息,里面包含有要调用的类名、方法名,实参 //根据通信双方的约定,客户端第一行发送类名,第二行发送方法名和实参列表 //获取类名 String className = br.readLine(); //方法名和实参列表 String methodAndParameter = br.readLine(); int beginIndex = methodAndParameter.indexOf("("); int endIndex = methodAndParameter.indexOf(")"); //获取方法名 String methodName = methodAndParameter.substring(0, beginIndex); //获取参数列表 String parameterList[] = methodAndParameter.substring(beginIndex+1, endIndex).split(","); Object retValue = null; try { //反射调用 //先弄到类的实例 Class clazz = Class.forName(className); Object obj = clazz.newInstance(); //获取到字节码文件对象中的方法 Method method = clazz.getMethod(methodName, int.class,int.class); retValue = method.invoke(obj, Integer.parseInt(parameterList[0]), Integer.parseInt(parameterList[1])); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } //2.将调用结果写到sokect的输出流中,以发送给客户端 //将Socket输出流用PrintWriter重新包装一下 PrintWriter pw = new PrintWriter(out); pw.println(retValue.toString()); pw.flush(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ try { in.close(); out.close(); socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
服务器端定义的业务方法(供远程调用):Computer.class
package com.aishang.socket; public class Computer { //加法计算 public int add(int a,int b){ return (a+b); } }
客户端:ClientService.class
public class ClientService { public static void main(String[] args){ Socket socket = null; InputStream inputStream = null; OutputStream outputStream = null; try { //创建Socket对象,向服务器发出请求建立连接 socket = new Socket("localhost", 3366); // 从socket中获取输入输出流 inputStream = socket.getInputStream(); outputStream = socket.getOutputStream(); //通过Socket输出流,向服务器发送信息 PrintWriter pw = new PrintWriter(outputStream); pw.println("com.aishang.socket.Computer"); pw.println("add(3,5)"); pw.flush(); System.out.println("客户端发送了方法调用信息"); //在没收到服务器端的返回信息前,客户端一直阻塞 BufferedReader br = new BufferedReader(new InputStreamReader(inputStream)); String result = br.readLine(); System.out.println("客户端收到服务端的信息:"+result); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } finally{ try { //完成通信 inputStream.close(); outputStream.close(); socket.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
相关文章推荐
- Python案例-网络编程-socket入门-server&client
- Socket的入门案例(上)
- 从Samples中入门IOS开发(四)------ 基于socket的网络编程
- websocket入门(1)——初识socket.io
- 嵌入式OS入门笔记-以RTX为案例:八.RTX的进程间通讯(二)
- 第21天(就业班) 过滤器知识入门级案例
- ZigBee入门之Socket----TCP/IP、Http与Socket
- OSPF Stub Area入门教程图解 (案例、过程、分析,并有配套的仿真链接)
- MapReduce入门案例深入分析以及切片源码简析
- Hadoop入门进阶课程9--Mahout介绍、安装与应用案例
- 02.ZooKeeper读书笔记之入门案例
- SpringBoot 整合 SpringData 入门案例(一)
- 入门案例
- Winsocket入门教程三:以Windows消息机制驱动的客户端程序
- socket.io 入门教程
- kylin从入门到实战:实际案例
- windows下C++的socket编程入门--文件传输
- 分布式服务框架Dubbo入门案例和项目源码
- C# Socket UDP 案例
- 关于spring中aop的一个入门案例