2021-03-23 MiddleWare實(shí)驗(yàn)1 建立一個(gè)多終端文本聊天軟件(v1.0)

1 引言:

1.0 本項(xiàng)目還在不斷完善之中判帮,歡迎提出寶貴的建議袱饭。

1.1 實(shí)驗(yàn)?zāi)康?/h4>

初步需求如下:用你熟悉的語(yǔ)言雌桑,開(kāi)發(fā)一個(gè)基于網(wǎng)絡(luò)(比如Socket)的簡(jiǎn)單的互操作程序。要求在局域網(wǎng)內(nèi)實(shí)現(xiàn)網(wǎng)絡(luò)版的QQ务荆,多個(gè)終端可以進(jìn)行文本聊天妆距。

1.2 技術(shù)路線(xiàn)和開(kāi)發(fā)環(huán)境

本次任務(wù)的技術(shù)路線(xiàn)和開(kāi)發(fā)環(huán)境:
開(kāi)發(fā)語(yǔ)言:

  • Java(Java 11)

圖形化界面內(nèi)容:

  • JavaFX

開(kāi)發(fā)環(huán)境和工具:

  • IntelliJ IDEA Educational
  • JavaFX Scene Builder 2.0

技術(shù)路線(xiàn):建立C/S架構(gòu),基于Java-Socket建立TCP連接傳遞信息
開(kāi)發(fā)模式:原型開(kāi)發(fā)
備注:由于這個(gè)項(xiàng)目比較小蛹含,出于效率考慮毅厚,不會(huì)完全按照軟件工程的步驟嚴(yán)格執(zhí)行流程。

2 初步設(shè)計(jì)思路

2.0 總體設(shè)計(jì)

總體上浦箱,在功能的實(shí)現(xiàn)中吸耿,我們?cè)诟拍钌献屢慌_(tái)機(jī)器擔(dān)任服務(wù)端,若干臺(tái)機(jī)器擔(dān)任客戶(hù)端進(jìn)行通訊酷窥。


C/S架構(gòu)示意圖

這些機(jī)器共享一個(gè)聊天室咽安。由于不同機(jī)器在對(duì)話(huà)上具有對(duì)等性,我們考慮在這個(gè)程序內(nèi)讓同一臺(tái)機(jī)器既可以當(dāng)客戶(hù)端蓬推,也可以當(dāng)服務(wù)端妆棒。
換言之,讓概念上的客戶(hù)端和服務(wù)端位于同一個(gè)程序中。不同計(jì)算機(jī)的地位區(qū)別在于程序使用的時(shí)候提前進(jìn)行多方約定糕珊,由某一臺(tái)計(jì)算機(jī)擔(dān)任服務(wù)端開(kāi)放端口动分,而讓其他計(jì)算機(jī)擔(dān)任客戶(hù)端連接該端口。
在本設(shè)計(jì)中客戶(hù)端和服務(wù)端的區(qū)別有:

  • 聊天室起源于服務(wù)端開(kāi)放端口红选,由客戶(hù)端進(jìn)行連接
  • (施工中澜公。。喇肋。)

2.1 客戶(hù)端設(shè)計(jì)

客戶(hù)端主要需要考慮以下功能:

  • 連接到局域網(wǎng)中的IP與端口坟乾,加入虛擬聊天室
  • 在聊天室中發(fā)言
  • (施工中。蝶防。甚侣。)

2.2 服務(wù)端設(shè)計(jì)

服務(wù)端主要需要考慮以下功能:

  • 在會(huì)話(huà)中開(kāi)放端口,創(chuàng)建虛擬聊天室
  • 在聊天室中發(fā)言
  • (施工中间学。殷费。。)

2.3 界面設(shè)計(jì)

(施工中低葫。宗兼。。)

3 協(xié)議設(shè)計(jì)

這是一個(gè)基于TCP的連接氮采,然而我們需要設(shè)定一定的協(xié)議,使得通訊過(guò)程更加順暢染苛,沒(méi)有差錯(cuò)鹊漠。

單方發(fā)送小寫(xiě)字母q可以掐斷聯(lián)系

(施工中。茶行。躯概。)

4 類(lèi)設(shè)計(jì)

設(shè)計(jì)兩個(gè)類(lèi),一個(gè)類(lèi)是Clinet畔师,另一個(gè)類(lèi)是Server娶靡。目前先考慮命令行的基本功能操作。

