# JavaFX_IM **Repository Path**: idmask/JavaFX_IM ## Basic Information - **Project Name**: JavaFX_IM - **Description**: 基于JavaFX的即时通讯程序 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 3 - **Created**: 2020-05-04 - **Last Updated**: 2022-07-05 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # IM + 目录 - [注意事项](#注意事项) - [前言](#前言) - [主要思路](#主要思路) - [事件监听](#事件监听) - [消息格式设计](#消息格式设计) - [消息分发](#消息分发) - [界面](#界面) - [效果展示](#效果展示) # 注意事项 + 本项目包括程序的服务端和客户端 + 程序是基于Java8开发的 + 启动程序之前需要先将项目中lib中的jar包Add to Build Path + 启动客户端之前需要先启动服务端 + 使用IDE创建项目时,应该选择JavaFX项目 + 各种消息的格式以及在通信过程中的具体使用方式,可以查看下项目中的"消息格式对照表" + 由于并未实现注册功能,并且程序实现的是,程序启动时从本地的user.db(已经有3个可用的用户数据)读取用户数据,当程序关闭时,将用户数据写入user.db文件中。所以,请不要删除user.db文件,或者自行实现注册功能也可以。 # 前言 之前写了一个即时通讯桌面应用程序,使用JavaFX进行开发,使用socket来完成客户端之间的消息传递。做一下总结,程序写得比较简单,存在很多不够好的地方。 # 主要思路 我做的聊天程序有服务端和客户端。 + **主要完成的功能有:用户登陆功能,普通消息发送功能(文字+emoji表情),文件传输功能,视频通信功能** + 服务端主要负责客户端登陆时的信息验证和负责接受客户端的上线下线的状态消息,维护在线用户列表,并且向客户端更新在线用户列表消息。并且服务端还可以管理用户信息和在聊天大厅中聊天,充当管理员的角色。 + 客户端需要与客户端之间一直维持着socket连接,如果连接断开,服务端会判定为用户下线,并且更新用户列表。客户端与客户端之间进行聊天时,所传递的消息不需要经过服务端,也就是说,此时的客户端相当与有一个内置的服务器,可以监听其他客户端发送的连接请求,并且使用该socket连接来完成通信。 + 因此服务端程序只开放一个端口,而客户端启动时会使用一个随机端口,客户端登陆成功后会启动一个内置的服务器,客户端会把内置服务器的监听端口向服务端进行汇报登记,服务在更新在线用户列表时会把客户端相对应的内置服务器端口一并更新了。然后不用用户之间进行通信时,如果之前已经有用于通信的连接,那么就使用这个已存在的连接,如果是第一次与这个用户进行通信,那么就向这个用户的监听端口发起连接请求,然后进行通信。 ![在这里插入图片描述](https://github.com/godelgnisEJW/IM/blob/master/images/structure.png) 使用这种方式,则客户端之间总的只需要3个socket连接即可实现客户端之间相互通信。如果不采用这种方式,每与一个新的用户通信就建立一个新的socket连接,那么就会多建立一倍的socket。 # 事件监听 我自定义了程序中的几个事件,分别是程序启动事件(需要完成程序初始化工作),程序关闭事件(需要完成程序的收尾工作,包括用户信息保存和临时文件的删除等),消息事件(需要进行消息分发)。 使用了观察者模式和中介者模式 ![在这里插入图片描述](https://github.com/godelgnisEJW/IM/blob/master/images/uml.jpg) 在程序启动,程序关闭和接收到消息时,会分别产生相应事件类型的事件,触发事件分派器分派消息。事件处理器需要到事件分派器进行注册,处理相应的事件。其中EventDispatch既扮演观察者的角色,又扮演中介者的角色。 # 消息格式设计 以下是我设计的消息格式 ![在这里插入图片描述](https://github.com/godelgnisEJW/IM/blob/master/images/msgformat1.png) 格式比较简单,每条消息的第一个字节为这条消息的消息类型,然后接着的四个字节为消息内容的长度,紧接着的就是消息的内容了。 客户端在接受消息的时候就可以按照固定的格式读取指定的字节内容,消息内容则根据4个字节的消息长度读取指定的字节数,这样就可以解决**TCP消息无边界**的问题了。 最初的消息格式的设计太过于简单,以至于后续要扩展消息格式时不好用,缺少参数的设置。。。 如果重新设计的话,我会设计成这样 ![在这里插入图片描述](https://github.com/godelgnisEJW/IM/blob/master/images/msgformat2.png) 这样设计的话消息就能带上参数,消息类型和内容的扩展会更加容易。 # 消息分发 ![在这里插入图片描述](https://github.com/godelgnisEJW/IM/blob/master/images/dispatch.png) 消息的分发主要使用中介者模式,程序中定义的多个消息解析器需要在MessageDispatch进行注册。 MessageDispatch在接收到消息事件时,会将接受到的消息进行分发,不同的消息类型有不同的解析方式。 # 界面 界面主要使用**Scence Builder**来完成,操作简便,可以快速完成界面的设计,有一点值得一提的是,在设计的时候我习惯用AnchorPane作为最底层的面板,该面板上的元素位置可以很容易地进行调整,而不像BorderPane或者StackPane那样,面板上元素的位置是固定的,不容易进行调整。 # 效果展示 ![服务端启动](https://github.com/godelgnisEJW/IM/blob/master/images/server.gif) ![客户端登录](https://github.com/godelgnisEJW/IM/blob/master/images/login.gif) ![发送文字消息](https://github.com/godelgnisEJW/IM/blob/master/images/chat.gif) ![发送文件](https://github.com/godelgnisEJW/IM/blob/master/images/file.gif) ![视频通话](https://github.com/godelgnisEJW/IM/blob/master/images/video.gif)