不说废话,先看效果,目前实现的基本功能有一对一私聊。一对多群聊。
1、先启动服务端,等待客户端连接…。

2、启动三个客户端,代表不同的用户。右上角分别选择不同的用户进行登录。


3、登录的用户可对所有用户发送消息,也可以对某个用户发送消息。

下面是具体的代码实现(采用传统的BIO实现,也可参考我另一篇博客NIO实现其中的功能)。
server端代码:

package Server;import java.io.*;
import java.net.*;
import java.util.*;/*
server端*/public class ChatServer {private ServerSocket ss;private boolean flag = false;private Map<String, Client> clients = new HashMap<>();public static void main(String args[]) {new ChatServer().start();}public void start() {try {ss = new ServerSocket(8888);flag = true;System.out.println("Server启动成功...");} catch (BindException e) {System.out.println("端口使用中!!!");} catch (IOException e) {e.printStackTrace();}try {//接收客户端的连接while (flag) {//accept方法是一个阻塞的方法,会阻塞当前的线程。Socket socket = ss.accept();Client c = new Client(socket);System.out.println("一个客户端已经连接...");new Thread(c).start();}} catch (IOException e) {System.out.println("Client closed...");} finally {try {if (ss != null)ss.close();} catch (IOException e) {e.printStackTrace();}}}private class Client implements Runnable {private Socket s;private String userName = "";private DataInputStream input = null;private DataOutputStream output = null;private boolean connected = false;private BufferedOutputStream fout = null;private String saveFilePath = "";public Client(Socket s) {this.s = s;try {input = new DataInputStream(s.getInputStream());output = new DataOutputStream(s.getOutputStream());connected = true;} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {byte buffer[] = new byte[1024];int len = 0;try {while (connected) {String msg[] = input.readUTF().split("#");//msg={"  ","登录用户","目标用户","要发送的信息"}switch (msg[0]) {case "LOGIN":String userName = msg[1];if (clients.containsKey(userName)) {output.writeUTF("FAIL");//已经登录System.out.println("拒绝了一个重复连接...");closeConnect();} else {output.writeUTF("SUCCESS");clients.put(userName, this);//将所有登录用户信息发送给新登录的用户StringBuffer allUsers = new StringBuffer();allUsers.append("ALLUSERS#");for (String user : clients.keySet())allUsers.append(user + "#");output.writeUTF(allUsers.toString());//将新登录的用户信息发送给其他用户String newLogin = "LOGIN#" + userName;sendMsg(userName, newLogin);this.userName = userName;}break;case "LOGOUT":clients.remove(this.userName);String logoutMsg = "LOGOUT#" + this.userName;sendMsg(this.userName, logoutMsg);System.out.println("用户" + this.userName + "已下线...");closeConnect();break;case "SENDONE":Client c = clients.get(msg[1]);//获取目标用户的连接String msgToOne="";if (c != null) {msgToOne="SENDONE#" + this.userName + "#" + msg[2];c.output.writeUTF(msgToOne);c.output.flush();}break;case "SENDALL":String msgToAll = "";msgToAll = "SENDALL#" + this.userName + "#" + msg[1];sendMsg(this.userName, msgToAll);break;}}} catch (IOException e) {System.out.println("Client closed...");connected = false;} finally {try {if (input != null)input.close();if (output != null)output.close();if (fout != null)fout.close();if (s != null)s.close();} catch (IOException e) {e.printStackTrace();}}}public void closeConnect() {connected = false;try {if (input != null)input.close();if (output != null)output.close();if (s != null)s.close();} catch (IOException e) {e.printStackTrace();}}public void sendMsg(String fromUser, String msg) {String tempUser = "";try {for (String toUser : clients.keySet()) {if (!toUser.equals(fromUser)) {tempUser = toUser;DataOutputStream out = clients.get(toUser).output;out.writeUTF(msg);out.flush();}}} catch (IOException e) {System.out.println("用户" + tempUser + "已经离线!!!");}}}
}

客户client端:

package Client;import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.Socket;
import java.net.SocketException;
/*客户client端*/public class ChatClient extends JFrame {private JTextArea sendArea, contentArea;JPanel p1, p11, p12, p2, p21, p22;JComboBox<String> user1, user2;private RecvThread clientThread = null;private String filePath = null;public void start() {Container con = getContentPane();con.setLayout(new BorderLayout());Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();int screenWidth = screenSize.width / 2;int screenHeight = screenSize.height / 2;int height = getHeight();int width = getWidth();setSize(350, 400);setLocation((screenWidth - width) / 2, (screenHeight - height) / 2);sendArea = new JTextArea(3, 10);//设置发送区域几行几列sendArea.setBorder(BorderFactory.createLineBorder(Color.BLUE, 1));sendArea.setLineWrap(true);sendArea.setWrapStyleWord(true);//激活断行不断字功能sendArea.addKeyListener(new KeyAdapter() {@Overridepublic void keyPressed(KeyEvent e) {if ('\n' == e.getKeyCode())if (clientThread != null) {clientThread.sendMsg();}}});contentArea = new JTextArea(6, 10);contentArea.setBorder(BorderFactory.createLineBorder(Color.BLUE, 1));//北边接收消息区域p1 = new JPanel();p1.setLayout(new BorderLayout());p11 = new JPanel();p11.setLayout(new GridLayout(1, 2));JLabel l1 = new JLabel("选择你的身份:");user1 = new JComboBox<>();user1.addItem("-----选择-----");user1.addItem("张三");user1.addItem("李四");user1.addItem("王五");user1.addItem("小六");user1.addItemListener(e -> {if (e.getStateChange() == ItemEvent.SELECTED) {//                    System.out.println("选中的项:" + user1.getSelectedItem());if (user1.getSelectedIndex() == 0) {return;}clientThread = new RecvThread((String) user1.getSelectedItem());new Thread(clientThread).start();}});p11.add(l1);p11.add(user1);p12 = new JPanel();p12.setLayout(new GridLayout(1, 1));p12.add(new JScrollPane(contentArea));p1.add(p11, BorderLayout.NORTH);p1.add(p12, BorderLayout.SOUTH);//南边发送消息区域p2 = new JPanel();p2.setLayout(new BorderLayout());p21 = new JPanel();p21.setLayout(new GridLayout(2, 2));user2 = new JComboBox<>();user2.addItem("所有用户");JLabel l2 = new JLabel("选择要发送的用户:");p21.add(l2);p21.add(user2);p22 = new JPanel();p22.setLayout(new GridLayout(1, 1));p22.add(new JScrollPane(sendArea));p2.add(p21, BorderLayout.NORTH);p2.add(p22, BorderLayout.SOUTH);con.add(p1, BorderLayout.NORTH);con.add(p2, BorderLayout.SOUTH);setVisible(true);setDefaultCloseOperation(EXIT_ON_CLOSE);addWindowListener(new WindowAdapter() {@Overridepublic void windowClosing(WindowEvent e) {if (clientThread != null)clientThread.exit();System.exit(0);}});}private class RecvThread implements Runnable {private Socket s = null;private DataInputStream in = null;private DataOutputStream out = null;private String userName;private boolean isLogin = false;StringBuilder msg = new StringBuilder();public RecvThread(String userName) {this.userName = userName;}//用户登录public void login() {try {s = new Socket("127.0.0.1", 8888);//监听本机的8888端口in = new DataInputStream(s.getInputStream());out = new DataOutputStream(s.getOutputStream());String sendMsg = "LOGIN#" + userName;out.writeUTF(sendMsg);out.flush();//服务器返回的信息String recv = in.readUTF();if (recv.equals("FAIL")) {showMsg(userName + "已经登录!!!");user1.setEnabled(true);exit();return;} else if (recv.equals("SUCCESS")) {showMsg("登录成功!!!");user1.setEnabled(false);isLogin = true;}} catch (IOException e) {e.printStackTrace();}}public void exit() {//用户退出,释放资源try {if (isLogin) {out.writeUTF("LOGOUT");out.flush();isLogin = false;}if (in != null)in.close();if (out != null)out.close();if (s != null)s.close();} catch (IOException e) {System.out.println("连接已关闭!!!");}}//用户发送消息public void sendMsg() {int len = 0;//   String fileName = "";if (!isLogin) {showMsg("没有登录,请登录!!!");return;}msg.setLength(0);String sendInfo = sendArea.getText().trim();String user = (String) user2.getSelectedItem();if(sendInfo.equals(""))sendInfo=" ";try {if (user.equals("所有用户")) {//给所有用户发送消息msg.append("SENDALL#");msg.append(sendInfo);} else {//只给某个用户发送消息msg.append("SENDONE#");msg.append(user+"#" + sendInfo);//如果这里sendinfo=SENDFILE那么可能就会发生错误。有待改进....}out.writeUTF(msg.toString());showMsg("我说:" + sendInfo);sendArea.setText("");} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {login();try {while (isLogin) {String msgs[] = in.readUTF().split("#");switch (msgs[0]) {case "LOGIN":user2.addItem(msgs[1]);//后面可以加个提示信息break;case "ALLUSERS":for (int i = 1; i < msgs.length; i++) {if (!"".equals(msgs[i]))user2.addItem(msgs[i]);}break;case "SENDONE":showMsg(msgs[1] + ":" + msgs[2]);break;case "SENDALL":showMsg(msgs[1] + "对所有人说:" + msgs[2]);break;case "LOGOUT":showMsg("用户" + msgs[1] + "已下线!!!");user2.removeItem(msgs[1]);break;}}} catch (SocketException e) {System.out.println(userName + "已退出...");} catch (IOException e) {isLogin = false;//返回数据出现异常,退出登录e.printStackTrace();}}}//设置显示信息public void showMsg(String msg) {contentArea.append(msg + "\n");contentArea.setCaretPosition(contentArea.getText().length());// 自动滚动到文本区的最后一行}public static void main(String args[]) {//将swing风格控件渲染成Windows风格try {UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());} catch (Exception e) {e.printStackTrace();}new ChatClient().start();}
}

上面代码我都放在gitte上面,需要的自己去拿聊天室源代码

Java聊天室(实现群聊、私聊功能)GUI界面相关推荐

  1. springboot+websocket构建在线聊天室(群聊+单聊)

    系列导读: 1.springboot+websocket构建在线聊天室(群聊+单聊) 2.Spring Boot WebSocket:单聊(实现思路) 3.Websocket Stomp+Rabbit ...

  2. socket聊天室实现-群聊,私聊,好友列表,完整版

    效果图 登录.好友上线,下线均提示. 点击好友列表所有人,发送消息,既为群聊 点击好友列表,好友名字,既为选中此好友进行私聊 服务器端代码 ChatRoomServer package sram.se ...

  3. Node + WebSocket + Vue 聊天室创建群聊/加入群聊功能 – 第五章

    前言 本次算是做了一个小小的专题吧,"Nodejs + WebSocket + Vue实现聊天室功能",目前还在一步一步推进,之前已经可以一对一.一对多聊天了,今天就来创建群聊组, ...

  4. django+vue3实现websocket聊天室(群聊)

    1.如何实现聊天功能 2.什么是websocket 2.1解释什么叫全双工,半双工,单工 3.websocker的概念 4.websocket的优点 5.django ,vue如何实现websocke ...

  5. Go实现简易聊天室(群聊)

    参考:Go 群聊 ( goroutine ) · 语雀 基于websocket的聊天室,可进一步参考: (1) go实现聊天室(WebSocket方式) (2) Golang代码搜集-基于websoc ...

  6. 佳信客服接口文档 REST API(第二部分)包含用户、聊天室、群聊、消息管理,通用接口数据结构、通用接口返回码

    6.聊天室管理 6.1.添加聊天室 接口定义: 请求URI https://api.jiaxincloud.com/rest/{orgName}/{appName}/chatrooms 访问角色 de ...

  7. C++ 实现聊天室(群聊、单聊、文件传送)

    文章目录 前言 一.前置知识点 1.相关文章 2.WTL的基本使用流程 二.项目下载与文件介绍 三.服务器代码讲解 1.NetPacket类 2.dealCli函数 3.NoticeOtherUser ...

  8. SpringBoot+STOMP 实现聊天室(单聊+多聊)及群发消息详解

    上篇系列文章:springboot+websocket构建在线聊天室(群聊+单聊) 最近发现stomp协议来实现长连接,非常简单(springboot封装的比较好) 本系列文章: 1.springbo ...

  9. Java WebSocket实现网络聊天室(群聊+私聊)

    WebChat聊天室 2018.02.26 源码地址早就贴了呀, 留邮箱不如自己下载 项目地址: https://github.com/Amayadream/WebChat 2017.01.11更新 ...

  10. 从0实现基于Linux socket聊天室-实现聊天室的公聊、私聊功能-4

    前面文章链接如下: <从0实现基于Linux socket聊天室-多线程服务器模型-1> <从0实现基于Linux socket聊天室-多线程服务器一个很隐晦的错误-2> &l ...

最新文章

  1. cookie、localStorage和sessionStorage区别
  2. 动态添加后的数据转换 — 后台接收数据
  3. 2015 German Collegiate Programming Contest (GCPC 15)
  4. 从 0 到 1,看我玩弄千万日志于股掌
  5. 简单几招优化你的Go程序
  6. python 脚本编码_Python-我如何编码我的Python脚本
  7. 2 HTTP和HTTPS
  8. Redis:30分钟从入门到精通 - 2P
  9. python怎么看自己安装的第三方包_安装第三方包查看python版本/第三方包版本
  10. iptv服务器制作 php,DIY点播服务器
  11. 计算机的静态存储区在哪里,静态随机访问存储器
  12. ubuntu14.04安装360随身wifi 2代
  13. Mac技巧|如何快速显示Mac桌面?Mac桌面快捷操作方式
  14. 程序员除了写代码,还能做哪些副业?
  15. Node Sass could not find a binding for your current environment
  16. VSLAM与VIO的3D建图,重定位与世界观综述
  17. 给图片加水印--手把手教新码农如何把技术变成产品
  18. Qt5.5-msvc2013-x64编译的程序在其它机器上无法运行,提示0xc000007b错误
  19. 2022-2027年(新版)中国质子交换膜行业发展状况及前景趋势预测报告
  20. AD7656六通道同步采集出现数据串通道的问题处理

热门文章

  1. python运行代码时标红_PyCharm 中写 Turtle代码没提示以及标黄问题
  2. C++独立游戏存档模块设计 VERSION_1.7
  3. Java8新特性DateTime使用
  4. psd缩略图上传控件
  5. Sm4【国密4加密解密】实战
  6. python deap,安装Deap for Python(Spyder)
  7. ADMM之1范数理解
  8. Baxter学习笔记
  9. 基于Python的Web开发
  10. 二种方法js实现轮播图自动切换