一、概述
1.目标:在上一个版本非线程的聊天系统中,出于要不断监听接收新client和接收client发出的信息,把accept()和DataInputStream.readUTF()分别写在了while()死循环里,由于俩方法都是阻塞性方法,所以一方阻塞,另一方永远得不到执行,所以,在上述代码中,只能监听第一个client的发送信息,新的client永远连接不上。
2.思路:
(1)把socet.accept()接收线程和DataInputStream.readUTF()的处理分开,把前者交给server端的处理,server端把接收到的clent封装到线程里,把DataInputStream.readUTF()的逻辑交给线程处理。
(2)采用异步IO
二、代码
1.ChatServer.java
import java.io.DataInputStream; import java.io.EOFException; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.UnknownHostException; public class ChatServer{ private ServerSocket ss = null; private boolean started = false; public static void main(String[] args) { new ChatServer().start(); } public void start(){ try { ss = new ServerSocket(8888); started = true; } catch (IOException e1) { e1.printStackTrace(); } try { while(started){ //!!!!!注意accept()是阻塞性方法,当被readUTF()阻塞时它不会被执行 Socket s = ss.accept(); System.out.println("a client connect------"+s); new Thread(new Client(s)).start(); } } catch (EOFException e) { System.out.println("客户端已关闭!"); } catch (IOException e) { e.printStackTrace(); }finally{ try { //if(dis != null ) dis.close(); //if(s != null ) s.close(); if(ss != null ) ss.close(); } catch (Exception e) { e.printStackTrace(); } } } private class Client implements Runnable{ private Socket s; private DataInputStream dis = null; boolean bConnect = false; public Client(Socket s) { super(); this.s = s; try { dis = new DataInputStream(s.getInputStream()); bConnect = true; } catch (IOException e) { e.printStackTrace(); } } @Override public void run() { try { while(bConnect){ //!!!!!注意readUTF()是阻塞性方法 System.out.println(dis.readUTF()); } } catch (EOFException e) { System.out.println("客户端已关闭!"); } catch (IOException e) { e.printStackTrace(); }finally{ try { if(dis != null ) dis.close(); if(s != null ) s.close(); } catch (Exception e) { e.printStackTrace(); } } } } }
2.ChatClient.java
import java.awt.BorderLayout; import java.awt.Button; import java.awt.Frame; import java.awt.TextArea; import java.awt.TextField; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.DataOutputStream; import java.io.IOException; import java.io.OutputStream; import java.net.Socket; import java.net.UnknownHostException; public class ChatClient extends Frame{ private TextField tfText; private TextArea taContent; // private Button btnSend; private Socket socket; private DataOutputStream dos; public void launchFrame(){ addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { disconnect(); System.exit(0); } }); tfText = new TextField(); taContent = new TextArea(); // btnSend = new Button("发送"); // // btnSend.addActionListener(new ActionListener() { // @Override // public void actionPerformed(ActionEvent e) { // //taContent.setText(taContent.getText()+" "+tfText.getText()); // //tfText.setText(""); // try { // DataOutputStream dos = new DataOutputStream(socket.getOutputStream()); // dos.writeUTF(tfText.getText()); // dos.close(); // socket.close(); // } catch (IOException e1) { // e1.printStackTrace(); // } // } // }); tfText.addActionListener(new TFListener()); add(taContent,BorderLayout.NORTH); add(tfText,BorderLayout.CENTER); // add(btnSend,BorderLayout.SOUTH); setLocation(300, 100); pack(); setVisible(true); connect("localhost", 8888); } //当调用了此方法,会自动把成员变量给socket连接上server public void connect(String address, int port){ try { socket = new Socket(address, port); dos = new DataOutputStream(socket.getOutputStream()); } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } //退出时释放资源 public void disconnect(){ try { if(dos != null ) dos.close(); if(socket != null ) socket.close(); } catch (IOException e) { e.printStackTrace(); } } class TFListener implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { taContent.setText(taContent.getText().trim()+" "+tfText.getText()); try { dos.writeUTF(tfText.getText()); dos.flush(); tfText.setText(""); //dos.close(); //socket.close(); } catch (IOException e1) { e1.printStackTrace(); } } } public static void main(String[] args) { new ChatClient().launchFrame(); } }
三、运行结果