d0304 更新功能实现

d0312 更新部分图片&UI设计部分

d0318 更新功能实现

d1222 实现添加好友功能、实现注册功能、修改大量BUG

github:https://github.com/He11oLiu/ChatRoom.git

==========================================================

即时通讯(Instant messaging,简称IM)是一个终端服务,允许两人或多人使用网路即时的传递文字讯息、档案、语音与视频交流。如QQ,微信都属于即时通讯。

本篇博客将详细记录我在JAVA上搭建一个自己的即时通讯工具的实现方法,如有错误的地方或者建议,请多多提出。

功能实现

基本技术

  • Socket 与 ServerSocket

    作为一个即时通讯工具,客户端(Client)和服务器(Server)是两个必不可少的部分。首先我们就来解决服务器和客户端连接的问题。

    Socket的英文原义是“孔”或“插座”。

    Socket用于描述IP地址和端口,是一个通信链的句柄,可以用来实现不同虚拟机或不同计算机之间的通信。

    在Internet上的主机一般运行了多个服务软件,同时提供几种服务。每种服务都打开一个Socket,并绑定到一个端口上,不同的端口对应于不同的服务。

    网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个Socket。建立了一个Socket后,从这个Socket中读取I/O流,就可以实现两个程序的通讯。

    而服务器需要与多个客户端进行双向的通讯连接,并非单一的连接。于是可以通过每接收到一个Client后就开一个单独的进程,来完成与该Client的通讯步骤。这样就可以同时接受多个Client,从而实现服务器的功能。

  • 客户端建立:

    Java提供了Socket类,用来建立客户端

    提供的构造方法如下:



    当调用构造方法,构造一个新的Socket的时候,就是向指定的端口请求连接。

    通过以下方法,可以获取该Socket的I/O流





    通过close方法,关闭该Socket

  • 服务器建立:

    Java提供了ServerSocket类,用来建立服务器。

    提供的构造方法如下:



    可以通过Telnet来测试是否成功的建立了服务器。(win7后默认关闭,在控制面板-程序-启用或关闭windows功能下开启)

    telnet localhost <port>

    或者

    telnet 127.0.0.1 <port>

    该类下自带了



    accept方法用来接收连接,返回一个Socket对象。接收该对象,并调用刚才提到的getInputStream()方法以及getOutputStream()方法,即可实现获取该Socket的I/O流。从该流上读取信息或者写入信息,即可达到通讯的目的。要注意的是,此时客户端的Input流对应着服务器端的Output流。

    同样ServerSocket也带了close方法,用来关闭服务器。

  • 通讯协议设计

通讯协议具体内容

type 描述
1.注册请求信息 0x01 客户发送注册请求数据给服务器 MsgReg
2.注册应答消息 0x11 客户端返回注册结果 MsgRegResp
3.登陆请求信息 0x02 客户端发送包括JK号及密码 MsgLogin
4.登录应答消息 0x22 服务器返回登录结果 MsgLoginResp
5.添加好友信息 0x05 客户端向服务器发送添加好友JK号和添加好友所在列表 MsgAddFriend
6.添加好友应答信息 0x55 服务器返回添加好友结果 MsgAddFriendResp
7.好友列表 0x03 服务器给用户发送好友列表信息 MsgTeamList
8.聊天信息 0x04 客户端给服务器/服务器给客户端消息 MsgChatText

消息头(MsgHead)

MsgHead 消息头(13) 消息体
int totalLen 消息总长度(4)
byte type 消息类型(1)
int desk 目标JK号(4) 服务器的JK号:2000000000
int src 发送用户JK号(4) 登录发送JK号:2000000001

注册消息体(MsgReg extends MsgHead)

成员属性 类型 长度(总长33)
String nikeName Octet String 10 昵称
String Pwd Octet String 10 密码

注册应答消息(MsgRegResp)

成员属性 类型 长度(总长14)
byte state byte 1 若state为0.desk为目标JK号;若state为1(或其它)错误

登录请求信息(MsgLogin)

成员属性 类型 长度(总长23)
String pwd Octet String 10 密码JK号保存到src中

登录应答信息(MsgLoginResp)

成员属性 类型 长度(14)
byte state byte 1 若为0:登录成功;若为1:JK/pwd错误;若为2:ip错误;其它:未知错误

添加好友信息 (MsgAddFriend)

