目录

项目介绍

项目截图

服务器与客户端

新用户注册

注册新账号成功

进入聊天室

多人在线

选择发送文件

文件接收提醒

项目代码参考

服务器入口程序

服务器请求处理

原理解析

服务器多人网络连接:

如何实现窗口抖动

获取源码


项目介绍

使用 java swing 开发多人聊天室,分为服务端和客户端,属于BS架构。

功能包括:注册、登录、单聊、群聊、窗口抖动、发送文件、选头像。

服务器:可以看到全部已注册用户的列表,用户登录之后也可以在服务器看到在线信息。

客户端:可以注册新用户,注册时可以填写昵称、密码、性别、头像。

登录成功之后会进入聊天室,在聊天室可以看到其他在线用户,也可以选择某个具体用户进行单聊。

也可以给其他用户发送窗口抖动。

也可以给其他用户发送文件。

项目截图

服务器与客户端

新用户注册

可以选择头像

注册新账号成功

进入聊天室

多人在线

选择发送文件

文件接收提醒

项目代码参考

服务器入口程序

这是服务器启动的主程序,在这里监听了网络端口,循环接收客户端的连接请求。


package server;import java.io.IOException;
import java.net.*;import javax.swing.*;import server.controller.RequestProcessor;
import server.ui.ServerInfoFrame;/** 服务器入口程序 */
public class ServerMain {public static void main(String[] args) {try {//设置外观样式UIManager.setLookAndFeel("com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); } catch (Exception e) {e.printStackTrace();}int port = Integer.parseInt(DataBuffer.configProp.getProperty("port"));//初始化服务器套节字try {DataBuffer.serverSocket = new ServerSocket(port);} catch (IOException e) {e.printStackTrace();}new Thread(new Runnable() {//启动新线程进行客户端连接监听public void run() {try {while (true) {// 监听客户端的连接Socket socket = DataBuffer.serverSocket.accept();System.out.println("客户来了:" + socket.getInetAddress().getHostAddress()+ ":" + socket.getPort());//针对每个客户端启动一个线程,在线程中调用请求处理器来处理每个客户端的请求new Thread(new RequestProcessor(socket)).start();}} catch (IOException e) {e.printStackTrace();}}}).start();//启动服务器监控窗体new ServerInfoFrame(); }
}

服务器请求处理

服务器对收到的消息进行处理,例如注册、登录、窗口震动、发送文件、接收文件、聊天、拒收文件,以及其他类型的消息都在这进行处理。


package server.controller;import java.io.*;
import java.net.Socket;
import java.text.*;
import java.util.concurrent.CopyOnWriteArrayList;
import server.*;
import server.model.service.UserService;
import common.model.entity.*;/** 服务器端请求处理器 */
public class RequestProcessor implements Runnable{private Socket currentClientSocket;  //当前正在请求服务器的客户端Socketpublic RequestProcessor(Socket currentClientSocket){this.currentClientSocket = currentClientSocket;}public void run() {boolean flag = true; //是否不间断监听try{OnlineClientIOCache currentClientIOCache = new OnlineClientIOCache(new ObjectInputStream(currentClientSocket.getInputStream()), new ObjectOutputStream(currentClientSocket.getOutputStream()));while(flag){ //不停地读取客户端发过来的请求对象//从请求输入流中读取到客户端提交的请求对象Request request = (Request)currentClientIOCache.getOis().readObject();System.out.println("Server读取了客户端的请求:" + request.getAction());String actionName = request.getAction();   //获取请求中的动作if(actionName.equals("userRegiste")){      //用户注册registe(currentClientIOCache, request);}else if(actionName.equals("userLogin")){  //用户登录login(currentClientIOCache, request);}else if("exit".equals(actionName)){       //请求断开连接flag = logout(currentClientIOCache, request);}else if("chat".equals(actionName)){       //聊天chat(request);}else if("shake".equals(actionName)){      //振动shake(request);}else if("toSendFile".equals(actionName)){ //准备发送文件toSendFile(request);}else if("agreeReceiveFile".equals(actionName)){ //同意接收文件agreeReceiveFile(request);}else if("refuseReceiveFile".equals(actionName)){ //拒绝接收文件refuseReceiveFile(request);}}}catch(Exception e){e.printStackTrace();}}/** 拒绝接收文件 */private void refuseReceiveFile(Request request) throws IOException {FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");Response response = new Response();  //创建一个响应对象response.setType(ResponseType.REFUSERECEIVEFILE);response.setData("sendFile", sendFile);response.setStatus(ResponseStatus.OK);//向请求方的输出流输出响应OnlineClientIOCache ocic = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());this.sendResponse(ocic, response);}/** 同意接收文件 */private void agreeReceiveFile(Request request) throws IOException {FileInfo sendFile = (FileInfo)request.getAttribute("sendFile");//向请求方(发送方)的输出流输出响应Response response = new Response();  //创建一个响应对象response.setType(ResponseType.AGREERECEIVEFILE);response.setData("sendFile", sendFile);response.setStatus(ResponseStatus.OK);OnlineClientIOCache sendIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getFromUser().getId());this.sendResponse(sendIO, response);//向接收方发出接收文件的响应Response response2 = new Response();  //创建一个响应对象response2.setType(ResponseType.RECEIVEFILE);response2.setData("sendFile", sendFile);response2.setStatus(ResponseStatus.OK);OnlineClientIOCache receiveIO = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());this.sendResponse(receiveIO, response2);}/** 客户端退出 */public boolean logout(OnlineClientIOCache oio, Request request) throws IOException{System.out.println(currentClientSocket.getInetAddress().getHostAddress()+ ":" + currentClientSocket.getPort() + "走了");User user = (User)request.getAttribute("user");//把当前上线客户端的IO从Map中删除DataBuffer.onlineUserIOCacheMap.remove(user.getId());//从在线用户缓存Map中删除当前用户DataBuffer.onlineUsersMap.remove(user.getId());Response response = new Response();  //创建一个响应对象response.setType(ResponseType.LOGOUT);response.setData("logoutUser", user);oio.getOos().writeObject(response);  //把响应对象往客户端写oio.getOos().flush();currentClientSocket.close();  //关闭这个客户端SocketDataBuffer.onlineUserTableModel.remove(user.getId()); //把当前下线用户从在线用户表Model中删除iteratorResponse(response);//通知所有其它在线客户端return false;  //断开监听}/** 注册 */public void registe(OnlineClientIOCache oio, Request request) throws IOException {User user = (User)request.getAttribute("user");UserService userService = new UserService();userService.addUser(user);Response response = new Response();  //创建一个响应对象response.setStatus(ResponseStatus.OK);response.setData("user", user);oio.getOos().writeObject(response);  //把响应对象往客户端写oio.getOos().flush();//把新注册用户添加到RegistedUserTableModel中DataBuffer.registedUserTableModel.add(new String[]{String.valueOf(user.getId()),user.getPassword(),user.getNickname(),String.valueOf(user.getSex())});}/** 登录 */public void login(OnlineClientIOCache currentClientIO, Request request) throws IOException {String idStr = (String)request.getAttribute("id");String password = (String) request.getAttribute("password");UserService userService = new UserService();User user = userService.login(Long.parseLong(idStr), password);Response response = new Response();  //创建一个响应对象if(null != user){if(DataBuffer.onlineUsersMap.containsKey(user.getId())){ //用户已经登录了response.setStatus(ResponseStatus.OK);response.setData("msg", "该 用户已经在别处上线了!");currentClientIO.getOos().writeObject(response);  //把响应对象往客户端写currentClientIO.getOos().flush();}else { //正确登录DataBuffer.onlineUsersMap.put(user.getId(), user); //添加到在线用户//设置在线用户response.setData("onlineUsers", new CopyOnWriteArrayList<User>(DataBuffer.onlineUsersMap.values()));response.setStatus(ResponseStatus.OK);response.setData("user", user);currentClientIO.getOos().writeObject(response);  //把响应对象往客户端写currentClientIO.getOos().flush();//通知其它用户有人上线了Response response2 = new Response();response2.setType(ResponseType.LOGIN);response2.setData("loginUser", user);iteratorResponse(response2);//把当前上线的用户IO添加到缓存Map中DataBuffer.onlineUserIOCacheMap.put(user.getId(),currentClientIO);//把当前上线用户添加到OnlineUserTableModel中DataBuffer.onlineUserTableModel.add(new String[]{String.valueOf(user.getId()), user.getNickname(), String.valueOf(user.getSex())});}}else{ //登录失败response.setStatus(ResponseStatus.OK);response.setData("msg", "账号或密码不正确!");currentClientIO.getOos().writeObject(response);currentClientIO.getOos().flush();}}/** 聊天 */public void chat(Request request) throws IOException {Message msg = (Message)request.getAttribute("msg");Response response = new Response();response.setStatus(ResponseStatus.OK);response.setType(ResponseType.CHAT);response.setData("txtMsg", msg);if(msg.getToUser() != null){ //私聊:只给私聊的对象返回响应OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());sendResponse(io, response);}else{  //群聊:给除了发消息的所有客户端都返回响应for(Long id : DataBuffer.onlineUserIOCacheMap.keySet()){if(msg.getFromUser().getId() == id ){  continue; }sendResponse(DataBuffer.onlineUserIOCacheMap.get(id), response);}}}/** 发送振动 */public void shake(Request request)throws IOException {Message msg = (Message)request.getAttribute("msg");DateFormat df = new SimpleDateFormat("HH:mm:ss");StringBuffer sb = new StringBuffer();sb.append(" ").append(msg.getFromUser().getNickname()).append("(").append(msg.getFromUser().getId()).append(") ").append(df.format(msg.getSendTime())).append("\n  给您发送了一个窗口抖动\n");msg.setMessage(sb.toString());Response response = new Response();response.setStatus(ResponseStatus.OK);response.setType(ResponseType.SHAKE);response.setData("ShakeMsg", msg);OnlineClientIOCache io = DataBuffer.onlineUserIOCacheMap.get(msg.getToUser().getId());sendResponse(io, response);}/** 准备发送文件 */public void toSendFile(Request request)throws IOException{Response response = new Response();response.setStatus(ResponseStatus.OK);response.setType(ResponseType.TOSENDFILE);FileInfo sendFile = (FileInfo)request.getAttribute("file");response.setData("sendFile", sendFile);//给文件接收方转发文件发送方的请求OnlineClientIOCache ioCache = DataBuffer.onlineUserIOCacheMap.get(sendFile.getToUser().getId());sendResponse(ioCache, response);}/** 给所有在线客户都发送响应 */private void iteratorResponse(Response response) throws IOException {for(OnlineClientIOCache onlineUserIO : DataBuffer.onlineUserIOCacheMap.values()){ObjectOutputStream oos = onlineUserIO.getOos();oos.writeObject(response);oos.flush();}}/** 向指定客户端IO的输出流中输出指定响应 */private void sendResponse(OnlineClientIOCache onlineUserIO, Response response)throws IOException {ObjectOutputStream oos = onlineUserIO.getOos();oos.writeObject(response);oos.flush();}
}

原理解析

服务器多人网络连接:

首先来分析一下要实现的流程

