Java Socket之多线程通信
程序员文章站
2024-02-01 13:52:34
...
上一篇文章说到怎样写一个最简单的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分配给处于可运行状态的线程。