成员属性 类型 长度(27)
int add_ID int 4 所添加好友的JK号
String list_name Octet String 10 添加好友至好友列表的名称

添加好友应答信息 (MsgAddFriendResp)

成员属性 类型 长度(14)
byte state byte 1 若为0:添加好友成功;若为1:不存在该用户;若为2:已经存在该好友;若为3:创建好友列表失败

好友列表信息(MsgTeamList)

成员属性 类型 长度(总长:利用计算长度)
String UserName Octet String 10 用户名字
int UserPic int 4 用户头像
byte listCount byte 1 好友分组个数,表示有几组
String listName Octet String 10 分组名称
byte bodyCount byte 1 本组有多少个用户
int bodyPic int 4 好友头像
int bodyNum int 4 好友的JK号
String nikeName Octet String 10 好友
byte bodyState byte 1 好友状态,0:在线

聊天信息(MsgChatText)

成员属性 类型 长度
String msgText Octet String 13 可聊天的内容

发送一次信息的总流程

框架设计

界面层

ChatRoom的主要界面有:

  • 登陆界面
  • 注册界面
  • 好友列表界面
  • 添加好友界面
  • 聊天界面

业务逻辑层

  • 服务器业务逻辑层

    服务器主要提供以下功能

    服务器主线程:
功能 创建服务器
描述 创建服务器。
动作 根据指定的port创建服务器。
输入 port(端口)

服务器对应每一个连接的单独线程ServerThread

这些ServerThread利用HashMap保存到线程库,key为JK号

功能 接受Client
描述 接受客户端,创建单独线程,并通过输入输出流通信。
动作 循环监听是否有client接入,若有,则创建单独线程对其进行操作。
相关 服务器服务线程,ServerThread
功能 响应登陆请求&发送好友列表
描述 响应客户端发送的登陆请求。
输入 根据输入流中读取的数据以及通讯协议,读取userid和pwd。
行动 利用数据库查询输入的userid和pwd是否匹配
输出 根据通讯协议,向输出流输出回执信息,包含最终匹配结果。
行动 若登陆信息匹配,更新用户在线表。
输出 若登陆信息匹配,则再根据通讯协议,向输出流发送好友列表。
相关 数据库,通讯协议
功能 一对一聊天
描述 响应客户端的聊天请求,并将聊天信息发到指定客户端。
输入 根据输入流中读取的数据以及通讯协议,获取目标userid以及发送内容。
行动 根据目标userid以及发送内容,给对应客户端发送信息。
输出 通过寻找对应客户端所接入的thread,给对应客户端发送内容。
相关 通讯协议,serverthread
功能 注册用户
描述 响应客户端的注册请求,并利用数据访问层提供接口写入数据库
输入 根据输入流中读取的数据以及通讯协议,获取目注册用户名以及登陆密码
行动 利用数据访问层提供接口写入数据库
输出 若注册成功,返回客户端住车好的JK号
相关 通讯协议,serverthread
功能 添加好友
描述 响应客户端的添加好友,利用数据访问层提供接口。
输入 客户端发送的添加好友的JK号已经好友列表名称
行动 利用数据访问层提供的接口判断输入的正确性,若正确在数据库中好友列表添加内容
输出 添加好友的状态。
相关 通讯协议,serverthread
  • 客户端业务逻辑层
功能 连接服务器
描述 客户端连接服务器,确认服务器可以连接。
输入 读取类中的ServerIP和port。
动作 根据ServerIP和port,开启Socket,获取输入输出流。
输出 能否连接到服务器
功能 注册
描述 输入用户名和密码
输入 NikeName和Password
动作 将注册请求,打包成消息,发送给服务器。
输出 根据服务器返回结果显示JK号或者显示注册失败。
功能 登陆服务器
描述 客户端申请登陆,确认用户密码是否正确。
输入 用户输入的userid和password
动作 将userid和password根据通讯协议传输到服务器,并接收服务器回信。
输出 用户名密码是否正确
相关 通讯协议
功能 获取好友列表
描述 完成登陆后,从服务器获取好友列表,并显示出好友界面
动作 从服务器获取好友列表,并通过给好友列表界面对象。
相关 通讯协议,好友列表界面对象
功能 一对一聊天
描述 在好友列表中点击一个好友,开始一对一聊天,可以发送/接收信息
动作 根据通讯协议,向指定用户发送信息
输入 发送的目标userid以及发送内容(聊天界面传入)
动作 根据通讯协议,读取信息来源用户,通过聊天界面显示内容。
输出 聊天内容传给聊天界面对象
相关 通讯协议,聊天界面对象
功能 添加好友
描述 添加好友到列表
输入 好友的JK号和列表名
动作 将请求打包成消息,发送给服务器,等待服务器返回结果
输出 根据结果弹出结果消息框,更新好友列表。