  • 首先建立一个服务器端,构建serversocket并绑定端口
  • 创建socket客户端,连接到指定ip以及其端口
  • 然后使用accept阻塞接收socket发出的连接请求
  • 接收到的socket对象需要使用thread单独处理,
  • 每个用户分配单独的线程进行读写处理
  • 根据输入流和输出流进行两者数据的通信
  • 获取连接后的socket客户端的输入流和输出流

值得一提是:该socket是同步阻塞的,因此在socket客户端需要进行创建一个线程,来分别进行向服务器输出,和接收服务器传输的数据。

如何实现窗口抖动

窗口的左上角是原点,我们首先记录起始坐标,计算出向左上角移动的距离和右下角移动的距离,通过循环语句控制窗口位移,最终将窗口恢复到起始坐标。

java仿qq聊天系统 多人聊天室相关推荐

  1. Java Socket实现简易多人聊天室传输聊天内容或文件

    Java Socket实现简易多人聊天室传输聊天内容或文件 Java小练手项目:用Java Socket实现多人聊天室,聊天室功能包括传输聊天内容或者文件.相比于其它的聊天室,增加了传输文件的功能供参 ...

  2. java控制台输出版多人聊天室

    多人聊天室就要用到网络以及多线程以及输入输出流的知识 多人聊天室就是多个人同时聊天,一个发一条信息所有人都是可以接收得到. 接下来我们捋清楚一下思路 在这里面服务器充当了一个转发的作用,服务器要做的事 ...

