一对一聊天

news2025/2/25 2:27:16

1.创建包

.服务界面 

package yiduiy;
 
 
import java.awt.BorderLayout;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Set;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
 
public class fuwumianban extends JFrame {
    private JTextArea ta_info;
    private ServerSocket server; // 声明ServerSocket对象
    private Socket socket; // 声明Socket对象socket
    private Hashtable<String, Socket> map = new Hashtable<String, Socket>();// 用于存储连接到服务器的用户和客户端套接字对象
    
    public void createSocket() {
        try {
            server = new ServerSocket(1978);
            while (true) {
                ta_info.append("等待新客户连接......\n");
                socket = server.accept();// 创建套接字对象
                ta_info.append("客户端连接成功。" + socket + "\n");
                new ServerThread(socket).start();// 创建并启动线程对象
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    class ServerThread extends Thread {
        Socket socket;
        
        public ServerThread(Socket socket) {
            this.socket = socket;
        }
        
        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));// 创建输入流对象
                while (true) {
                    String info = in.readLine();// 读取信息
                    String key = "";
                    if (info.startsWith("用户:")) {// 添加登录用户到客户端列表
                        key = info.substring(3, info.length());// 获得用户名并作为键使用
                        map.put(key, socket);// 添加键值对
                        Set<String> set = map.keySet();// 获得集合中所有键的Set视图
                        Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器
                        while (keyIt.hasNext()) {
                            String receiveKey = keyIt.next();// 获得表示接收信息的键
                            Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象
                            PrintWriter out = new PrintWriter(s
                                    .getOutputStream(), true);// 创建输出流对象
                            Iterator<String> keyIt1 = set.iterator();// 获得所有键的迭代器
                            while (keyIt1.hasNext()) {
                                String receiveKey1 = keyIt1.next();// 获得键,用于向客户端添加用户列表
                                out.println(receiveKey1);// 发送信息
                                out.flush();// 刷新输出缓冲区
                            }
                        }
                        
                    } else {// 转发接收的消息
                        key = info.substring(info.indexOf(":发送给:") + 5, info
                                .indexOf(":的信息是:"));// 获得接收方的key值,即接收方的用户名
                        String sendUser = info.substring(0, info
                                .indexOf(":发送给:"));// 获得发送方的key值,即发送方的用户名
                        Set<String> set = map.keySet();// 获得集合中所有键的Set视图
                        Iterator<String> keyIt = set.iterator();// 获得所有键的迭代器
                        while (keyIt.hasNext()) {
                            String receiveKey = keyIt.next();// 获得表示接收信息的键
                            if (key.equals(receiveKey)
                                    && !sendUser.equals(receiveKey)) {// 如果是发送方,但不是用户本身
                                Socket s = map.get(receiveKey);// 获得与该键对应的套接字对象
                                PrintWriter out = new PrintWriter(s
                                        .getOutputStream(), true);// 创建输出流对象
                                
                                out.println("MSG:"+info);// 发送信息
                                out.flush();// 刷新输出缓冲区
                            }
                        }
                    }
                }
            } catch (IOException e) {
                ta_info.append(socket + "已经退出。\n");
            }
        }
    }
    
  
    public static void main(String args[]) {
        fuwumianban frame = new fuwumianban();
        frame.setVisible(true);
        frame.createSocket();
    }
    
 
    public fuwumianban() {
        super();
        setTitle("多个用户聊天");
        setBounds(100, 100, 385, 266);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        final JScrollPane scrollPane = new JScrollPane();
        getContentPane().add(scrollPane, BorderLayout.CENTER);
        
        ta_info = new JTextArea();
        scrollPane.setViewportView(ta_info);
    }
}

 客户界面

package yiduiy;
 
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
 
public class kehu extends JFrame {
    private JTextField tf_newUser;
    private JList user_list;
    private JTextArea ta_info;
    private JTextField tf_send;
    PrintWriter out;// 声明输出流对象
    private boolean loginFlag = false;// 为true时表示已经登录,为false时表示未登录
    