数据访问层

本部分由黄成越同学合作完成(https://hcyue.me/)

本次数据库选用SQLite数据库,数据库结构如下。

数据访问层提供UserModel,其中包括

  • 根据JK号获取用户内容
  • 验证用户信息
  • 获取用户好友列表
  • 增加好友,删除好友

UI设计

  • Metro UI

    Metro UI是基于瑞士平面设计原则,其最初在Windows XP的Windows Media Center就中有体现,这有利于以文字为主的界面导航。2006年著名的Zune播放器开始使用类似Metro的设计风格。微软的设计师计划重新设计现有用户界面、更清爽的排版和较少的重点以便于用户使用。Zune的桌面客户端程序也使用了不同于以往Portable Media Center用户界面,其清爽排版和设计给用户耳目一新的冲击。

    Metro UI的特点:强调信息本身

    参考资料:http://www.csdn.net/article/2012-02-01/310896/1



  • 窗体设置无边框以及拖动选项

    为了彻底改变Swing的风格,实现Metro UI的界面,将原有的边框以及按钮重写是必不可少的。

    首先,我们将窗体的边框取消

    setUndecorated(true); //设置无边框

    这行代码的作用,就是去掉了整个窗体的边框,但是同时也就去掉关闭按钮,缩小放大按钮。同时无法移动边框。为了能够移动边框,我们在窗体上添加一个监听器,代码如下。

    addMouseListener(new MouseAdapter() {
    public void mousePressed(MouseEvent e) {
    isDraging = true;
    wx = e.getX();
    wy = e.getY();
    } public void mouseReleased(MouseEvent e) {
    isDraging = false;
    }
    }); //确定鼠标按下的位置 addMouseMotionListener(new MouseMotionAdapter() {
    public void mouseDragged(MouseEvent e) {
    if (isDraging) {
    int left = getLocation().x;
    int top = getLocation().y;
    setLocation(left + e.getX() - wx, top + e.getY() - wy);
    }
    }//更改窗体的位置
    });
  • 关闭、缩小、选择按钮的重写

    因为选择了无边框,则原来的关闭以及缩小按钮都已经不能使用了,于是可以继承JButton,自己重写一个关闭,缩小按钮。同时为了配合Metro UI,选择按钮也需要重写注意实现鼠标移进、移出、按下的颜色改变(可以添加其他效果)。

    各个组件实现代码见GitHub。

  • 好友列表的实现



    要实现好友列表,第一个想到的就是树状结构。但是要实现相对漂亮的UI,利用树状结果不太好实现。

    经过多次尝试,最终确定用JScrollPane来完成这个可能需要拖动的好友列表。但是利用JScrollPane后,不宜布局,若利用JPanel来制作好友,其大小不好固定。最终重写滚动条,具体实现见代码。