  3. Java仿QQ聊天系统Eclipse+MySql实现

    qq聊天项目使用简介: 通过之前的java学习,写了一个仿QQ的聊天程序,主要实现的功能有注册.登录.好友列表.发送文字.图片.文件.表情. 项目环境配置 软件开发工具:eclipse 项目结构:客户 ...

  4. JAVA利用websocket实现多人聊天室、私信(附源码)

    声明:此文为原创,转载请声明出处! 小编曾在毕业设计中用到了聊天室这个功能,现在稍作整理分享一下,希望能对大家有所帮助,有不足之处请指出 在学习websocket前,首先得知道它的一些基本操作,可参考 ...

  5. 【Java课程设计】仿QQ多人聊天室(基于TCP协议与JavaSwing)附下载

    仿QQ多人聊天室 下载地址:链接:https://pan.baidu.com/s/1dLFjSxwTA4gL5lI0B4UGuQ  提取码:2qs0 有两个项目,分别是服务器chatterServer ...

  6. 仿QQ聊天系统(JAVA+MySQL)

    摘  要 仿QQ聊天系统是基于MySQL数据库开发工具进行设计,理论研究与实践相结合,利用计算机技术.数据库技术,java技术等对腾讯QQ聊天系统的开发设计进行研究 以JAVA技术为核心,利用计算机局 ...

