Java网络IO通信:Socket

原创
2017/03/29 10:29
阅读数 20

1. Socket通信原理

Socket的底层数据传输使用的是SocketStream,本质上还是属于IO流。Socket的通信分为客户端和服务器端。客户端主要向服务器端发送请求和接受返回值;服务器端用于接收客户端请求,处理请求及返回处理结果。下面从两个方面介绍其基本原理:

1.1  服务器端的流程

1)服务器端首先要启动监听。监听使用的类ServerSocket,创建该类的实例,然后调用bind方法绑定监听的IP地址和端口号。然后调用accept方法进行监听,此时IO阻塞一直到有请求。

2)当服务器端监听到客户端的请求,则accept方法会返回一个Socket对象,这时候已经与客户端建立了Socket通道,使用Socket的getInputStream()方法获取通道输入流,通过输入流获取客户端发送的请求数据。

3)获取客户端的请求数据后,服务器开始调用相应的方法等来处理。接着使用socket获取输出流getOutputStream(),将结果写回到客户端。

4)最后一步,关闭输入输出流及socket通道。

需要注意的是:使用socketinputstream读取数据都是祖阻塞的。

1.2 客户端流程

 1)创建Socket对象,该对象绑定到服务器监听的IP地址和端口号。

 2)同样用getInoutStream和getOutputStream获取输入输出流接受数据和发送数据。

总结:从上述流程可以看出,在服务器端只需要使用ServerSocket进行监听客户端请求,实际的通信是由Socket底层的输入输出流完成的。Socket很大的缺点是读取数据时会发生阻塞。

 

2. Socket的实例

在该实例中有详细的代码注解。

服务器端代码的实现:

package com.dd171290.socket;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

public class UserServer {

	
	@SuppressWarnings("resource")
	public static void main(String[] args) throws IOException {
		//服务器端监听客户端的请求,使用的类是ServerSocket
		ServerSocket serverSocket=new ServerSocket();
		//绑定监听的ip地址和端口号
		serverSocket.bind(new InetSocketAddress("localhost", 9920));
		//开始监听客户端请求,此时IO阻塞,一直到有新的请求时被激活,为了能够处理多客户端发来的请求
		//使用线程来处理每一次请求的业务
		while(true){
			Socket socket=serverSocket.accept();
			new Thread(new ServiceDeal(socket)).start();
		}
	}
}

线程的业务处理类,通过反射实现目标类的调用:

package com.dd171290.socket;


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.net.Socket;

public class ServiceDeal implements Runnable {

	Socket socket;
	InputStream inputStream=null;
	OutputStream outputStream=null;
	public ServiceDeal(Socket socket) {
		this.socket=socket;
	}

	public void run() {
		//开始处理业务逻辑
		
		//先获取到客户端的请求输入流
		try {
			inputStream=socket.getInputStream();
			BufferedReader reader=new BufferedReader(new InputStreamReader(inputStream));
			//从网络中读取客户端发送过来的数据流
			//使用socketinputstream读取数据都是祖阻塞的。
			String request=reader.readLine();
			
			//获取到了请求数据后,开始调用相对应的业务逻辑处理,这里采用的是反射来处理业务并将结果放回给客户端。
			//为了方便,这里约定用空格来分割不同的参数
			String [] params=request.split(" ");
			String className=params[0].trim();//服务端调用类所在包的路径
			String method=params[1].trim();//调用方法的名字
			String arg=params[2].trim();//默认传递一个参数
			System.out.println("packages:"+className);
			System.out.println("method:"+method);
			System.out.println("args:"+arg);
			
			//获取Class对象
			Class<?> service=Class.forName(className);
			Object data=service.newInstance();
			Method method1=service.getMethod(method, String.class);
			Object result=method1.invoke(data, arg);
			System.out.println("返回的结果:"+result);
			
			//将结果返回给客户端
			System.out.println("开始向客户端返回结果!");
			outputStream=socket.getOutputStream();
			PrintWriter pWriter=new PrintWriter(outputStream);
			pWriter.println(result.toString());
			pWriter.flush();
			System.out.println("向客户端发送数据结束!!");
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				outputStream.close();
				inputStream.close();
				if(socket!=null)
				   socket.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

}

业务处理的目标类:

package com.dd171290.socket;

public class ReflectData {

	public String welcome(String msg) {
		return "welcome:"+msg;
	}
}

客户端代码实现:

package com.dd171290.socket;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

public class UserClient {

	
	public static void main(String[] args) throws Exception {
		// 向客户端发送请求
		Socket socket=new Socket("localhost", 9920);
		//获取输出流,发送数据
		PrintWriter pWriter=new PrintWriter(socket.getOutputStream());
		String mSg="com.dd171290.socket.ReflectData welcome client!";
		pWriter.println(mSg);
		pWriter.flush();
		
		
		//从服务器端读取返回的结果
		BufferedReader bReader=new BufferedReader(new InputStreamReader(socket.getInputStream()));
		String result=bReader.readLine();
		System.out.println(result);
	}
	
}

 

先启动服务端,运行的结果为:

packages:com.dd171290.socket.ReflectData
method:welcome
args:client!
返回的结果:welcome:client!
开始向客户端返回结果!
向客户端发送数据结束!!

客户端运行的结果:

welcome:client!

 

展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部