基于socket的進(jìn)程通信

  • 實(shí)現(xiàn)目標(biāo)

    • 實(shí)現(xiàn)服務(wù)端與客戶端的連接
    • 實(shí)現(xiàn)多個(gè)客戶端向服務(wù)端發(fā)送消息森缠,并由服務(wù)端將消息發(fā)送給每個(gè)客戶端
  • 涉及的Java類

    • java.net.ServerSocket 用于創(chuàng)建服務(wù)器端口
    • java.net.Socket 用于創(chuàng)建Socket
    • java.net.URLDecoder 用于在服務(wù)端將客戶端傳來(lái)的消息解碼
    • java.util.ArrayList 用于動(dòng)態(tài)存放多個(gè)不同的Socket
    • Java.util.scanner 用于從控制臺(tái)讀取輸入
  • 具體實(shí)現(xiàn)思路

    • 服務(wù)端

      • 在主函數(shù)中建立一個(gè)端口用于監(jiān)聽(tīng)客戶端請(qǐng)求适刀,端口大小可自行設(shè)置

        ServerSocket sock = new ServerSocket(1999)
        
      • 需要接受多個(gè)客戶端的消息祷舀,因此需要和每個(gè)客戶端建立唯一的Socket對(duì)用于通信党涕,所以需要將新建的Socket存入動(dòng)態(tài)容器ArrayList<Socket>中

        ArrayList<Socket> list = new ArrayList<Socket>()
        
      • 使用while循環(huán),在while循環(huán)中調(diào)用ServerSocket的accept()方法等待客戶端請(qǐng)求返奉,當(dāng)接受到請(qǐng)求時(shí)就將返回的Socket存入容器中尤蒿,并新建一個(gè)線程(調(diào)用start函數(shù))

        while(true) {
            Socket socket = sock.accept();
            list.add(socket);
            new MsgThread(socket, list).start();
        }
        
      • 在線程類中進(jìn)行數(shù)據(jù)的讀入和輸出

      • 定義類的屬性:Socket, ArrayList<Socket>,BufferedReader

      • 定義構(gòu)造函數(shù)粗合,將傳入的參數(shù)賦給當(dāng)前對(duì)象的屬性,同時(shí)乌昔,通過(guò)Socket讀取客戶端的數(shù)據(jù)到BufferedReader對(duì)象

        BufferedReader bf = new BufferedReader(new   InputStreamReader(client.getInputStream));
        //這里需要用InputStreamReader類來(lái)包裝client.getInputStream是為了將字節(jié)流轉(zhuǎn)換成字符流
        
      • 重載run函數(shù)隙疚,將讀取的消息發(fā)送給除當(dāng)前socket對(duì)象外的其他客戶端

        • 在這一步中的PrintWriter的使用要注意,一定要將自動(dòng)刷新設(shè)置為true磕道,否則消息就不能夠即時(shí)傳入到內(nèi)存中供屉,而是會(huì)等到程序結(jié)束時(shí)才傳入,這個(gè)bug卡了我好久
      • 將消息解碼后顯示在控制臺(tái)上

    • 客戶端

      • 和服務(wù)端差不多的思路溺蕉,主要是實(shí)現(xiàn)消息的讀取和上傳

      • 新建Socket伶丐,連接服務(wù)端

        Socket client = new Socket("127.000.001", 1999;
        
      • 讀取Socket中的數(shù)據(jù)并顯示在控制臺(tái)上

      • 線程函數(shù)和服務(wù)端類似,無(wú)非是從控制臺(tái)讀取數(shù)據(jù)然后用getOutPutStream寫(xiě)入Socket中

  • 源碼

    //服務(wù)端
    import java.io.*;
    import java.net.ServerSocket;
    import java.net.Socket;
    import java.net.URLDecoder;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Scanner;
    
    public class ChatServer {
        //SockerList用于保存當(dāng)前連接的用戶
        public static ArrayList<Socket> SocketList = new ArrayList<Socket>();
        public static void main(String[] args) throws IOException {
            //創(chuàng)建端口監(jiān)聽(tīng)用戶的請(qǐng)求
            ServerSocket sock = new ServerSocket(1999);
            System.out.println("服務(wù)啟動(dòng)....");
            //服務(wù)器循環(huán)接受來(lái)自用戶端的請(qǐng)求
            while(true) {
                //等待客戶端的請(qǐng)求疯特,捕獲到請(qǐng)求后返會(huì)一個(gè)Socket
                Socket socket = sock.accept();
                System.out.println("服務(wù)連接....");
                //將返回的Socket加入在線用戶列表中
                SocketList.add(socket);
                System.out.println("當(dāng)前有" + (SocketList.size()) + "個(gè)用戶");
                //創(chuàng)建一個(gè)新的線程哗魂,每個(gè)連接都會(huì)有自己獨(dú)立的任務(wù)線程,用于實(shí)現(xiàn)接受和發(fā)送消息
                new MsgThread(socket, SocketList).start();
            }
        }
    }
    
    //任務(wù)線程
    class MsgThread extends Thread {
        //定義單個(gè)用戶連接的Socket
        Socket client;
        //定義用戶組的Socket
        ArrayList<Socket> clients;
        //定義讀入的數(shù)據(jù)
        BufferedReader br;
        //構(gòu)造函數(shù)
        public MsgThread(Socket client, ArrayList<Socket> clients) throws IOException {
            //調(diào)用父類的構(gòu)造函數(shù)
            super();
            //使用傳入的參數(shù)初始化
            this.client = client;
            this.clients = clients;
            //將當(dāng)前用戶的輸入緩存
            br = new BufferedReader(new InputStreamReader(this.client.getInputStream()));
        }
        //重載run()函數(shù)漓雅,將接受到的用戶信息發(fā)送給其他用戶
        @Override
        public void run() {
            try {
                String content = null;
                while(true) {
                    //從某個(gè)客戶端獲取信息
                    if ((content = br.readLine()) != null) {
                        //將消息發(fā)送給其他各個(gè)客戶端
                        for (Socket socket:clients) {
                            //去掉自身客戶端
                            if (socket != client) {
                                //將消息寫(xiě)入socket的緩存區(qū),設(shè)置為自動(dòng)刷新
                                PrintWriter pw = new PrintWriter(socket.getOutputStream(), true);
                                pw.println(content);
                            }
                        }
                        content = URLDecoder.decode(content, "UTF-8");
                        System.out.println(content);
                    }
                }
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    //客戶端
    import java.io.*;
    import java.net.*;
    
    public class ChatClient {
    
        public static void main(String[] args) throws Exception {
            //連接服務(wù)端
            Socket client = new Socket("127.0.0.1", 1999);
            System.out.println("服務(wù)器已連接");
            //新建線程
            new MsgThread(client).start();
            //獲取輸入
            InputStream in = client.getInputStream();
            BufferedReader bf = new BufferedReader(new InputStreamReader(in));
            while (true) {
                String msg = bf.readLine();
                //對(duì)收到的信息進(jìn)行解碼
                msg=URLDecoder.decode(msg, "UTF-8");
                System.out.println(msg);
            }
        }
    }
    
    class MsgThread extends Thread {
        Socket client;
        String hostname;
        public MsgThread(Socket client) {
            super();
            this.client = client;
            try {
                //獲取本計(jì)算機(jī)名稱
                InetAddress addr = InetAddress.getLocalHost();
                hostname =addr.getHostName().toString();
            } catch (UnknownHostException e1) {
                e1.printStackTrace();
            }
        }
        //發(fā)送消息
        @Override
        public void run() {
            try {
                //讀取控制臺(tái)輸入
                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                //將客戶端輸出流存到pw中
                PrintWriter pw = new PrintWriter(client.getOutputStream(),true);
                while (true) {
                    String msg = br.readLine();
                    //對(duì)發(fā)出的消息進(jìn)行編碼
                    msg = URLEncoder.encode(hostname + "說(shuō):"+ msg, "UTF-8");
                    pw.println(msg);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    
    
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末录别,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子邻吞,更是在濱河造成了極大的恐慌组题,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,686評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抱冷,死亡現(xiàn)場(chǎng)離奇詭異崔列,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)徘层,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,668評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)峻呕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人趣效,你說(shuō)我怎么就攤上這事瘦癌。” “怎么了跷敬?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,160評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵讯私,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我西傀,道長(zhǎng)斤寇,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,736評(píng)論 1 284
  • 正文 為了忘掉前任拥褂,我火速辦了婚禮娘锁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘饺鹃。我一直安慰自己莫秆,他們只是感情好间雀,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,847評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著镊屎,像睡著了一般惹挟。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上缝驳,一...
    開(kāi)封第一講書(shū)人閱讀 50,043評(píng)論 1 291
  • 那天连锯,我揣著相機(jī)與錄音,去河邊找鬼用狱。 笑死运怖,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的齿拂。 我是一名探鬼主播驳规,決...
    沈念sama閱讀 39,129評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼署海!你這毒婦竟也來(lái)了吗购?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,872評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤砸狞,失蹤者是張志新(化名)和其女友劉穎捻勉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體刀森,經(jīng)...
    沈念sama閱讀 44,318評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡踱启,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,645評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了研底。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埠偿。...
    茶點(diǎn)故事閱讀 38,777評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖榜晦,靈堂內(nèi)的尸體忽然破棺而出冠蒋,到底是詐尸還是另有隱情,我是刑警寧澤乾胶,帶...
    沈念sama閱讀 34,470評(píng)論 4 333
  • 正文 年R本政府宣布抖剿,位于F島的核電站,受9級(jí)特大地震影響识窿,放射性物質(zhì)發(fā)生泄漏斩郎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,126評(píng)論 3 317
  • 文/蒙蒙 一喻频、第九天 我趴在偏房一處隱蔽的房頂上張望缩宜。 院中可真熱鬧,春花似錦甥温、人聲如沸脓恕。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,861評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)炼幔。三九已至,卻和暖如春史简,著一層夾襖步出監(jiān)牢的瞬間乃秀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,095評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工圆兵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留跺讯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,589評(píng)論 2 362
  • 正文 我出身青樓殉农,卻偏偏與公主長(zhǎng)得像刀脏,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子超凳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,687評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容