服務端:
1 import java.io.*; 2 3 import java.net.*; 4 5 import java.util.*; 6 7 public class ChatServer { 8 9 boolean stat = false; 10 11 ServerSocket ss = null; 12 13 List<Client> clients = new ArrayList<Client>();//用於存客戶端 14 15 public static void main(String[] args) { 16 17 new ChatServer().start(); 18 19 } 20 21 public void start(){ 22 23 try { 24 25 ss = new ServerSocket(8888); 26 27 stat = true; 28 29 } catch(BindException e){ //Sever端已經執行,當重複執行時拋異常 30 31 System.out.println("埠正在使用中。。。。"); 32 33 System.out.println("請關掉相關程式並重新執行伺服器!"); //還會拋別的異常,所以直接關閉視窗 34 35 System.exit(0); 36 37 } catch(IOException e) { 38 39 e.printStackTrace(); 40 41 } 42 43 try{ 44 45 while(stat){ 46 47 Socket s = ss.accept(); 48 49 System.out.println("a client connected!" ); //測試語句寫在最左邊,以後沒用可以刪除或注掉 50 51 Client c = new Client(s); //每建立一個客戶端,就new一個客戶端物件,啟動一個執行緒 52 53 new Thread(c).start(); 54 55 clients.add(c); //勿忘寫,將每個客戶端加入到容器裡 56 57 } 58 59 } catch (IOException e) { 60 61 e.printStackTrace(); 62 63 } finally { 64 65 try { 66 67 ss.close(); 68 69 } catch (IOException e) { 70 71 e.printStackTrace(); 72 73 } 74 75 } 76 77 } 78 79 class Client implements Runnable { 80 81 private Socket s; 82 83 private DataInputStream dis; 84 85 private DataOutputStream dos; 86 87 private boolean cont = false; 88 89 public Client(Socket s){ 90 91 this.s = s; 92 93 try { 94 95 dis = new DataInputStream(s.getInputStream());//初始化 96 97 dos = new DataOutputStream(s.getOutputStream()); 98 99 cont = true; 100 101 } catch (IOException e) { 102 103 e.printStackTrace(); 104 105 } 106 107 } 108 109 public void send(String str){ //用於傳送給客戶端 110 111 try { 112 113 dos.writeUTF(str); 114 115 } catch (IOException e) { 116 117 clients.remove(this); //移除那個退出的物件 118 119 System.out.println("一個客戶退出了"); 120 121 //e.printStackTrace(); 122 123 } 124 125 } 126 127 public void run() { 128 129 try{ 130 131 while(cont){ 132 133 String str = dis.readUTF(); //阻塞式方法 134 135 System.out.println(str); 136 137 for(int i=0; i<clients.size(); i++){ 138 139 Client c = clients.get(i); //取客戶端 140 141 c.send(str); 142 143 } 144 145 /* 另外兩種方法,但不適用,它會鎖定服務端 146 147 for(Iterator<Client> it = clients.iterator(); it.hasNext();){ 148 149 Client c = it.next(); 150 151 c.send(str); 152 153 } 154 155 Iterator<Client> it = clients.iterator(); 156 157 while(it.hasNext()){ 158 159 Client c = it.next(); 160 161 c.send(str); 162 163 } 164 165 */ 166 167 } 168 169 } catch (EOFException e){ //readUTF()阻塞式方法,所以關閉客戶端會拋異常 170 171 System.out.println("Client closed!"); 172 173 } catch (IOException e) { 174 175 e.printStackTrace(); 176 177 } finally { 178 179 try { 180 181 if(dis != null) dis.close(); 182 183 if(dos != null) dos.close(); 184 185 if(s != null) { 186 187 s.close(); 188 189 s = null;//更嚴格的方法,等於空就沒人去用了,垃圾收集器就回收走 190 191 } 192 193 } catch (IOException e) { 194 195 e.printStackTrace(); 196 197 } 198 199 } 200 201 } 202 203 } 204 205 }
客戶端:
import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; public class ChatClient extends Frame { Socket s = null; DataOutputStream dos = null; DataInputStream dis = null; private boolean cont = false; TextField tfTxt = new TextField(); TextArea taContent = new TextArea(); Thread tRecv = new Thread(new RecvThread()); public static void main(String[] args) { new ChatClient().launchFrame(); } public void launchFrame() { setLocation(400, 300); this.setSize(300, 300); add(tfTxt,BorderLayout.SOUTH); add(taContent,BorderLayout.NORTH); pack(); //包在一起,去掉中間空著的 this.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ disconnect(); System.exit(0); } }); tfTxt.addActionListener(new TfListent()); setVisible(true); connect(); tRecv.start(); //啟動執行緒 } public void connect(){ try { s = new Socket("127.0.0.1",8888);//注意不要定義成Socket s,這就成了區域性變數而不是成員變數了 System.out.println("connected!"); dos = new DataOutputStream(s.getOutputStream()); dis = new DataInputStream(s.getInputStream()); cont = true; } catch (UnknownHostException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void disconnect(){ try { dos.close(); dis.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } /*//無法解決readUTF阻塞式方法 try { cont = false; //關閉執行緒 tRecv.join(); //合併執行緒,徹底讓他停止 } catch (InterruptedException e) { e.printStackTrace(); } finally { try { dos.close(); //執行緒停止之後才能關流,不然拋SocketException異常 dis.close(); s.close(); } catch (IOException e) { e.printStackTrace(); } } */ } private class TfListent implements ActionListener { public void actionPerformed(ActionEvent e) { String str = tfTxt.getText().trim(); tfTxt.setText(""); try { dos.writeUTF(str); dos.flush(); } catch (IOException e1) { e1.printStackTrace(); } } } private class RecvThread implements Runnable{ public void run() { try { while(cont){ String str = dis.readUTF(); taContent.setText(taContent.getText() + str + '\n'); } } catch (SocketException e){ System.out.println("退出了,bye!"); } catch (IOException e) { e.printStackTrace(); } } } }
簡單的聊天程式,主要用到的是Socket,執行緒以及流
如果沒看懂可以去我部落格