一、概述
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()+"\n\r"+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()+"\n\r"+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(); }}
三、运行结果