Socket编程之聊天室

2023-11-14

1.单线程模式:
创建服务端:
第一步,准备地址和端口;第二步,创建一个ServerSocket对象;
第三步,等待客户端连接;最后一步,数据接收和发送。

public class SingleThreadServer {
    public static void main(String[] args) {
        //1. 准备地址和端口
        int port  = 1314;
        try {
            //2. ServerSocket
            ServerSocket serverSocket = new ServerSocket(port);
            //3. 等待客户端连接
            Socket client = serverSocket.accept();
            //4. 数据接收和发送
            //4.1 接收
            InputStream in = client.getInputStream();
            Scanner scanner = new Scanner(in);
            System.out.println("客户端说:"+scanner.nextLine());
            //4.2 发送
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            printStream.println("欢迎,欢迎");
            printStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建客户端:
第一步,准备服务端地址和端口号;第二步,创建客户端Socket连接服务器,
最后一步,数据传输(数据的发送和接收)。

public class SingleThreadClient {
    public static void main(String[] args) {
        //1. 服务端地址,端口号
        String ip = "127.0.0.1";//本机IP地址
        int port = 1314;
        try {
            //2.Socket
            Socket client = new Socket(ip,port);
            //3.数据传输(键盘输入,输出到显示屏)
            //3.1 发送数据
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            printStream.println("服务器,我来了");
            printStream.flush();
            //3.2 接收数据
            InputStream in = client.getInputStream();
            Scanner scanner = new Scanner(in);
            System.out.println("来自服务端的数据:"+scanner.nextLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

结果如下:
在这里插入图片描述
在这里插入图片描述
2.多线程模式:
上面的Server和Client只是进行了简单的通信操作:服务器端接收到客户端连接之后,服务器端向客户端输出一个字符串,而客户端也只是读取服务器端的字符串后就退出了。
实际应用中的客户端则可能需要和服务器端保持长时间通信,即服务器端需要不断地读取客户端数据,并向客户端写入数据;客户端也不需要不断地读取服务器端数据,并向服务器端写入数据。
创建服务端:
首先创建一个与客户端交互的任务处理;

public class ClientHandler implements Runnable {
    //储存所有注册的客户端
    private static final Map<String, Socket> socketMap = new ConcurrentHashMap<>();
    private final Socket client;
    private String name;

    public ClientHandler(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            //获取客户端输入流
            InputStream in = this.client.getInputStream();
            Scanner scanner = new Scanner(in);
            while (true) {
                String line = scanner.nextLine();
                if (line.startsWith("register:")) {
                    String[] segments = line.split(";");
                    if (segments.length == 2 && segments[0].equals("register")) {
                        String name = segments[1];
                        register(name);
                    }
                    continue;
                }
                if (line.startsWith("groupChat:")) {
                    String[] segments = line.split(":");
                    if (segments.length == 2 && segments[0].equals("groupChat")) {
                        String message = segments[1];
                        groupChat(message);
                    }
                    continue;
                }
                if (line.startsWith("privateChat:")) {
                    String[] segments = line.split(":");
                    if (segments.length == 3 && segments[0].equals("privateChat")) {
                        String name = segments[1];
                        String message = segments[2];
                        privateChat(name, message);
                    }
                    continue;
                }
                if (line.equalsIgnoreCase("bye")) {
                    quitChat();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void quitChat() {
        socketMap.remove(this.name);
        System.out.println(this.name + "下线了");
        printOnlineClient();
    }

    private void privateChat(String name, String message) {
        Socket socket = socketMap.get(name);
        if (socket != null) {
            sendMessage(socket, this.name + " 说:" + message);
        }
    }

    private void groupChat(String message) {
        for(Map.Entry<String,Socket> entry:socketMap.entrySet()) {
            Socket socket = entry.getValue();
            if (socket == this.client) {
                continue;
            }
            sendMessage(socket, this.name + "说:" + message);
        }
    }

    private void register(String name) {
        this.name = name;
        socketMap.put(name,this.client);
        System.out.println(name + "注册到系统中");
        sendMessage(this.client, "欢迎," + name + "注册成功");
        printOnlineClient();
    }
    //打印当前在线客户人数
    private void printOnlineClient() {
        System.out.println("当前在线的客户端有:" + socketMap.size() + "个,名称列表如下:");
        for(String name:socketMap.keySet()) {//keySet()取得所有的key信息
            System.out.println(name);
        }
    }
    //发指定消息到客户端
    private void sendMessage(Socket client, String s) {
        try {
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            printStream.println(s);
            printStream.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

创建服务端主程序。

public class MultiThreadServer {
    public static void main(String[] args) {
        int port = 1314;
        final ExecutorService executorService = Executors.newFixedThreadPool(2 * Runtime.getRuntime().availableProcessors());
        try {
            ServerSocket serverSocket = new ServerSocket(port);
            System.out.println("服务端启动,运行在:" + serverSocket.getLocalSocketAddress());
            while (true) {
                final Socket socket = serverSocket.accept();
                System.out.println("客户端连接,来自:" + socket.getRemoteSocketAddress());
                executorService.execute(new ClientHandler(socket));
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            executorService.shutdown();
        }
    }
}

创建客户端:
首先创建一个读取服务端信息线程;

public class ReadDataFromServerThread extends Thread{
    private Socket client;

    public ReadDataFromServerThread(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            InputStream in = client.getInputStream();
            Scanner scanner = new Scanner(in);
            while (true) {
                try {
                    String message = scanner.nextLine();
                    System.out.println("来自服务端>" +
                            message);
                }catch (NoSuchElementException e) {
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

再创建一个发送信息给服务端的线程;

public class WriteDataToServerThread extends Thread{
    private Socket client;

    public WriteDataToServerThread(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try {
            OutputStream out = client.getOutputStream();
            PrintStream printStream = new PrintStream(out);
            Scanner scanner = new Scanner(System.in);
            while (true) {
                System.out.print("请输入>");
                String message = scanner.nextLine();
                printStream.println(message);
                printStream.flush();
                if(message.equals("bye")){
                    break;
                }
            }
            this.client.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

最后客户端主程序。

public class MultiThreadClient {
    public static void main(String[] args) {
        String ip = "127.0.0.1";//本机IP地址
        int port = 1314;
        try {
            final Socket socket = new Socket(ip,port);
            new WriteDataToServerThread(socket).start();
            new ReadDataFromServerThread(socket).start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

先启动服务端,再启动多个客户端。
结果如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Socket编程之聊天室 的相关文章

  • 传输层——详解UDP和TCP的区别

    首先我们看一下UDP和TCP的特点 UDP 无连接 不可靠 面向数据报 没有发送缓冲区 TCP 面向连接 可靠 面向字节流 有发送缓冲区 1 无连接和面向连接 UDP 无连接 在网络中使用UDP协议时 只需要提供对端的IP地址和端口号POR
  • 解决vue+scss中使用 /deep/ 不生效

    遇到的问题如下 elementUI里使用复合input输入框时 默认append的样式不能满足后面经纬度符号的显示 并且背景颜色也有问题 对此进行样式修改 如下 但修改后的效果如第一张图所示没有任何效果 在Chrome里也并未出现上述样式
  • SpringBoot配置过滤器、监听器和拦截器

    一 配置过滤器 1 创建TestFilter类并实现Filter接口 WebFilter filterName testFilter urlPatterns WebFilter是定义过滤器的注解 urlPatterns 定义过滤器过滤的路径

随机推荐

  • Dependency ‘mysql:mysql-connector-java:5.1.46‘ not found

    在当前maven项目中 右键选择 Maven gt open settings xml 添加镜像 alimaven aliyun maven http maven aliyun com nexus content groups public
  • 【Cross-Chain】跨链桥架构

    在区块链中 通常利用跨链桥技术来帮助用户实现跨链交易 所谓跨链桥应用一般使用托管者 发债者架构 custodian debt issuer architecture 进行设计 在这种架构下 跨链桥主要由三个部分组成 分别是Custodian
  • 【转】经典论文翻译导读之《Finding a needle in Haystack: Facebook’s photo storage》

    译者预读 面对海量小文件的存储和检索 Google发表了GFS 淘宝开源了TFS 而Facebook又是如何应对千亿级别的图片存储 每秒百万级别的图片查询 Facebook与同样提供了海量图片服务的淘宝 解决方案有何异同 本篇文章 为您揭晓
  • 设置SecureCRT会话的缓冲区大小

    http guanjianfeng com archives 1484 在使用SecureCRT操作设备时 默认的回滚行数为500行 可以通过打开 选项 gt 会话选项 gt Terminal gt Emulation Scrollback
  • Python使用Mysql连接池

    0X00 为什么要用数据库连接池 平常可能习惯使用pymysql或者一些数据库连接包去跟数据库交互 代码可能是这样的 import pymysql config host config template MYSQL HOST port co
  • Android CoordinatorLayout使用

    一 简介 CoordinatorLayout翻译为协调者布局 是在 Google IO 15 大会发布的 是用来协调其子View们之间动作的一个容器 遵循Material Design风格 包含在 com android support d
  • arduino uno+驱动器控制42步进电机

    1 步进电机工作原理 步进电机通过不停的变换通电线圈和线圈的通电方向进行旋转 每次变换使步进电机转子转动1 8 如图所示 这里采用的是两相四线步进电机 所有的转动都由以下四个步骤构成 2 arduino 驱动器 步进电机 接线示意图 3 编
  • SpringBoot 提示: Cannot construct instance of `*` (no Creators, like default construct, exist)

    SpringBoot 提示 Cannot construct instance of com digipower sercurity entity JwtUserDetails no Creators like default constr
  • Nacos快速入门(二):Nacos集群安装部署

    1 集群部署架构图 官方提供了三种部署架构 http ip1 port openAPI 直连ip模式 机器挂则需要修改ip才可以使用 http VIP port openAPI 挂载VIP模式 直连vip即可 下面挂server真实ip 可
  • 基于Taro + 云开发 打造婚礼邀请函

    趣婚礼 基于Taro2 云开发 打造婚礼邀请函 项目名称 趣婚礼 基于Taro2 云开发 打造婚礼邀请函 Taro2 云开发 项目介绍 结婚的时候婚礼邀请函是一道必不可少的程序 但是没法去很好的留存我们的数据和回忆 除非有后端支持 最近刚好
  • java 面试的常用问题

    ArrayList 和 LinkedList 的区别 数据结构层面 ArrayList 是动态数组的数据结构 LinkedList是链表的数据结构 数据操作层面 对于随机访问get和set ArrayList优于LinkedList 对于新
  • PyQt(Python+Qt)学习随笔

    专栏 Python基础教程目录 专栏 使用PyQt开发图形界面Python应用 专栏 PyQt moviepy音视频剪辑实战 专栏 PyQt入门学习 老猿Python博文目录 老猿学5G博文目录 PyQt学习随笔 PyQt Python Q
  • EBNF范式

    1 巴科斯范式 巴科斯范式 BNF Backus Naur Form 的缩写 是由 John Backus 和 Peter Naur 首先引入的用来描述计算机语言语法的符号集 现在 几乎每一位新编程语言书籍的作者都使用巴科斯范式来定义编程语
  • web前端入门到实战:CSS遮罩效果、阴影效果、毛玻璃效果

    一般遮罩 background 000 在body标签的最后加上div标签作为遮罩 如下 div class mask div css样式 mask position fixed top 0 left 0 bottom 0 right 0
  • Thrift之TProtocol类体系原理及源码详细解析之JSon协议类TJSONProtocol

    我的新浪微博 http weibo com freshairbrucewoo 欢迎大家相互交流 共同提高技术 JSON JavaScriptObjectNotation 是一种数据交换格式 是以JavaScript为基础的数据表示语言 是在
  • vant框架DropdownMenu 下拉菜单组件在小程序中的应用

    vant框架DropdownMenu 下拉菜单组件在小程序中的应用 官方文档实例
  • Grafana Kubernetes部署(rancher)

    1 相关资源导航 https blog csdn net zyj81092211 article details 122917786 2 环境介绍 kubernetes版本 v1 23 4 rancher版本 v2 6 3 容器相关环境配置
  • 获取服务器信息失效,获取服务器时间失败

    获取服务器时间失败 内容精选 换一换 安装完Mind Studio后 如果用户进行编译运行相关操作 则需要参见该章节 将硬件环境的lib库同步到Mind Studio安装服务器 已经完成安装 请确保DDK版本号与硬件环境所安装的软件包版本号
  • IO(输入/输出)

    用户态和内核态 用户态 用来运行应用程序 不能直接对操作系统进行调用 而是需要切换到内核态对操作系统进行操作 内核态 直接访问操作系统资源或运行操作系统程序 例如程序要保存一个文件到硬盘 在程序执行的用户态 是直接操作磁盘的 只有切换到内核
  • Socket编程之聊天室

    1 单线程模式 创建服务端 第一步 准备地址和端口 第二步 创建一个ServerSocket对象 第三步 等待客户端连接 最后一步 数据接收和发送 public class SingleThreadServer public static