您的位置:首页 > 其它

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();
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: