Java Socket之多线程通信

上一篇文章说到怎样写一个最简单的Java Socket通信,但是在上一篇文章中的例子有一个问题就是Server只能接受一个Client请求,当第一个Client连接后就占据了这个位置,后续Client不能再继续连接,所以需要做些改动。

当Server每次接受到一个Client的请求之后,都建立一个线程,然后继续等待下一个Client的连接请求。这样就不会阻塞Server端接收请求了。具体代码如下:

 

代码流程图如下:

 

 

服务端的代码

public class MyServer1 implements Runnable {
	
	private Socket socket;
	
	private String clientId;
	
	public MyServer1(Socket socket) {
		this.socket = socket;
	}

	public static void main(String[] args) throws IOException {
		int port = 9999;
		
		// 监听服务器端口
		ServerSocket server = new ServerSocket(port);
		System.out.println("listening on " + port);
		
		while(true) {
			Socket socket = server.accept();
			new Thread(new MyServer1(socket)).start();
		}
		
	}

	public void run() {
		// 设置客户端名称,方便区分不同client
		setClientId();
		System.out.println("the client " + this.getClientId() + " has connected!");
		// 获取客户端的输入流
		BufferedReader in = null;
		PrintWriter out = null;
		try {
			in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
			// 获取客户端的输出流
	                out = new PrintWriter(socket.getOutputStream());
	                while (true) {
				String msg = in.readLine();
				System.out.println("----------------------------------------------------");
				System.out.println("-------------client " + this.getClientId() + "--------------");
				System.out.println("----------------------------------------------------");
				System.out.println("\nServer received " + msg);
				
				if (msg.equals("bye")) {
					System.out.println("Server stoped!");
					break;
				} else {
					// 向客户端发送信息
					System.out.println("Server send " + msg + "\n");
					out.print("Server responsed " + msg);
					out.flush();
				}
	        }
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
			
	}
	
	public String getClientId() {
		return clientId;
	}

	public void setClientId() {
		Time now = new Time(new Date().getTime());
		this.clientId = socket.getInetAddress().getHostAddress() + "-" + now.toString();
	}

}

 

客户端代码

public class MyClient {

	public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
    	Scanner reader = new Scanner(System.in);
    	
    	// 创建客户端socket
    	Socket client = new Socket("localhost", 9999);
    	
    	// 获取客户端的输出流(获取服务器端的输入流)
        PrintWriter out = new PrintWriter(client.getOutputStream()); 
        // 获取客户端的输入流(获取服务器端的输出流)
        InputStream in = client.getInputStream();
        
        while (true) {
        	System.out.println("---------------------------");
            System.out.println("Input Something: ");
        	String msg = reader.nextLine(); 
        	
        	System.out.println("Client sended " +  msg);
            out.println(msg);  
            out.flush();  
            
            Thread.sleep(1000);
            
            byte[] buff = new byte[in.available()];  
            in.read(buff);  
            System.out.println(new String(buff, "UTF-8"));
            
            if (msg.equals("bye")) {  
            	System.out.println("Client stop!");
                break;  
            }
        }
        out.close();
        client.close();
	}

}

 

先运行MyServer1类,再运行两个MyClient类(相当与两个线程)。结果如下所示:

clent1(127.0.0.1-16:22:53)

---------------------------
Input Something: 
11
Client sended 11
Server responsed 11
---------------------------
Input Something: 
123
Client sended 123
Server responsed 123
---------------------------
Input Something: 
bye
Client sended bye

Client stop!

 

client2(1127.0.0.1-16:22:59)

---------------------------
Input Something: 
333
Client sended 333
Server responsed 333
---------------------------
Input Something: 
bye
Client sended bye

Client stop!

 

服务端

listening on 9999
the client 127.0.0.1-16:22:53 has connected!
the client 127.0.0.1-16:22:59 has connected!
----------------------------------------------------
-------------client 127.0.0.1-16:22:59--------------
----------------------------------------------------

Server received 333
Server send 333

----------------------------------------------------
-------------client 127.0.0.1-16:22:53--------------
----------------------------------------------------

Server received 11
Server send 11

----------------------------------------------------
-------------client 127.0.0.1-16:22:53--------------
----------------------------------------------------

Server received 123
Server send 123

----------------------------------------------------
-------------client 127.0.0.1-16:22:53--------------
----------------------------------------------------

Server received bye
Server stoped!
----------------------------------------------------
-------------client 127.0.0.1-16:22:59--------------
----------------------------------------------------

Server received bye
Server stoped!

 

这种实现方式有以下不足之处

1、服务器创建和销毁工作线程的开销很大;

2、活动的线程也消耗系统资源。每个线程本身都会占用一定的内存(每个线程需要大约1MB内存),这样就很容易导致系统的内存不足;

3、Java虚拟机会为每个线程分配独立的堆栈空间,工作线程数目越多,系统开销越大,而且增加了Java虚拟机调度线程的负担,增加了线程之间同步的复杂性,提高了线程死锁的可能性。

4、工作线程的许多时间都浪费在阻塞I/O操作上,Java虚拟机需要频繁地转让CPU的使用权,使进入阻塞状态的线程放弃CPU,再把CPU分配给处于可运行状态的线程。

 

展开阅读全文

没有更多推荐了,返回首页