日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

多人聊天室(Java)

發(fā)布時(shí)間:2024/8/26 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 多人聊天室(Java) 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

第1部分 TCP和UDP

TCP:是一種可靠地傳輸協(xié)議,是把消息按一個(gè)個(gè)小包傳遞并確認(rèn)消息接收成功和正確才發(fā)送下一個(gè)包,速度相對于UDP慢,但是信息準(zhǔn)確安全;常用于一般不要求速度和需要準(zhǔn)確發(fā)送消息的場合。

UDP:是一種不可靠的傳輸協(xié)議,常用于視頻直播、游戲等及時(shí)性比較強(qiáng)的場景。

進(jìn)行相關(guān)編程可以查詢API手冊。

?

第2部分 多人聊天室

下面是利用Java的TCP協(xié)議的API實(shí)現(xiàn)多人聊天室的案例代碼:

服務(wù)端:

運(yùn)行在服務(wù)端的SeverSocket主要負(fù)責(zé):

?1 向系統(tǒng)申請服務(wù)端口號,客戶端是通過這個(gè)端口號和IP地址與之連接的;端口號一般取四千之一萬之間,因?yàn)槠溆嘤械囊呀?jīng)綁定系統(tǒng)系統(tǒng)應(yīng)用和主流應(yīng)用程序,最常用的便是8088。

?2 監(jiān)聽申請的服務(wù)端口號,當(dāng)一個(gè)客戶端通過該端口號嘗試建立聯(lián)系連接時(shí),SeverSocket會(huì)在服務(wù)端創(chuàng)建一個(gè)Socket與客戶端建立連接,服務(wù)端正對不同客戶端建立多個(gè)Socket,利用多線程實(shí)現(xiàn)。

工作模塊及過程:

服務(wù)器先初始化,包括申請端口號,和創(chuàng)建共享消息集合(可以用map,key是用戶名,value是消息,私聊返回value值,廣播則遍歷value),另外創(chuàng)建增刪和發(fā)送消息的方法;

創(chuàng)建處理客戶端交互的類,繼承runnable,通過socket的getInetAdress和getHostAdress方法獲取客戶端計(jì)算機(jī)的信息,其start方法用來完成從一個(gè)客戶端接收消息,并將其他客戶端的消息返回給該客戶端;