[置顶] Chat Room:基于JAVA Socket的聊天室设计的更多相关文章

  1. 基于Java的在线聊天室

    概述 Java socket编程,实现一个在线聊天室, 实现在线用户群聊,私聊,发送文件等功能. 详细 代码下载:http://www.demodashi.com/demo/13623.html 一. ...

  2. Java Socket 多线程聊天室

    本来这次作业我是想搞个图形界面的,然而现实情况是我把题意理解错了,于是乎失去了最初的兴致,还是把程序变成了功能正确但是“UI”不友好的console了,但是不管怎么样,前期的图形界面的开发还是很有收获 ...

  3. 移动开发首页业界资讯移动应用平台技术专题 输入您要搜索的内容 基于Java Socket的自定义协议,实现Android与服务器的长连接(二)

    在阅读本文前需要对socket以及自定义协议有一个基本的了解,可以先查看上一篇文章<基于Java Socket的自定义协议,实现Android与服务器的长连接(一)>学习相关的基础知识点. ...

  4. workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的)

    workerman-chat(PHP开发的基于Websocket协议的聊天室框架)(thinkphp也是支持socket聊天的) 一.总结 1.下面链接里面还有一个来聊的php聊天室源码可以学习 2. ...

  5. Java Socket 网络编程心跳设计概念

    Java Socket 网络编程心跳设计概念   1.一般是用来判断对方(设备,进程或其它网元)是否正常动行,一 般采用定时发送简单的通讯包,如果在指定时间段内未收到对方响应,则判断对方已经当掉.用于 ...

  6. java Socket多线程聊天程序

    参考JAVA 通过 Socket 实现 TCP 编程 参考java Socket多线程聊天程序(适合初学者) 以J2SDK-1.3为例,Socket和ServerSocket类库位于java.net包 ...

  7. 基于springboot的websocket聊天室

    WebSocket入门 1.概述 1.1 Http #http简介 HTTP是一个应用层协议,无状态的,端口号为80.主要的版本有1.0/1.1/2.0. #http1.0/1.1/2.0 1.HTT ...

  8. Socket.IO聊天室~简单实用

    小编心语:大家过完圣诞准备迎元旦吧~小编在这里预祝大家元旦快乐!!这一次要分享的东西小编也不是很懂啊,总之小编把它拿出来是觉地比较稀奇,而且程序也没有那么难,是一个比较简单的程序,大家可以多多试试~ ...

  9. 分享基于 websocket 网页端聊天室

    博客地址:https://ainyi.com/67 有一个月没有写博客了,也是因为年前需求多.回家过春节的原因,现在返回北京的第二天,想想,应该也要分享技术专题的博客了!! 主题 基于 websock ...

随机推荐

  1. 有關於USB保固

    ================================================= 版權聲明:如需轉載,請列明出處:HingAglaiaWong@博客園 支持原創,是對作者最好的的鼓勵 ...

  2. 基于.NET CORE微服务框架 -Api网关服务管理

    1.前言 经过10多天的努力,surging 网关已经有了大致的雏形,后面还会持续更新完善,请大家持续关注研发的动态 最近也更新了surging新的版本 更新内容: 1. 扩展Zookeeper封装2 ...

  3. 【Java学习笔记之八】java二维数组及其多维数组的内存应用拓展延伸

    多维数组声明 数据类型[][] 数组名称; 数据类型[] 数组名称[]; 数据类型数组名称[][]; 以上三种语法在声明二维数组时的功能是等价的.同理,声明三维数组时需要三对中括号,中括号的位置可以在 ...

  4. promise处理多个相互依赖的异步请求

    在项目中,经常会遇到多个相互依赖的异步请求.如有a,b,c三个ajax请求,b需要依赖a返回的数据,c又需要a和b请求返回的数据.如果采用请求嵌套请求的方式自然是不可取的.导致代码难以维护,如何请求很 ...

  5. 【Spring】浅谈ContextLoaderListener及其上下文与DispatcherServlet的区别

    一般在使用SpingMVC开发的项目中,一般都会在web.xml文件中配置ContextLoaderListener监听器,如下: <listener> <listener-clas ...

  6. opencv 访问图像像素的三种方式

    访问图像中的像素 访问图像像素有三种可行的方法方法一:指针访问指针访问访问的速度最快,Mat类可以通过ptr函数得到图像任意一行的首地址,同时,Mat类的一些属性也可以用到公有属性 rows和cols ...

  7. 开源社交系统ThinkSNS+ 0.7.3研发周报

    什么是ThinkSNS+ ThinkSNS(简称TS),一款全平台综合性社交系统,为国内外大中小企业和创业者提供社会化软件研发及技术解决方案,目前最新版本为ThinkSNS+. 亲爱的粉丝,授权客户, ...

  8. QLineEdit IP地址校验

    QLineEdit IP地址校验 原文出处:[上善若静水] 1.通过自定义类方式实现IP4地址范围限制输入: //--------------------TLineEditIP.h---------- ...

  9. JavaWeb(二)jsp运行原理,九大内置对象

    JSP运行原理: 每个JSP页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet) ...

  10. Go语言中函数的实现

    Go 语言函数 函数是基本的代码块,用于执行一个任务. Go 语言最少有个 main() 函数. 你可以通过函数来划分不同功能,逻辑上每个函数执行的是指定的任务. 函数声明告诉了编译器函数的名称,返回 ...