  7. java 网络编程 聊天_Java——网络编程(实现基于命令行的多人聊天室)

    目录: 1.ISO和TCP/IP分层模型 2.IP协议 3.TCP/UDP协议 4.基于TCP的网络编程 5.基于UDP的网络编程 6.基于TCP的多线程的聊天室的实现 1.ISO和TCP/IP分层模 ...

  8. 多人聊天室(Java)

    第1部分 TCP和UDP TCP:是一种可靠地传输协议,是把消息按一个个小包传递并确认消息接收成功和正确才发送下一个包,速度相对于UDP慢,但是信息准确安全:常用于一般不要求速度和需要准确发送消息的场 ...

  9. Java——网络编程(实现基于命令行的多人聊天室)

    2019独角兽企业重金招聘Python工程师标准>>> 目录: 1.ISO和TCP/IP分层模型 2.IP协议 3.TCP/UDP协议 4.基于TCP的网络编程 5.基于UDP的网络 ...

最新文章

  1. 【poj3420】 Quad Tiling
  2. Linux下防御arp***的方法
  3. 查找字符位置_学习VB编程第69天 字符串查找与替换
  4. L1相对于L2较稀疏的原因
  5. java 条件变量_Windows下条件变量的实现
  6. 列表-列表统计及删除方法扩展
  7. 开机自启动程序关闭方法_电脑非常卡,总有软件偷偷自启动?学会这1招,永久关闭它们!...
  8. 【Leetcode | 52】257. 二叉树的所有路径
  9. 2021年,Web前端还好找工作吗?
  10. Kotlin入门(6)条件分支的实现
  11. Jquery Ui AutoComplete自动填写的功能
  12. SQL 面试题及答案(一)
  13. 使用QRCode轻松实现二维码扫描下载的功能
  14. 使用yum安装Apache+PHP+MySQL
  15. 科技爱好者周刊(第 171 期):云服务流量有多贵?
  16. Houdini17 OptiX Denoise使用
  17. Raspberry 静态IP配置
  18. 山东省第五届蓝桥杯 ///标题:史丰收速算//c/c++组
  19. Selenium运行IE报错This usually means that a call to the COM method IWebBrowser2::Navigate2() failed.解决方案
  20. 北京智和信通网络流量监控分析平台

热门文章

  1. 为什么要做ASO优化?
  2. 学习资料三(11月2日更新)
  3. 解决Windows11双击QQ应用图标无法打开程序的问题
  4. 【Inception-v3模型】迁移学习 实战训练 花朵种类识别
  5. 好书分享 ——《深度工作》
  6. MySQL数据库(分库分表)中间件对比
  7. jquery去除两边空格
  8. 一文读懂数字人民币的发行原因与特性 |链捕手
  9. 时尚潮流是不一样时代的发展时尚元素
  10. 教师招聘计算机专业技能测试,教师招聘考试面试,专业技能测试考什么?全在这了...