網絡編程是指編寫運行在多個設備(計算機)的程序,這些設備都經過網絡鏈接起來。html
java.net包中JavaSE的API包含有類和接口,它們提供低層次的通訊細節。你能夠直接使用這些類和接口,來專一於解決問題,而不用關注通訊細節。java
java.net包中提供了兩種常見的網絡協議的支持:編程
TCP:TCP是傳輸控制協議的縮寫,它保障了兩個應用程序之間的可靠通訊。一般用於互聯網協議,被稱TCP/IP。服務器
UDP:UDP是用戶數據報協議的縮寫,一個無鏈接的協議。提供了應用程序之間要發送的數據的數據報。網絡
本案例以TCP協議爲例,結合多線程,實現一個多人同時聊天的聊天室。多線程
釋放資源:ide
Utils.javathis
1 package com.bjwyj.chat; 2 3 import java.io.Closeable; 4 5 public class Utils { 6 /** 7 * 釋放資源 8 */ 9 public static void close(Closeable... targets) { 10 for(Closeable target:targets) { 11 try { 12 if(target!=null) { 13 target.close(); 14 } 15 }catch(Exception e) { 16 e.printStackTrace(); 17 } 18 } 19 } 20 }
服務器端:spa
Chat.java.net
1 package com.bjwyj.chat; 2 3 import java.io.DataInputStream; 4 import java.io.DataOutputStream; 5 import java.io.IOException; 6 import java.net.ServerSocket; 7 import java.net.Socket; 8 import java.util.concurrent.CopyOnWriteArrayList; 9 10 /** 11 * 在線聊天室:服務端 12 * 目標:加入容器實現羣聊和私聊 13 * 14 * @author 吳永吉 15 * 16 */ 17 public class Chat { 18 private static CopyOnWriteArrayList<Channel> all = new CopyOnWriteArrayList<>(); 19 public static void main(String[] args) throws IOException { 20 System.out.println("------server------"); 21 //1.指定端口:使用ServerSocket建立服務器 22 ServerSocket server = new ServerSocket(9999); 23 //2.阻塞式等待鏈接accept 24 while(true) { 25 Socket client = server.accept(); 26 System.out.println("一個客戶端創建了鏈接"); 27 Channel c = new Channel(client); 28 all.add(c); //管理全部的成員 29 new Thread(c).start(); 30 } 31 } 32 //一個客戶表明一個Channel 33 static class Channel implements Runnable{ 34 private DataInputStream dis; 35 private DataOutputStream dos; 36 private Socket client; 37 private boolean isRunning; 38 private String name; 39 40 public Channel(Socket client) { 41 isRunning = true; 42 this.client = client; 43 try { 44 dis = new DataInputStream(client.getInputStream()); 45 dos = new DataOutputStream(client.getOutputStream()); 46 //獲取名稱 47 this.name = receive(); 48 //歡迎你的到來 49 this.send("歡迎上線"); 50 this.sendOthers(this.name+"上線啦!",true); 51 }catch(Exception e) { 52 release(); 53 } 54 } 55 56 //接收消息 57 public String receive() { 58 String msg = ""; 59 try { 60 msg = dis.readUTF(); 61 } catch (IOException e) { 62 System.out.println("-------Chat receive------"); 63 release(); 64 } 65 return msg; 66 } 67 //發送消息 68 public void send(String msg) { 69 try { 70 dos.writeUTF(msg); 71 dos.flush(); 72 } catch (IOException e) { 73 System.out.println("--------Chat send-------"); 74 release(); 75 } 76 } 77 /** 78 * 羣聊:獲取本身的消息,發給其餘人 79 * 私聊:約定數據格式:@xxx:msg 80 * @param msg 81 */ 82 public void sendOthers(String msg,boolean isSys) { 83 boolean isPrivate = msg.startsWith("@"); 84 if(isPrivate) { //私聊 85 int idx = msg.indexOf(":"); 86 //獲取目標和數據 87 String targetName = msg.substring(1,idx); 88 msg = msg.substring(idx+1); 89 for(Channel other:all) { 90 if(other.name.equals(targetName)) { //目標 91 other.send(this.name+"悄悄的對你說:"+msg); 92 break; 93 } 94 } 95 }else { //羣聊 96 for(Channel other:all) { 97 if(this==other) { //本身 98 continue; 99 } 100 if(!isSys) { 101 other.send(this.name+"對全部人說:"+msg); //羣聊消息 102 }else { 103 other.send(msg); //系統消息 104 } 105 } 106 } 107 } 108 //關閉資源 109 public void release() { 110 this.isRunning = false; 111 Utils.close(dis,dos,client); 112 //退出 113 all.remove(this); 114 sendOthers(this.name+"下線了!",true); 115 } 116 117 @Override 118 public void run() { 119 while(isRunning) { 120 String msg = receive(); 121 if(!msg.equals("")) { 122 //send(msg); 123 sendOthers(msg,false); 124 } 125 } 126 } 127 } 128 }
客戶端:
Send.java
1 package com.bjwyj.chat; 2 3 import java.io.BufferedReader; 4 import java.io.DataOutputStream; 5 import java.io.IOException; 6 import java.io.InputStreamReader; 7 import java.net.Socket; 8 9 /** 10 * 使用多線程封裝了客戶發送端: 11 * 1.發送消息 12 * 2.從控制檯獲取消息 13 * 3.釋放資源 14 * 4.重寫run 15 * @author 吳永吉 16 * 17 */ 18 public class Send implements Runnable{ 19 private BufferedReader console; 20 private DataOutputStream dos; 21 private Socket client; 22 private boolean isRunning; 23 private String name; 24 25 public Send(Socket client,String name) { 26 isRunning = true; 27 this.client = client; 28 this.name = name; 29 console = new BufferedReader(new InputStreamReader(System.in)); 30 try { 31 dos = new DataOutputStream(client.getOutputStream()); 32 //發送名稱 33 send(name); 34 } catch (IOException e) { 35 System.out.println("------Client Send------"); 36 this.release(); 37 } 38 } 39 40 @Override 41 public void run() { 42 while(isRunning) { 43 String msg = this.getStringFromConsole(); 44 if(!msg.equals("")) { 45 this.send(msg); 46 } 47 } 48 } 49 50 /** 51 * 發送消息 52 */ 53 private void send(String msg) { 54 try { 55 dos.writeUTF(msg); 56 dos.flush(); 57 } catch (IOException e) { 58 System.out.println("------Client send------"); 59 release(); 60 } 61 } 62 63 /** 64 * 從控制檯獲取消息 65 */ 66 private String getStringFromConsole() { 67 try { 68 return console.readLine(); 69 } catch (IOException e) { 70 System.out.println("------Client console------"); 71 release(); 72 } 73 return ""; 74 } 75 76 //釋放資源 77 private void release() { 78 this.isRunning = false; 79 Utils.close(dos,client); 80 } 81 }
Receive.java
1 package com.bjwyj.chat; 2 3 import java.io.DataInputStream; 4 import java.io.IOException; 5 import java.net.Socket; 6 7 /** 8 * 使用多線程封裝了客戶接收端 9 * 1.接收消息 10 * 2.釋放資源 11 * 3.重寫run 12 * @author 吳永吉 13 * 14 */ 15 public class Receive implements Runnable{ 16 private DataInputStream dis; 17 private Socket client; 18 private boolean isRunning; 19 20 public Receive(Socket client) { 21 this.isRunning = true; 22 this.client = client; 23 try { 24 dis = new DataInputStream(client.getInputStream()); 25 } catch (IOException e) { 26 System.out.println("------Client Receive------"); 27 this.release(); 28 } 29 } 30 31 //接收消息 32 public String receive() { 33 String msg = ""; 34 try { 35 msg = dis.readUTF(); 36 } catch (IOException e) { 37 System.out.println("-------Receive receive------"); 38 release(); 39 } 40 return msg; 41 } 42 43 @Override 44 public void run() { 45 while(isRunning) { 46 String msg = this.receive(); 47 if(!msg.equals("")) { 48 System.out.println(msg); 49 } 50 } 51 } 52 53 //釋放資源 54 private void release() { 55 this.isRunning = false; 56 Utils.close(dis,client); 57 } 58 }
Client.java
1 package com.bjwyj.chat; 2 3 import java.io.BufferedReader; 4 import java.io.IOException; 5 import java.io.InputStreamReader; 6 import java.net.Socket; 7 import java.net.UnknownHostException; 8 9 /** 10 * 在線聊天室:客戶端 11 * 12 * @author 吳永吉 13 * 14 */ 15 public class Client { 16 public static void main(String[] args) throws UnknownHostException, IOException { 17 System.out.println("------client------"); 18 BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); 19 System.out.println("請輸入名稱:"); 20 String name = br.readLine(); 21 //創建鏈接:使用Socket建立客戶端+服務器的地址和端口號 22 Socket client = new Socket("localhost",9999); 23 //客戶端發送消息 24 new Thread(new Send(client,name)).start(); 25 //獲取消息 26 new Thread(new Receive(client)).start(); 27 } 28 }
運行結果:
原文出處:https://www.cnblogs.com/wuyongji/p/10659540.html