4.1 服務(wù)器相關(guān)類(lèi)

地址:

src/Server/

繼承:

父類(lèi)Thread
ServerThread類(lèi)繼承Java中的Thread類(lèi)看锉,這是為了支持網(wǎng)絡(luò)進(jìn)行的多線(xiàn)程設(shè)計(jì)姿锭。

屬性:

其中有一個(gè)ServerSocket類(lèi)型的屬性和一個(gè)Socket類(lèi)型的屬性

ServerSocket與Socket不同,ServerSocket是等待客戶(hù)端的請(qǐng)求伯铣,一旦獲得一個(gè)連接請(qǐng)求呻此,就創(chuàng)建一個(gè)Socket示例來(lái)與客戶(hù)端進(jìn)行通信。參考鏈接
然后我們需要這個(gè)類(lèi)的構(gòu)造函數(shù)腔寡,當(dāng)然主要指定Port對(duì)ServerSocket初始化即可

    public ServerThread(int port) {
        try {
            server = new ServerSocket(port);
        } catch (IOException e) {
            System.out.println("Error Occcurs:");
            e.printStackTrace();
        }
    }

由于目前我們只使用這個(gè)類(lèi)進(jìn)行通信焚鲜,并且為了便于之后對(duì)這個(gè)類(lèi)進(jìn)行測(cè)試,所以添加一個(gè)函數(shù)入口,初始化線(xiàn)程為2333端口忿磅。

    public static void main(String[] args) {
        ServerThread server = new ServerThread(2333);
        server.start();
    }