    /**
     * Launch the application
     * 
     * @param args
     */
    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    kehu frame = new kehu();
                    frame.setVisible(true);
                    frame.createClientSocket();// 调用方法创建套接字对象
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }
    
    public void createClientSocket() {
        try {
            Socket socket = new Socket("127.0.0.1", 1978);// 创建套接字对象
            out = new PrintWriter(socket.getOutputStream(), true);// 创建输出流对象
            new ClientThread(socket).start();// 创建并启动线程对象
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    class ClientThread extends Thread {
        Socket socket;
        
        public ClientThread(Socket socket) {
            this.socket = socket;
        }
        
        public void run() {
            try {
                BufferedReader in = new BufferedReader(new InputStreamReader(
                        socket.getInputStream()));// 创建输入流对象
                DefaultComboBoxModel model = (DefaultComboBoxModel) user_list
                                .getModel();// 获得列表框的模型
                while (true) {
                    String info = in.readLine().trim();// 读取信息
                    
                    if (!info.startsWith("MSG:")) {
                        boolean itemFlag = false;// 标记是否为列表框添加列表项,为true不添加,为false添加
                        for (int i = 0; i < model.getSize(); i++) {
                            if (info.equals((String) model.getElementAt(i))) {
                                itemFlag = true;
                            }
                        }
                        if (!itemFlag) {
                            model.addElement(info);// 添加列表项
                        } else {
                            itemFlag = false;
                        }
                    } else {
                        ta_info.append(info + "\n");// 在文本域中显示信息
                        if (info.equals("88")) {
                            break;// 结束线程
                        }
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    private void send() {
        if (!loginFlag) {
            JOptionPane.showMessageDialog(null, "请先登录。");
            return;
        }
        String sendUserName = tf_newUser.getText().trim();
        String info = tf_send.getText();// 获得输入的信息
        if (info.equals("")) {
            return;// 如果没输入信息则返回,即不发送
        }
        String receiveUserName = (String) user_list.getSelectedValue();// 获得接收信息的用户
        String msg = sendUserName + ":发送给:" + receiveUserName + ":的信息是: "
                + info;// 定义发送的信息
        if (info.equals("88")) {
            System.exit(0);// 如果没输入信息是88,则退出
        }
        out.println(msg);// 发送信息
        out.flush();// 刷新输出缓冲区
        tf_send.setText(null);// 清空文本框
    }
    
    /**
     * Create the frame
     */
    public kehu() {
        super();
        setTitle("多个用户聊天");
        setBounds(100, 100, 385, 288);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        final JPanel panel = new JPanel();
        getContentPane().add(panel, BorderLayout.SOUTH);
        
        final JLabel label = new JLabel();
        label.setText("输入聊天内容:");
        panel.add(label);
        
        tf_send = new JTextField();
        tf_send.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 调用方法发送信息
            }
        });
        tf_send.setPreferredSize(new Dimension(180, 25));
        panel.add(tf_send);
        
        final JButton button = new JButton();
        button.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                send();// 调用方法发送信息
            }
        });
        button.setText("发  送");
        panel.add(button);
        
        final JSplitPane splitPane = new JSplitPane();
        splitPane.setDividerLocation(100);
        getContentPane().add(splitPane, BorderLayout.CENTER);
        
        final JScrollPane scrollPane = new JScrollPane();
        splitPane.setRightComponent(scrollPane);
        
        ta_info = new JTextArea();
        scrollPane.setViewportView(ta_info);
        
        final JScrollPane scrollPane_1 = new JScrollPane();
        splitPane.setLeftComponent(scrollPane_1);
        
        user_list = new JList();
        user_list.setModel(new DefaultComboBoxModel(new String[] { "" }));
        scrollPane_1.setViewportView(user_list);
        
        final JPanel panel_1 = new JPanel();
        getContentPane().add(panel_1, BorderLayout.NORTH);
        
        final JLabel label_1 = new JLabel();
        label_1.setText("输入用户名称:");
        panel_1.add(label_1);
        
        tf_newUser = new JTextField();
        tf_newUser.setPreferredSize(new Dimension(180, 25));
        panel_1.add(tf_newUser);
        
        final JButton button_1 = new JButton();
        button_1.addActionListener(new ActionListener() {
            public void actionPerformed(final ActionEvent e) {
                if (loginFlag) {
                    JOptionPane.showMessageDialog(null, "在同一窗口只能登录一次。");
                    return;
                }
                String userName = tf_newUser.getText().trim();// 获得登录用户名
                out.println("用户:" + userName);// 发送登录用户的名称
                out.flush();// 刷新输出缓冲区
                tf_newUser.setEnabled(false);
                loginFlag = true;
            }
        });
        button_1.setText("登  录");
        panel_1.add(button_1);
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1290032.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IOday4作业

使用两个子进程完成两个文件的拷贝&#xff0c;子进程1拷贝前一半内容&#xff0c;子进程2拷贝后一半内容&#xff0c;父进程用于回收两个子进程的资源 #include<myhead.h>int main(int argc, const char *argv[]) {int pid-1;int fd -1;int fa -1;int fb -1;//求出文…

ahk系列-windows超级运行框-表达式计算(4)—len计算字符串长度

1、环境准备 windows 7&#xff0c;8&#xff0c;10&#xff0c;11操作系统ahk 2.x_64位 2、使用方式 len 用于计算字符串长度&#xff0c;同时也可以计算 “ 剪切板 ” 数据长度 输入winR打开windows运行框 在运行框中输入&#xff1a;len 你好呀&#xff01;&#xff0…

书-用数组存储高于60低于70的人单独存起来

#include<stdio.h> # define N 10 //书-用数组存储高于60低于70的人单独存起来 int main(){float s[N]{68.2,62.3,63.4,34.5,45.6,56.7,67.8,78.9,89.0,100};int i;float diyu[100];int j0;for(i0;i<N;i){if(s[i]>60 && s[i]<70)diyu[j]s[i];//这里的范…

近期复习三

目录 nginx.conf文件介绍 一.文件共享功能 1.清空html目录下文件并新建你要共享的文件 2.修改nginx.conf文件&#xff0c;开启autoindex功能 3.测试 二.状态模块 1.修改nginx.conf文件 2.测试 &#xff08;1&#xff09;使用刚才定义的IP/nginx_status进行访问 &#…

c++新经典模板与泛型编程:const修饰符的移除与增加

const修饰符的移除 让你来写移除const修饰符&#xff0c;你会怎么样来写&#xff1f; &#x1f602;&#x1f602;trait类模板&#xff0c;如下 #include <iostream>// 泛化版本 template<typename T> struct RemoveConst {using type T; };// 特化版本 template…

学完就能涨薪5k的接口自动化测试框架pytest-多线程、多进程执行用例

有些项目的测试用例较多&#xff0c;测试用例时需要分布式执行&#xff0c;缩短运行时间。 pytest框架中提供可用于分布式执行测试用例的插件&#xff1a;pytest-parallel、pytest-xdist&#xff0c;接下来我们来学习这两个插件的使用方法。 pytest-parallel pytest-paralle…

绘制6层及以上PCB板,需要明白PCB板的结构和叠层

PCB主要由PP半固化片和core芯板压合而成&#xff0c;其中core芯板两面都有铜箔&#xff0c;是PCB板的导电介质&#xff1b;PP半固化片是绝缘材料&#xff0c;用于芯板的粘合。 在PP半固化片被层压后&#xff0c;其环氧树脂被挤压开来&#xff0c;将core芯板粘合在一起。 PCB的叠…

[NAND Flash 2.1] NAND Flash 闪存改变了现代生活

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< ​ 1989年NAND闪存面世了&#xff0c;它曾经且正在改变了我们的日常生活。 NAND 闪存发明之所以伟大&#xff0c;是因为&#xff0c…

抖音短视频账号矩阵系统开发新规则

一、抖音官方平台开发新规&#xff1a; 1.代发布管理应用api接口无法在做新的应用申请 仅针对企事业单位开放&#xff0c;目前要想开发新的抖音矩阵系统&#xff0c;就需要在原有的技术算法上进行新一步的调整。 能力介绍 网站应用开发者可以申请开通【代替用户发布内容到抖…

[NAND Flash 2.2] NAND闪存及控制器的市场趋势 [2023]

依公知及经验整理&#xff0c;原创保护&#xff0c;禁止转载。 专栏 《深入理解NAND Flash》 <<<< 返回总目录 <<<< 一、NAND闪存市场分析 据欧洲知名半导体分析机构Yole发布的报告显示&#xff0c;2020年起&#xff0c;NAND闪存市场发展趋势保持稳定…

Web漏洞分析-SQL注入XXE注入(下)

随着互联网的不断普及和Web应用的广泛应用&#xff0c;网络安全问题愈发引起广泛关注。在网络安全领域中&#xff0c;SQL注入和XXE注入是两个备受关注的话题&#xff0c;也是导致许多安全漏洞的主要原因之一。本博客将深入研究这两种常见的Web漏洞&#xff0c;带您探寻背后的原…

@业务部门的,奉劝一句,赶紧掌握BI报表

趁着企业还在转型数字化&#xff0c;赶紧把BI报表掌握起来&#xff0c;以后BI大数据分析将是一个常用的企业级数据分析方向。掌握BI报表后&#xff0c;分析数据再也不用求人了。想分析什么数据&#xff0c;直接在BI平台上点击取数就是了&#xff0c;想怎么分析就怎么分析&#…

C++初学教程二

目录 一、格式化输出函数&#xff1a; 格式化输出函数printf() 1、格式 2、程序示例&#xff1a; 3、格式字符 4、举例 示例一&#xff1a; 示例二&#xff1a; ​示例三&#xff1a; 示例四&#xff1a; 示例五&#xff1a; 5、注意事项 二、格式化输入函数 格…

基于springboot+vue篮球联盟管理系统源码

&#x1f345; 简介&#xff1a;500精品计算机源码学习 &#x1f345; 欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 文末获取源码 目录 一、以下学习内容欢迎交流&#xff1a; 二、文档资料截图&#xff1a; 三、项目技术栈 四、项目运行图 背景&#xff1a; 篮球运…

Chrome浏览器调整搜索标签页按钮位置

地址栏输入 chrome://flags 搜索 chrome-refresh-2023 第一项 修改为Enabled 标签搜索页按钮出现在chrome的左上角 修改为Default 标签搜索页按钮出现在chrome的右上角 修改完成后&#xff0c;点击Relaunch&#xff0c;重启浏览器&#xff0c;修改生效。

在发布应用程序时如何选择合适的分发方式?

大家好&#xff0c;我是咕噜-凯撒&#xff0c;在现代移动互联网的环境下&#xff0c;应用已经成为人们生活不可或缺的一部分&#xff0c;选择合适的分发方式对于应用的发展和成功来说至关重要。不同的分发方式有着自己的特点和优缺点&#xff0c;所以需要针对性地进行选择。下面…

2024王道考研计算机组成原理——存储系统

微信打开的时候会有一个人站在地球上&#xff0c;这个过程就是把程序从辅存转移到主存&#xff0c;数据只有调入主存当中才可以被CPU访问 cache&#xff1a;主存速度还是慢&#xff0c;为了进一步缓解CPU和主存之间的速度矛盾 在微信打视频聊天的时候&#xff0c;在这一段比较…

算法-03-排序-归并-快速排序

冒泡排序、插入排序、选择排序这三种排序算法&#xff0c;它们的时间复杂度都是O(n^2)&#xff0c;比较高&#xff0c;适合小规模数据的排序。如果数据量大&#xff0c;我们就需要使用到时间复杂度低的排序算法&#xff0c;归并排序和快速排序是复杂度为O(nlogn)的排序算法。 …

Image Segmentation Using Deep Learning: A Survey

论文标题&#xff1a;Image Segmentation Using Deep Learning:A Survey作者&#xff1a;发表日期&#xff1a;阅读日期 &#xff1a;研究背景&#xff1a;scene understanding,medical image analysis, robotic perception, video surveillance, augmented reality, and image…

【keepalived】高可用神器,实现应用的自动主备切换

目录 1.概述 2.配置 3.效果 4.keepalived主备切换原理 5.联系作者 1.概述 什么是keepalived&#xff1a; keepalived是一个基于VRRP协议来实现的服务高可用方案。VRRP协议&#xff0c;即虚拟路由冗余协议&#xff0c;其一开始提出来是为了解决局域网中配置静态网关出现单…