============================================================
1.實現server和client模型程序
============================================================
實現原理:
============================================================
服務器,使用ServerSocket監聽指定的端口,端口可以隨意指定(由於1024以下的端口通常屬於保留端口,
在一些操作系統中不可以隨意使用,所以建議使用大於1024的端口),
等待客戶連接請求,客戶連接后,會話產生;在完成會話后,關閉連接。
============================================================
客戶端,使用Socket對網絡上某一個服務器的某一個端口發出連接請求,一旦連接成功,打開會話;會話完成后,
關閉Socket。客戶端不需要指定打開的端口,通常臨時的、動態的分配一個1024以上的端口。
============================================================
服務器端代碼:
1 package com.b510.socket1703; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.net.ServerSocket; 6 7 /** 8 * 服務器斷的工作就是在指定的端口上監聽 9 * <li>建立連接</li> 10 * <li>打開輸出流</li> 11 * <li>封裝輸出流</li> 12 * <li>向客戶端發送數據</li> 13 * <li>關閉打開的輸出流</li> 14 * <li>關閉打開的socket對象</li> 15 * 16 * @author Hongten 17 * 18 * @time 2012-4-29 2012 19 */ 20 public class TestServer { 21 public static void main(String args[]) { 22 try { 23 // 指定服務器端的端口號為8888 24 ServerSocket s = new ServerSocket(8888); 25 while (true) { 26 // 建立連接 27 Socket socket = s.accept(); 28 // 打開輸出流 29 OutputStream os = socket.getOutputStream(); 30 // 封裝輸出流 31 DataOutputStream dos = new DataOutputStream(os); 32 // s<li>.getInetAddress()獲取遠程ip地址,s<li>.getPort()遠程客戶端的斷后好 33 // 向客戶端發送數據 34 dos.writeUTF("你好,客戶端地址信息: " + socket.getInetAddress() 35 + "\t客戶端通信端口號: " + socket.getPort()); 36 dos.writeUTF("i'm a server ,my name is hongten!"); 37 // 關閉打開的輸出流 38 dos.close(); 39 // 關閉打開的socket對象 40 socket.close(); 41 }// 開始下一此循環 42 } catch (IOException e) { 43 e.printStackTrace(); 44 } 45 } 46 }
客戶端代碼:
1 package com.b510.socket1703; 2 3 import java.io.*; 4 import java.net.Socket; 5 6 /** 7 * 客戶端 8 * @author Hongten 9 * 10 * @time 2012-4-29 2012 11 */ 12 public class TestClient { 13 public static void main(String args[]) { 14 try { 15 // 創建socket對象,指定服務器的ip地址,和服務器監聽的端口號 16 // 客戶端在new的時候,就發出了連接請求,服務器端就會進行處理,如果服務器端沒有開啟服務,那么 17 // 這時候就會找不到服務器,並同時拋出異常==》java.net.ConnectException: Connection 18 // refused: connect 19 Socket s1 = new Socket("127.0.0.1", 8888); 20 // 打開輸入流 21 InputStream is = s1.getInputStream(); 22 // 封裝輸入流 23 DataInputStream dis = new DataInputStream(is); 24 // 打印服務器端發送過來的信息 25 System.out.println(dis.readUTF()); 26 System.out.println(dis.readUTF()); 27 // 關閉輸入流 28 dis.close(); 29 // 關閉打開的socket對象 30 s1.close(); 31 } catch (IOException e) { 32 e.printStackTrace(); 33 } 34 } 35 }
如果服務器端沒有打開,這時候運行客戶端,出現的結果:
1 java.net.ConnectException: Connection refused: connect 2 at java.net.PlainSocketImpl.socketConnect(Native Method) 3 at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) 4 at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) 5 at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182) 6 at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) 7 at java.net.Socket.connect(Socket.java:518) 8 at java.net.Socket.connect(Socket.java:468) 9 at java.net.Socket.<init>(Socket.java:365) 10 at java.net.Socket.<init>(Socket.java:179) 11 at com.b510.socket1703.TestClient.main(TestClient.java:19)
如果服務器端先打開服務,這時候客戶端連接服務器端,出現的效果:
1 你好,客戶端地址信息: /127.0.0.1 客戶端通信端口號: 2800 2 i'm a server ,my name is hongten!
============================================================
2.實現單線程的聊天室
============================================================
服務器端代碼:
1 package com.b510.socket1704.simplechatroom; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.net.ServerSocket; 6 import java.net.SocketException; 7 8 /** 9 * 服務器端程序,在while循環中所執行的動作是: 10 * 聽,說,聽,說,聽,說... 11 * 12 * @author Hongten 13 * 14 * @time 2012-4-29 2012 15 */ 16 public class TestServer { 17 public static void main(String args[]) { 18 try { 19 //創建一個socket對象 20 ServerSocket s = new ServerSocket(8888); 21 //socket對象調用accept方法,等待連接請求 22 Socket s1 = s.accept(); 23 //打開輸出流 24 OutputStream os = s1.getOutputStream(); 25 //封裝輸出流 26 DataOutputStream dos = new DataOutputStream(os); 27 //打開輸入流 28 InputStream is = s1.getInputStream(); 29 //封裝輸入流 30 DataInputStream dis = new DataInputStream(is); 31 //讀取鍵盤輸入流 32 InputStreamReader isr = new InputStreamReader(System.in); 33 //封裝鍵盤輸入流 34 BufferedReader br = new BufferedReader(isr); 35 36 String info; 37 while (true) { 38 //接受客戶端發送過來的信息 39 info = dis.readUTF(); 40 //打印接受的信息 41 System.out.println("對方說: " + info); 42 //如果發現接受的信息為:bye,那么就結束對話 43 if (info.equals("bye")) 44 break; 45 //讀取鍵盤的輸入流 46 info = br.readLine(); 47 //寫入到網絡連接的另一邊,即客戶端 48 dos.writeUTF(info); 49 //如果服務器自己說:bye,也是結束對話 50 if (info.equals("bye")) 51 break; 52 } 53 //關閉輸入流 54 dis.close(); 55 //關閉輸出流 56 dos.close(); 57 //關閉socket對象 58 s1.close(); 59 s.close(); 60 } catch (SocketException e) { 61 System.out.println("網絡連接異常,程序退出!"); 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 } 66 }
客戶端代碼:
1 package com.b510.socket1704.simplechatroom; 2 3 import java.io.*; 4 import java.net.Socket; 5 import java.net.SocketException; 6 /** 7 * 客戶端程序,在while循環中所執行的動作是: 8 * 說,聽,說,聽,說,聽.... 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestClient { 14 public static void main(String args[]) { 15 try { 16 // 創建socket對象,指定服務器的ip地址,和服務器監聽的端口號 17 // 客戶端在new的時候,就發出了連接請求,服務器端就會進行處理,如果服務器端沒有開啟服務,那么 18 // 這時候就會找不到服務器,並同時拋出異常==》java.net.ConnectException: Connection 19 // refused: connect 20 Socket s1 = new Socket("localhost", 8888); 21 //打開輸出流 22 OutputStream os = s1.getOutputStream(); 23 //封裝輸出流 24 DataOutputStream dos = new DataOutputStream(os); 25 //打開輸入流 26 InputStream is = s1.getInputStream(); 27 //封裝輸入流 28 DataInputStream dis = new DataInputStream(is); 29 //讀取鍵盤輸入流 30 InputStreamReader isr = new InputStreamReader(System.in); 31 //封裝鍵盤輸入流 32 BufferedReader br = new BufferedReader(isr); 33 34 String info; 35 while (true) { 36 //客戶端先讀取鍵盤輸入信息 37 info = br.readLine(); 38 //把他寫入到服務器方 39 dos.writeUTF(info); 40 //如果客戶端自己說:bye,即結束對話 41 if (info.equals("bye")) 42 break; 43 //接受服務器端信息 44 info = dis.readUTF(); 45 //打印 46 System.out.println("對方說: " + info); 47 if (info.equals("bye")) 48 break; 49 } 50 //關閉相應的輸入流,輸出流,socket對象 51 dis.close(); 52 dos.close(); 53 s1.close(); 54 } catch (IOException e) { 55 e.printStackTrace(); 56 } 57 } 58 }
運行效果:
服務器端效果>>>
1 對方說: hell 2 你好 3 對方說: 嘿嘿 4 你今天 5 對方說: 13 6 代售點
客戶端端效果>>>
1 hell 2 對方說: 你好 3 嘿嘿 4 對方說: 你今�? 5 13 6 對方說: 代售�?
當前的程序不管是服務器端,還是客戶端,都是單線程的。如: 服務器端說:"你好"
1 //讀取鍵盤的輸入流 2 info = br.readLine(); 3 //寫入到網絡連接的另一邊,即客戶端 4 dos.writeUTF(info); 5 //如果服務器自己說:bye,也是結束對話
通過上面的代碼,把"你好"發送出去了,這時候,程序又開始循環,運行到:
1 //接受客戶端發送過來的信息 2 info = dis.readUTF();
這段代碼,其實在這里就阻塞在這里了。要等到客戶端那邊說了話,"嘿嘿",這時候這里的
阻塞才會變為非阻塞狀態,然后又繼續說,說完后又繼續阻塞......
而對於客戶端來說,其實是一樣的道理,客戶端說完"hello"后,進入:
1 //接受服務器端信息 2 info = dis.readUTF();
到收聽服務器端的信息,在這里也產生了阻塞,只有服務器端說了"你好",這個阻塞才變為非阻塞
狀態。然后又繼續接下來的動作....
============================================================
3.實現多線程的聊天室
============================================================
服務器端代碼:
1 package com.b510.socket1705.freeechatroom; 2 3 import java.io.*; 4 import java.net.*; 5 6 /** 7 * 服務器端程序 8 * 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestServer { 14 public static void main(String args[]) { 15 try { 16 // 創建一個socket對象 17 ServerSocket s = new ServerSocket(8888); 18 // socket對象調用accept方法,等待連接請求 19 Socket s1 = s.accept(); 20 21 // =========服務器端,在這里應該先打開輸出流,在打開輸入流, 22 // =========因為服務器端執行的操作是先聽,再說,聽,說,聽,說..... 23 24 // 打開輸出流 25 OutputStream os = s1.getOutputStream(); 26 // 封裝輸出流 27 DataOutputStream dos = new DataOutputStream(os); 28 // 打開輸入流 29 InputStream is = s1.getInputStream(); 30 // 封裝輸入流 31 DataInputStream dis = new DataInputStream(is); 32 // 創建並啟用兩個線程 33 new MyServerReader(dis).start(); 34 new MyServerWriter(dos).start(); 35 } catch (IOException e) { 36 e.printStackTrace(); 37 } 38 } 39 } 40 41 // 接受並打印客戶端傳過來的信息 42 class MyServerReader extends Thread { 43 private DataInputStream dis; 44 45 public MyServerReader(DataInputStream dis) { 46 this.dis = dis; 47 } 48 49 public void run() { 50 String info; 51 try { 52 while (true) { 53 // 如果對方,即客戶端沒有說話,那么就會阻塞到這里, 54 // 這里的阻塞並不會影響到其他線程 55 info = dis.readUTF(); 56 // 如果狀態有阻塞變為非阻塞,那么就打印接受到的信息 57 System.out.println("對方說: " + info); 58 if (info.equals("bye")) { 59 System.out.println("對方下線,程序退出!"); 60 System.exit(0); 61 } 62 } 63 } catch (IOException e) { 64 e.printStackTrace(); 65 } 66 } 67 } 68 69 // 從鍵盤獲得輸入流並寫入信息到客戶端 70 class MyServerWriter extends Thread { 71 private DataOutputStream dos; 72 73 public MyServerWriter(DataOutputStream dos) { 74 this.dos = dos; 75 } 76 77 public void run() { 78 // 讀取鍵盤輸入流 79 InputStreamReader isr = new InputStreamReader(System.in); 80 // 封裝鍵盤輸入流 81 BufferedReader br = new BufferedReader(isr); 82 String info; 83 try { 84 while (true) { 85 info = br.readLine(); 86 dos.writeUTF(info); 87 if (info.equals("bye")) { 88 System.out.println("自己下線,程序退出!"); 89 System.exit(0); 90 } 91 } 92 } catch (IOException e) { 93 e.printStackTrace(); 94 } 95 } 96 }
客戶端代碼:
1 package com.b510.socket1705.freeechatroom; 2 3 import java.io.*; 4 import java.net.*; 5 6 /** 7 * 客戶端程序 8 * 9 * @author Hongten 10 * 11 * @time 2012-4-29 2012 12 */ 13 public class TestClient { 14 public static void main(String args[]) { 15 try { 16 // 創建socket對象,指定服務器的ip地址,和服務器監聽的端口號 17 // 客戶端在new的時候,就發出了連接請求,服務器端就會進行處理,如果服務器端沒有開啟服務,那么 18 // 這時候就會找不到服務器,並同時拋出異常==》java.net.ConnectException: Connection 19 // refused: connect 20 Socket s1 = new Socket("127.0.0.1", 8888); 21 22 // =========客戶端,在這里應該先打開輸入流,在打開輸出流, 23 // =========因為客戶端執行的操作是先說,再聽,說,聽,說,聽..... 24 25 // 打開輸入流 26 InputStream is = s1.getInputStream(); 27 // 封裝輸入流 28 DataInputStream dis = new DataInputStream(is); 29 // 打開輸出流 30 OutputStream os = s1.getOutputStream(); 31 // 封裝輸出流 32 DataOutputStream dos = new DataOutputStream(os); 33 34 // 創建並啟用兩個線程 35 new MyClientReader(dis).start(); 36 new MyClientWriter(dos).start(); 37 } catch (IOException e) { 38 e.printStackTrace(); 39 } 40 } 41 } 42 43 // 接受並打印服務器端傳過來的信息 44 class MyClientReader extends Thread { 45 private DataInputStream dis; 46 47 public MyClientReader(DataInputStream dis) { 48 this.dis = dis; 49 } 50 51 public void run() { 52 String info; 53 try { 54 while (true) { 55 info = dis.readUTF(); 56 System.out.println("對方說: " + info); 57 if (info.equals("bye")) { 58 System.out.println("對方下線,程序退出!"); 59 System.exit(0); 60 } 61 } 62 } catch (IOException e) { 63 e.printStackTrace(); 64 } 65 } 66 } 67 68 // 從鍵盤獲得輸入流並寫入信息到服務器端 69 class MyClientWriter extends Thread { 70 private DataOutputStream dos; 71 72 public MyClientWriter(DataOutputStream dos) { 73 this.dos = dos; 74 } 75 76 public void run() { 77 InputStreamReader isr = new InputStreamReader(System.in); 78 BufferedReader br = new BufferedReader(isr); 79 String info; 80 try { 81 while (true) { 82 info = br.readLine(); 83 dos.writeUTF(info); 84 if (info.equals("bye")) { 85 System.out.println("自己下線,程序退出!"); 86 System.exit(0); 87 } 88 } 89 } catch (IOException e) { 90 e.printStackTrace(); 91 } 92 } 93 }
客戶端運行效果:
1 這是客戶端 2 我是hongten 3 這是我說的第三句話,haha 4 對方說: 我是服務器端,這說我說的第一句話,hehe
服務器端運行效果:
1 對方說: 這是客戶�? 2 對方說: 我是hongten 3 對方說: 這是我說的第三句話,haha 4 我是服務器端,這說我說的第一句話,hehe
程序中加入了多線程后,不管是服務器端,還是客戶端,都可以連續的說話,另一邊連續的聽...