在通信的過(guò)程中糯彬,我們需要一個(gè)新的線(xiàn)程來(lái)幫助我們發(fā)送消息,所以我們建立一個(gè)內(nèi)部類(lèi)葱她,并且重載run函數(shù)幫助我們進(jìn)行消息發(fā)送撩扒。主要機(jī)理是不斷讀取緩沖區(qū),如果讀取到退出則退出览效,不然就繼續(xù)却舀。

    class sendMessageThread extends Thread{
        @Override
        public void run(){
            super.run();
            Scanner scanner = null;
            OutputStream out = null;
            try{
                if(socket != null){
                    scanner = new Scanner(System.in);
                    out = socket.getOutputStream();
                    String in = "";
                    do {
                        in = scanner.next();
                        out.write((in).getBytes());
                        out.flush();
                    }while (!in.equals("q"));
                    scanner.close();
                    try{
                        out.close();
                    }catch (IOException e){
                        e.printStackTrace();
                    }
                }
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

參考鏈接

4.2 客戶(hù)端相關(guān)類(lèi)

地址:

src/Clinet/

繼承:

父類(lèi)Thread
ClinetThread類(lèi)繼承Java中的Thread類(lèi),這是為了支持網(wǎng)絡(luò)進(jìn)行的多線(xiàn)程設(shè)計(jì)锤灿。

屬性:

其中有一個(gè)一個(gè)Socket類(lèi)型的屬性以建立連接
我們需要一個(gè)構(gòu)造函數(shù)提供IP和地址初始化這一個(gè)線(xiàn)程

    public ClientThread(String host, int port) {
        try {
            socket = new Socket(host, port);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

Clinet同樣需要一個(gè)發(fā)送消息的內(nèi)部類(lèi)

    class sendMessageThread extends Thread{
        @Override
        public void run() {
            super.run();
            Scanner scanner=null;
            OutputStream out= null;
            try {
                scanner=new Scanner(System.in);
                out= socket.getOutputStream();
                String message="";
                do{
                    message=scanner.next();
                    out.write((""+message).getBytes());
                    out.flush();
                }while(!message.contentEquals("q"));
            } catch (IOException e) {
                e.printStackTrace();
            }
            scanner.close();
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

繼承線(xiàn)程類(lèi)并重載的run函數(shù)大同小異

    @Override
    public void run() {
        new sendMessageThread().start();
        super.run();
        try {
            InputStream s = socket.getInputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            String txt = "";
            boolean exist = false;
            while ((len = s.read(buffer)) != -1) {
                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                System.out.println("Server at " +  df.format(new Date()) + ":");
                System.out.println(new String(buffer, 0, len));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

主方法

    public static void main(String[] args) {
        ClientThread clientThread=new ClientThread("127.0.0.1", 2333);
        clientThread.start();
    }

4.3 功能選擇/協(xié)調(diào)類(lèi)

位置src/sample
這里姑且以Main.java命名這個(gè)類(lèi)
其實(shí)我們只要做一個(gè)功能選擇就可以了挽拔,然后讓客戶(hù)輸入對(duì)應(yīng)的信息進(jìn)行選擇C或者S模式。此處略但校。

其他

關(guān)于多線(xiàn)程:
Java中可以由主線(xiàn)程派生其他線(xiàn)程螃诅,也可以由其他線(xiàn)程派生其他線(xiàn)程,線(xiàn)程一般有以下?tīng)顟B(tài):

線(xiàn)程狀態(tài)圖

我們這個(gè)例子的狀態(tài)轉(zhuǎn)換是這樣的:線(xiàn)程被構(gòu)造状囱,并且進(jìn)入start態(tài)术裸,在一般的網(wǎng)絡(luò)通信中,資源不會(huì)很多亭枷,會(huì)直接進(jìn)入running態(tài)袭艺,然后持續(xù)。
參考鏈接

5.測(cè)試

編譯代碼叨粘,在根目錄輸入 java sample/Main
開(kāi)啟兩個(gè)窗口猾编,按照提示操作


測(cè)試.png

可以看到完成基本功能

6. 不足與下一個(gè)改進(jìn)點(diǎn):

  • 由于buffer調(diào)用的特性,空格間隔的消息會(huì)被截?cái)喑扇舾蓷l
  • 退出還比較僵硬升敲,可以考慮用個(gè)協(xié)議對(duì)消息進(jìn)行封裝
  • 缺乏連接失敗的錯(cuò)誤提醒
  • 可以考慮自行指定port的方法

項(xiàng)目鏈接地址:
https://github.com/SoneMiyuki/MiddleWare/tree/main/lab1-Mychat/1.0

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末答倡,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子驴党,更是在濱河造成了極大的恐慌瘪撇,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,496評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件港庄,死亡現(xiàn)場(chǎng)離奇詭異倔既,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)攘轩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,407評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)叉存,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人度帮,你說(shuō)我怎么就攤上這事歼捏「宕妫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,632評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵瞳秽,是天一觀的道長(zhǎng)瓣履。 經(jīng)常有香客問(wèn)我,道長(zhǎng)练俐,這世上最難降的妖魔是什么袖迎? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,180評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮腺晾,結(jié)果婚禮上城豁,老公的妹妹穿的比我還像新娘币狠。我一直安慰自己煌恢,他們只是感情好挺峡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,198評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鼻由,像睡著了一般暇榴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蕉世,一...
    開(kāi)封第一講書(shū)人閱讀 51,165評(píng)論 1 299
  • 那天蔼紧,我揣著相機(jī)與錄音,去河邊找鬼狠轻。 笑死奸例,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的向楼。 我是一名探鬼主播哩至,決...
    沈念sama閱讀 40,052評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蜜自!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起卢佣,我...
    開(kāi)封第一講書(shū)人閱讀 38,910評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤重荠,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后虚茶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體戈鲁,經(jīng)...
    沈念sama閱讀 45,324評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,542評(píng)論 2 332
  • 正文 我和宋清朗相戀三年嘹叫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了婆殿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,711評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡罩扇,死狀恐怖婆芦,靈堂內(nèi)的尸體忽然破棺而出怕磨,到底是詐尸還是另有隱情,我是刑警寧澤消约,帶...
    沈念sama閱讀 35,424評(píng)論 5 343
  • 正文 年R本政府宣布肠鲫,位于F島的核電站,受9級(jí)特大地震影響或粮,放射性物質(zhì)發(fā)生泄漏导饲。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,017評(píng)論 3 326
  • 文/蒙蒙 一氯材、第九天 我趴在偏房一處隱蔽的房頂上張望渣锦。 院中可真熱鬧,春花似錦氢哮、人聲如沸袋毙。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,668評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)娄猫。三九已至,卻和暖如春生闲,著一層夾襖步出監(jiān)牢的瞬間媳溺,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,823評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工碍讯, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留悬蔽,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,722評(píng)論 2 368
  • 正文 我出身青樓捉兴,卻偏偏與公主長(zhǎng)得像蝎困,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子倍啥,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,611評(píng)論 2 353

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