2021-03-23 MiddleWare实验1 建立一个多终端文本聊天软件(v1.0)

1 引言:

1.0 本项目还在不断完善之中,欢迎提出宝贵的建议。

1.1 实验目的

初步需求如下:用你熟悉的语言,开发一个基于网络(比如Socket)的简单的互操作程序。要求在局域网内实现网络版的QQ,多个终端可以进行文本聊天。

1.2 技术路线和开发环境

本次任务的技术路线和开发环境:
开发语言:

  • Java(Java 11)

图形化界面内容:

  • JavaFX

开发环境和工具:

  • IntelliJ IDEA Educational
  • JavaFX Scene Builder 2.0

技术路线:建立C/S架构,基于Java-Socket建立TCP连接传递信息
开发模式:原型开发
备注:由于这个项目比较小,出于效率考虑,不会完全按照软件工程的步骤严格执行流程。

2 初步设计思路

2.0 总体设计

总体上,在功能的实现中,我们在概念上让一台机器担任服务端,若干台机器担任客户端进行通讯。


C/S架构示意图

这些机器共享一个聊天室。由于不同机器在对话上具有对等性,我们考虑在这个程序内让同一台机器既可以当客户端,也可以当服务端。
换言之,让概念上的客户端和服务端位于同一个程序中。不同计算机的地位区别在于程序使用的时候提前进行多方约定,由某一台计算机担任服务端开放端口,而让其他计算机担任客户端连接该端口。
在本设计中客户端和服务端的区别有:

  • 聊天室起源于服务端开放端口,由客户端进行连接
  • (施工中。。。)

2.1 客户端设计

客户端主要需要考虑以下功能:

  • 连接到局域网中的IP与端口,加入虚拟聊天室
  • 在聊天室中发言
  • (施工中。。。)

2.2 服务端设计

服务端主要需要考虑以下功能:

  • 在会话中开放端口,创建虚拟聊天室
  • 在聊天室中发言
  • (施工中。。。)

2.3 界面设计

(施工中。。。)

3 协议设计

这是一个基于TCP的连接,然而我们需要设定一定的协议,使得通讯过程更加顺畅,没有差错。

单方发送小写字母q可以掐断联系

(施工中。。。)

4 类设计

设计两个类,一个类是Clinet,另一个类是Server。目前先考虑命令行的基本功能操作。

4.1 服务器相关类

地址:

src/Server/

继承:

父类Thread
ServerThread类继承Java中的Thread类,这是为了支持网络进行的多线程设计。

属性:

其中有一个ServerSocket类型的属性和一个Socket类型的属性

ServerSocket与Socket不同,ServerSocket是等待客户端的请求,一旦获得一个连接请求,就创建一个Socket示例来与客户端进行通信。参考链接
然后我们需要这个类的构造函数,当然主要指定Port对ServerSocket初始化即可

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

由于目前我们只使用这个类进行通信,并且为了便于之后对这个类进行测试,所以添加一个函数入口,初始化线程为2333端口。

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

在通信的过程中,我们需要一个新的线程来帮助我们发送消息,所以我们建立一个内部类,并且重载run函数帮助我们进行消息发送。主要机理是不断读取缓冲区,如果读取到退出则退出,不然就继续。

    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 客户端相关类

地址:

src/Clinet/

继承:

父类Thread
ClinetThread类继承Java中的Thread类,这是为了支持网络进行的多线程设计。

属性:

其中有一个一个Socket类型的属性以建立连接
我们需要一个构造函数提供IP和地址初始化这一个线程

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

Clinet同样需要一个发送消息的内部类

    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();
            }
        }
    }

继承线程类并重载的run函数大同小异

    @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 功能选择/协调类

位置src/sample
这里姑且以Main.java命名这个类
其实我们只要做一个功能选择就可以了,然后让客户输入对应的信息进行选择C或者S模式。此处略。

其他

关于多线程:
Java中可以由主线程派生其他线程,也可以由其他线程派生其他线程,线程一般有以下状态:

线程状态图

我们这个例子的状态转换是这样的:线程被构造,并且进入start态,在一般的网络通信中,资源不会很多,会直接进入running态,然后持续。
参考链接

5.测试

编译代码,在根目录输入 java sample/Main
开启两个窗口,按照提示操作


测试.png

可以看到完成基本功能

6. 不足与下一个改进点:

  • 由于buffer调用的特性,空格间隔的消息会被截断成若干条
  • 退出还比较僵硬,可以考虑用个协议对消息进行封装
  • 缺乏连接失败的错误提醒
  • 可以考虑自行指定port的方法

项目链接地址:
https://github.com/SoneMiyuki/MiddleWare/tree/main/lab1-Mychat/1.0

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,657评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,662评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,143评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,732评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,837评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,036评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,126评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,868评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,315评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,641评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,773评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,859评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,584评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,676评论 2 351

推荐阅读更多精彩内容