基于GUI的简单聊天室02
服务器端
与上一篇相比,加进了线程内部类,解决多个客户端连接时,服务器无法全部响应的问题。
利用List集合来装载客户端的对象。
还需要注意全局变量的应用。
1 /** 2 * 相比01,加进了线程内部类,解决多个客户端连接时,服务器无法全部响应的问题。 3 * @author Administrator 4 * 5 */ 6 7 import java.io.DataInputStream; 8 import java.io.DataOutputStream; 9 import java.io.EOFException; 10 import java.io.IOException; 11 import java.net.BindException; 12 import java.net.ServerSocket; 13 import java.net.Socket; 14 import java.util.ArrayList; 15 import java.util.List; 16 17 public class ChatSever02 { 18 // 布尔类型变量表示服务器是否开着 19 boolean started = false; 20 21 ServerSocket ss = null; 22 23 List<Client> clients = new ArrayList<Client>(); 24 25 public static void main(String[] args) { 26 new ChatSever02().start(); 27 } 28 29 public void start() { 30 try { 31 // 建立服务端,8888为端口号 32 ss = new ServerSocket(8888); 33 started = true; 34 } 35 catch (BindException e) { 36 System.out.println("Socket has been used !"); 37 System.out.println("请重启服务器 !"); 38 System.exit(0); 39 }catch (IOException e) { 40 e.printStackTrace(); 41 } 42 // 服务器开启后,started变为true 43 try { 44 // 接受客户端的连接 45 while (started) { 46 Socket s = ss.accept(); 47 //构造Client对象 48 Client c = new Client(s); 49 clients.add(c); 50 System.out.println("一个客户连接"); 51 //启动线程 52 new Thread(c).start(); 53 } 54 } catch (Exception e) { 55 e.printStackTrace(); 56 } finally { 57 try { 58 ss.close(); 59 } catch (IOException e) { 60 e.printStackTrace(); 61 } 62 } 63 } 64 65 66 /** 67 * 建立线程内部类 68 */ 69 class Client implements Runnable{ 70 71 //要保有自己的Socket属性 72 private Socket s = null; 73 74 //自己的数据输入流 75 private DataInputStream dis = null; 76 77 private DataOutputStream dos = null; 78 79 private boolean bConnected = false ; 80 81 //采用构造方法,把Socket属性传进来 82 public Client(Socket s) { 83 //赋值给s 84 this.s = s ; 85 //将dis初始化 86 try { 87 dis = new DataInputStream(s.getInputStream()); 88 dos = new DataOutputStream(s.getOutputStream()); 89 //连接成功后,bConnected 变为true 90 bConnected = true ; 91 } catch (IOException e) { 92 e.printStackTrace(); 93 } 94 } 95 96 /** 97 * 发送信息的方法 98 */ 99 public void send(String str) { 100 try { 101 dos.writeUTF(str); 102 System.out.println(str); 103 } catch (IOException e) { 104 e.printStackTrace(); 105 } 106 } 107 @Override 108 public void run() { 109 try { 110 //while循环范围过大, 导致过一直报错; 111 while (bConnected) { 112 String str = dis.readUTF (); 113 //System.out.println(str); 114 //发送信息 115 for(int i = 0;i < clients.size(); i++) { 116 Client c = clients.get(i); 117 c.send(str); 118 //System.out.println(str); 119 } 120 121 /*利用迭代器 122 for(Iterator it = clients.iterator();it.hasNext();) { 123 Client c = it.next(); 124 c.send(str); 125 } 126 */ 127 /*利用迭代器第二版本 128 Iterator<Client> it = clients.iterator(); 129 while(it.hasNext()) { 130 Client c = it.next(); 131 c.send(str); 132 } 133 */ 134 } 135 }catch (EOFException e) { 136 137 System.out.println("Client Close !"); 138 }catch (IOException e) { 139 e.printStackTrace(); 140 }finally { 141 try { 142 if(dis != null) dis.close(); //再设置dis = null; 143 if(dos != null) dis.close(); 144 if(s != null) s.close(); 145 } catch (IOException e) { 146 e.printStackTrace(); 147 } 148 } 149 150 } 151 } 152 }
客户端也只是多了线程类来接收信息
import java.awt.BorderLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; import java.net.UnknownHostException; import javax.swing.JFrame; import javax.swing.JTextArea; import javax.swing.JTextField; /** * 完成图形界面 * @author Administrator * */ public class ChatClient extends JFrame{ JTextField jTextField = new JTextField(); JTextArea jTextArea = new JTextArea(); Socket s; //表示是否连上 private boolean bConnected = false; DataOutputStream dos; DataInputStream dis = null; public static void main(String[] args) { new ChatClient().launchFrame(); } public void launchFrame() { setLocation(200, 150); this.setSize(450, 450); this.add(jTextArea,BorderLayout.NORTH); this.add(jTextField,BorderLayout.SOUTH); jTextField.addActionListener(new TFListener()); //pack(); this.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent arg0) { disConnect(); System.exit(0); } });; setVisible(true); connect(); new Thread(new RecvThread()).start(); } /** * 建立连接的方法 * @throws IOException * @throws UnknownHostException */ public void connect() { try { s = new Socket("127.0.0.1",8888); //连接好后初始化 dos = new DataOutputStream(s.getOutputStream()); dis = new DataInputStream(s.getInputStream()); System.out.println("连接成功"); bConnected = true; } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 断开连接,关闭资源的方法 */ public void disConnect() { try { dos.close(); dis.close(); s.close(); } catch (IOException e1) { e1.printStackTrace(); } } /** * 内部类,实现监听 * 将文本框中的输入打印到文本域中 * */ private class TFListener implements ActionListener{ @Override public void actionPerformed(ActionEvent e) { String content = jTextField.getText().trim(); //jTextArea.setText(content); jTextField.setText(""); //将文本发送到服务器 try { //System.out.println(s); System.out.println(content); dos.writeUTF(content); dos.flush(); } catch (IOException e1) { e1.printStackTrace(); } } } /** * 线程类,用于接受信息 * */ private class RecvThread implements Runnable{ @Override public void run() { try { while(bConnected) { String str = dis.readUTF(); //System.out.println(str); jTextArea.setText(jTextArea.getText() + str +" "); } } catch (IOException e) { e.printStackTrace(); } } } }