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. 30. leetcode 121. Best Time to Buy and Sell Stock

    121. Best Time to Buy and Sell Stock Say you have an array for which the ith element is the price of ...

  2. poj-2287---Tian Ji -- The Horse Racing

    #include<iostream> #include<algorithm> using namespace std; bool cmp(const int,const int ...

  3. 封装sqlhelper类

    using System;using System.Collections.Generic;using System.Data;using System.Data.Common;using Syste ...

  4. PAT (Basic Level) Practise (中文)-1021. 个位数统计 (15)

    1021. 个位数统计 (15) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 给定一个k位整数N = dk-1 ...

  5. 小米wifi

    场景:把小米wifi插主机上,作为热点发射器:然后使用手机搜索到这个热点,建立wifi连接 驱动:当"把小米wifi插主机上"的时候,主机可能无法识别这个设备,所以需要前往官网下载驱动 下载地址:ht ...

  6. iOS开发中如何创建多个target

    在开发iOS应用程序的过程中,经常需要根据不同的需求,切换到不同的项目配置,或者打不同的包(测试环境.开发环境.生产环境等等),如果每次都是手动配置,一则比较麻烦,二则容易配置错,那么有没有更好的方案 ...

  7. C语言——指针

    一.什么是指针 "指针变量"是指用来存放变量地址的变量.指针变量也是一个变量,它和其他变量的区别在于它里面存的不是普通的数据,而是另一个变量的地址.访问变量有两种方式,第一种是直接 ...

  8. Node.js之错误处理与断言处理

    Node.js之错误处理与断言处理 1. 使用 domain 模块处理错误 try..catch 多用于捕捉同步方法中的抛出错误,但不能用try..catch捕捉异步方法中抛出de错误 如: 1 va ...

  9. 进程管理之wait和waitpid

    僵尸进程 在介绍wait.waitpid和waitid函数之前,首先要介绍一下僵尸进程,因为,这三个函数的本质任务就是处理僵尸进程的问题. 进程会我们的生命体一样,也有消亡.进程在退出时,内核会清理进 ...

  10. CSS选择器大汇总

    CSS选择器是学习CSS以及Web编程的基础. 整理出常用的CSS选择器,供自己和大家一起学习. 基本选择器 * /*通用元素选择器,匹配页面任何元素(这也就决定了我们很少使用)*/ #id /*id ...