package chat;import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; import java.util.ArrayList; import java.util.List;/*** * 運(yùn)行在服務(wù)端的SeverSocket主要負(fù)責(zé);* 1 向系統(tǒng)申請服務(wù)端口號客戶端是通過這個(gè)端口號與之連接的* 2 監(jiān)聽申請的服務(wù)端口號,當(dāng)一個(gè)客戶端通過該端口號嘗試建立聯(lián)系連接時(shí),* SeverSocket會(huì)在服務(wù)端創(chuàng)建一個(gè)Socket與客戶端建立連接* 服務(wù)端正對不同客戶端建立多個(gè)Socket* * @author KwinWei QQ:885251358**/ public class Server {public ServerSocket server;/** 用來保存客戶端輸出流的集合,*因?yàn)榫€程安全的也不和遍歷互斥,要自己維護(hù)也可以保證安全*/private List<PrintWriter> allOut; //私聊可以用map,key為昵稱,value是對應(yīng)消息,廣播則遍歷value/**初始化 服務(wù)端*/public Server()throws Exception {/** 初始化的同時(shí)申請端口號*/server = new ServerSocket(8788);allOut = new ArrayList<PrintWriter>();}/*** 將給定的輸出流存入共享集合* @param out*/private synchronized void addOut(PrintWriter out) {allOut.add(out);}/*** 將給定的輸出流從共享集合中刪除* @param out*/private synchronized void removeOut(PrintWriter out) {allOut.remove(out);}/*** 將給定的消息發(fā)送給所有客戶端* @param out*/private synchronized void sendMessage(String message) {for(PrintWriter out : allOut) {out.println(message);}}/*服務(wù)端開始工作的方法* */public void start() {try {/** ServerSocket的accept的方法* 是一個(gè)阻塞的方法,作用是監(jiān)聽服務(wù)端口號,知道一個(gè)客戶端;連接并創(chuàng)建一個(gè)Socket,使用該Socket* 即可與剛才鏈接的客戶端進(jìn)行交互*/while(true) {System.out.println("等待客戶端連接...");Socket socket = server.accept();System.out.println("一個(gè)客戶端連接了!");/** 啟動(dòng)一個(gè)線程,來完成與該客戶端的交互*/ClientHandler handler= new ClientHandler(socket);Thread t = new Thread(handler);t.start(); }} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {try {Server server = new Server();server.start();} catch (Exception e) {e.printStackTrace();System.out.println("服務(wù)端建立聯(lián)系失敗!");}}/***該線程負(fù)責(zé)處理一個(gè)客戶端的交互* */class ClientHandler implements Runnable{/** 該線程處理的客戶端的Socket*/private Socket socket ;// 客戶端的地址信息,區(qū)分不同客戶端private String host;//用戶的昵稱private String nickName;public ClientHandler(Socket socket) {this.socket = socket;/** 通過Socket可以獲取遠(yuǎn)端計(jì)算機(jī)的地址信息*/InetAddress address = socket.getInetAddress();//獲取IP地址host = address.getHostAddress();}public void run() {PrintWriter pw = null;try {/** Socket 提供的方法* InputStream getInputStream()* 該方法可以獲取一個(gè)輸入流,從該方法讀取的數(shù)據(jù)就是從遠(yuǎn)端計(jì)算機(jī)發(fā)送來的 */InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in,"UTF-8");BufferedReader br = new BufferedReader(isr);//首先讀取一行字符串為昵稱nickName = br.readLine();//System.out.println(host+"上線了");sendMessage(nickName+"上線了");/** 通過Socket創(chuàng)建輸出流用于將消息發(fā)送給客戶端*/OutputStream out = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");pw = new PrintWriter(osw,true);/** 將該客戶端對的輸出流存入到共享集合中*/addOut(pw);String message = null;/** br.readLine()在讀取客戶戶端發(fā)送過來的消息時(shí),由于客戶端斷線,* 而操作系統(tǒng)的不同,這里讀取后的結(jié)果不同:* 當(dāng)windows的客戶端斷開時(shí):br.readLine會(huì)拋出異常* 當(dāng)linux的客戶端斷開時(shí):br.readLine 會(huì)返回null*/while((message = br.readLine())!=null) {//System.out.println(host+"說:"+ message);//pw.println(host+"說:"+message);//廣播消息sendMessage(nickName+"說:"+message);} } catch (Exception e) {}finally {/** 處理當(dāng)前客戶端斷開后的邏輯*///將該客戶端的輸出流從共享集合中刪除 removeOut(pw);//System.out.println(host+"下線了");sendMessage(nickName+"下線了");try {socket.close();} catch (IOException e) {e.printStackTrace();}} }}} View Code

客戶端:

package chat;import java.io.BufferedReader; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.net.Socket; import java.util.Scanner;/*** * @author KwinWei QQ:885251358**/ public class Client {/** 套接字* * 理解為電話,撥號,建立聯(lián)系,麥克風(fēng)說話,* socket輸入和輸出流,* 你輸入流對應(yīng)他輸出流,你說話他聽* 你輸出流對應(yīng)他輸入流* * java,net.Socket;* 封裝了TCP協(xié)議,使用它就可以基于某種TCP協(xié)議進(jìn)行網(wǎng)絡(luò)通信* Socket試運(yùn)行在客戶端的*/private Socket socket;public Client() throws Exception {/**實(shí)例化Socket的時(shí)候需要傳入兩個(gè)參數(shù)* 1 IP:127.0.0.1或localhost本機(jī);* 2 端口:0-65535,聽服務(wù)端的,區(qū)用網(wǎng)程序,* 一般使用四千以上一萬以下,前四千被占用綁定主流應(yīng)用程序等 * 通過Ip可以找到服務(wù)的那臺計(jì)算機(jī),通過端口號可以找到服務(wù)端計(jì)算機(jī)上服務(wù)端用程序* * 實(shí)例化Socket的過程就是連接的過程,若遠(yuǎn)端計(jì)算機(jī)沒有響應(yīng)會(huì)拋出異常* */System.out.println("正在連接服務(wù)端...");socket = new Socket("localhost",8788);System.out.println("已經(jīng)和服務(wù)端建立聯(lián)系");}/** 啟動(dòng)客戶端的方法*/public void start() {try {Scanner scanner = new Scanner(System.in);/** 先要求用戶創(chuàng)建一個(gè)昵稱*///System.out.println("");String nickName = null;while(true) {System.out.println("請用戶輸入用戶名");nickName = scanner.nextLine();if(nickName.length()>0) {break;}System.out.println("輸入有誤");}System.out.println("歡迎你"+nickName+"!開始聊天吧!");/*socket 提供的方法:* OutputStream getOutStream* 獲取一個(gè)字節(jié)輸出流,通過該流寫出的數(shù)據(jù)會(huì)被發(fā)送至遠(yuǎn)端計(jì)算機(jī)。*/OutputStream out = socket.getOutputStream();OutputStreamWriter osw = new OutputStreamWriter(out,"UTF-8");PrintWriter pw = new PrintWriter(osw,true); //不能指明字節(jié)流,所以要加一個(gè)轉(zhuǎn)換流,第二參數(shù)為true會(huì)行刷新//先將昵稱發(fā)給服務(wù)器 pw.println(nickName);/** 啟動(dòng)讀取服務(wù)端發(fā)送過來消息的線程*/ServerHandler handler = new ServerHandler();Thread t = new Thread(handler);t.start();/** 將字符串發(fā)送至服務(wù)端,加上行刷新,說一句發(fā)一句* 否則需要用 flush()強(qiáng)制寫出*/while(true) {pw.println(scanner.nextLine());//pw.flush(); }} catch (Exception e) {e.printStackTrace();}}public static void main(String[] args) {try {Client client = new Client();client.start();}catch(Exception e) {e.printStackTrace();System.out.println("客戶端啟動(dòng)失敗!");}}/** 該線程用來讀取服務(wù)器端發(fā)送來的消息,并輸出到客戶端控制臺顯示*/class ServerHandler implements Runnable {public void run() {try {InputStream in = socket.getInputStream();InputStreamReader isr = new InputStreamReader(in,"UTF-8");BufferedReader br = new BufferedReader(isr);String message = null;while ((message = br.readLine())!=null) {System.out.println(message);}} catch (Exception e) {}}}} View Code

?

轉(zhuǎn)載于:https://www.cnblogs.com/kwinwei/p/10575144.html

總結(jié)

以上是生活随笔為你收集整理的多人聊天室(Java)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。