<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文範例為大家分享了Java用區域網實現聊天室的具體程式碼,供大家參考,具體內容如下
類和介面
Server類(伺服器端)
package Test; import java.io.IOException; import java.io.PrintStream; import java.net.ServerSocket; import java.net.Socket; public class Server { private static final int SERVER_PORT=30000; //使用CrazyitMap物件來儲存每個客戶名字和對應輸出流之間的對應關係 public static CrazyitMap<String,PrintStream> clients=new CrazyitMap<>(); public void init(){ try( //建立監聽的ServerSocket ServerSocket ss=new ServerSocket(SERVER_PORT)) { //採用死迴圈來不斷地接收來自使用者端的請求 while(true){ Socket socket=ss.accept(); new ServerThread(socket).start(); } } //如果丟擲異常 catch (IOException ex){ System.out.println("伺服器啟動失敗,是否埠"+SERVER_PORT+"已被佔用"); } } public static void main(String[] args){ Server server=new Server(); server.init(); } }
ServerThread類
package Test; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; public class ServerThread extends Thread { private Socket socket; BufferedReader br = null; PrintStream ps = null; //定義一個構造器,用於接收一個Socket來建立ServerThread執行緒 public ServerThread(Socket socket) { this.socket = socket; } public void run() { try { //獲取該Socket對應的輸入流 br = new BufferedReader(new InputStreamReader(socket.getInputStream())); //獲取該Socket對應的輸出流 ps = new PrintStream(socket.getOutputStream()); String line = null; while ((line = br.readLine()) != null) { //如果讀到的行以CrazyitProtocol.USER_ROUND開始,並以其結束 //則可以確定讀到的是使用者登入的使用者名稱 if (line.startsWith(CrazyitProtocol.USER_ROUND) && line.endsWith(CrazyitProtocol.USER_ROUND)) { //得到真實訊息 String userName = getRealMsg(line); //如果使用者名稱重複 if (Server.clients.map.containsKey(userName)) { System.out.println("重複"); ps.println(CrazyitProtocol.NAME_REP); } else { System.out.println("成功"); ps.println(CrazyitProtocol.LOGIN_SUCCESS); Server.clients.put(userName, ps); } } //如果讀到的行以CrazyitProtocol.PRIVATE_ROUND開始, //則可以確定是私聊資訊,私聊資訊只向特定的輸入流傳送 else if (line.startsWith(CrazyitProtocol.PRIVATE_ROUND) && line.endsWith(CrazyitProtocol.PRIVATE_ROUND)) { //得到真實的訊息 String userAndMsg = getRealMsg(line); //以SPLIT_SIGN分割字串,前半是私聊使用者,後半是聊天資訊 String user = userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[0]; String msg = userAndMsg.split(CrazyitProtocol.SPLIT_SIGN)[1]; //獲取私聊使用者對應的輸出流,並行送私聊資訊 Server.clients.map.get(user).println(Server.clients.getKeyByValue(ps) + "悄悄對你說:" + msg); } //公聊要向每一個Socket傳送 else { //得到真實訊息 String msg = getRealMsg(line); //遍歷clients中的每個輸出流 for (PrintStream clientPs : Server.clients.valueSet()) { clientPs.println(Server.clients.getKeyByValue(ps) + "說:" + msg); } } } } //捕獲到異常後,表明Socket對應的使用者端已經出現了問題 //所以程式將其對應的輸出流從Map中刪除 catch (IOException e) { Server.clients.removeByValue(ps); System.out.println(Server.clients.map.size()); //關閉網路,IO資源 try { if (br != null) { br.close(); } if (ps != null) { ps.close(); } if (socket != null) { socket.close(); } } catch (IOException ex) { ex.printStackTrace(); } } } //將讀到的內容去掉前後協定字元,恢復成真實資料 private String getRealMsg(String line) { return line.substring(CrazyitProtocol.PROTOCOL_LEN,line.length()-CrazyitProtocol.PROTOCOL_LEN); } }
Client類
package Test; import javax.swing.*; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; import java.net.UnknownHostException; public class Client { private static final int SERVER_PORT=30000; private Socket socket; private PrintStream ps; private BufferedReader brServer; private BufferedReader keyIn; public void init(){ try { //初始化代表鍵盤的輸入流 keyIn=new BufferedReader(new InputStreamReader(System.in)); //連線到伺服器端 socket=new Socket("127.0.0.1",SERVER_PORT); //獲取該Socket對應的輸入流和輸出流 ps=new PrintStream(socket.getOutputStream()); brServer=new BufferedReader(new InputStreamReader(socket.getInputStream())); String tip=" "; //採用不斷迴圈地彈出對話方塊要求輸入使用者名稱 while(true){ String userName= JOptionPane.showInputDialog(tip+"輸入使用者名稱"); //使用者輸入的使用者名稱前後增加協定字串後傳送 ps.println(CrazyitProtocol.USER_ROUND+userName+CrazyitProtocol.USER_ROUND); //讀取伺服器端的響應 String result=brServer.readLine(); //如果使用者名稱重複,則開始下一次迴圈 if (result.equals(CrazyitProtocol.NAME_REP)){ tip="使用者名稱重複,請重試"; continue; } //伺服器端登入成功 if (result.equals(CrazyitProtocol.LOGIN_SUCCESS)){ break; } } } //捕獲到異常,關閉網路資源,並退出該程式 catch (UnknownHostException ex){ System.out.println("找不到遠端伺服器,請確定伺服器已經啟動"); closeRs(); System.exit(1); } catch(IOException ex){ System.out.println("網路異常,請重新登入"); closeRs(); System.exit(1); } //以該Socket對應的輸入流啟動ClientThread執行緒 new ClientThread(brServer).start(); } //定義一個讀取鍵盤輸出,並以網路傳送的方法 private void readAndSend(){ try { //不斷讀取鍵盤輸入 String line=null; while ((line=keyIn.readLine())!=null){ //如果傳送的訊號中有冒號,並以//開頭,則認為想傳送私聊資訊 if (line.indexOf(":")>0&&line.startsWith("//")){ line=line.substring(2); ps.println(CrazyitProtocol.PRIVATE_ROUND+line.split(":")[0]+CrazyitProtocol.SPLIT_SIGN+line.split(":")[1]+CrazyitProtocol.PRIVATE_ROUND); } else{ ps.println(CrazyitProtocol.MSG_ROUND+line+CrazyitProtocol.MSG_ROUND); } } } catch (IOException ex){ System.out.println("網路通訊異常!請重新登入"); closeRs(); System.exit(1); } } //關閉Socket,輸入流,輸出流的方法 private void closeRs(){ try { if (keyIn!=null){ ps.close(); } if (brServer!=null){ ps.close(); } if (ps!=null){ ps.close(); } if (socket!=null){ keyIn.close(); } } catch (IOException ex){ ex.printStackTrace(); } } public static void main(String[] args){ Client client=new Client(); client.init(); client.readAndSend(); } }
ClientThread類
package Test; import java.io.BufferedReader; import java.io.IOException; public class ClientThread extends Thread { //該使用者端執行緒負責處理輸入流 BufferedReader br=null; //使用一個網路輸入流來建立使用者端執行緒 public ClientThread(BufferedReader br){ this.br=br; } public void run(){ try { String line=null; //不斷地從輸入流中讀取資料,並將這些資料列印輸出 while((line=br.readLine())!=null){ System.out.println(line); } } catch (IOException ex){ ex.printStackTrace(); } finally { try { if (br!=null){ br.close(); } } catch (IOException ex){ ex.printStackTrace(); } } } }
CrazyitMap類
package Test; import java.util.*; public class CrazyitMap<k,v> { //建立一個執行緒安全的HashMap public Map<k,v> map= Collections.synchronizedMap(new HashMap<k,v>()); //根據value來刪除指定項 public synchronized void removeByValue(Object value){ for (Object key:map.keySet()){ if (map.get(key)==value){ map.remove(key); break; } } } //獲取所有value組成的Set集合 public synchronized Set<v> valueSet(){ Set<v> result=new HashSet<v>(); //將map中的所有value新增到result集合中 map.forEach((key,value)->result.add(value)); return result; } //根據value查詢key public synchronized k getKeyByValue(v value){ //遍歷所有key組成的集合 for (k key:map.keySet()){ //如果指定key對應的value與被搜尋的value相同,則返回對應的key if(map.get(key)==value||map.get(key).equals(value)){ return key; } } return null; } //實現put()方法,該方法不允許value重複 public synchronized v put(k key,v value){ //遍歷所有value組成的集合 for (v val:valueSet()){ //如果某個value與試圖放入集合的value相同 //則丟擲一個RuntimeException異常 if (val.equals(value)&&val.hashCode()==value.hashCode()){ throw new RuntimeException("MyMap範例不允許有重複的value"); } } return map.put(key,value); } }
CrazyitProtocol類
package Test; public interface CrazyitProtocol { //定義協定字串的長度 int PROTOCOL_LEN=2; //下面是一些協定字串,伺服器端和使用者端交換的資訊都應該在前後新增這種特殊字串 String MSG_ROUND="ηθ"; String USER_ROUND="∏∑"; String LOGIN_SUCCESS="1"; String NAME_REP="-1"; String PRIVATE_ROUND="★【"; String SPLIT_SIGN="卐"; }
執行結果:
開啟伺服器並且執行三個使用者端使用者名稱分別是xuwei,jiji和yaou
首先傳送一句公開資訊:
xuwei傳送了一句話
jiji收到:
yaou收到:
再傳送一句私聊資訊給jiji
xuwei傳送了一句悄悄話:
jiji收到:
yaou沒有收到:
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援it145.com。
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45