Java 网络编程之TCP(二):基于BIO的聊天室

news/2024/9/18 21:18:35/ 标签: java, BIO, 聊天室

在上一篇【Java 网络编程之TCP(一):基于BIO】中,介绍Java中I/O和TCP的基本概念,本文在上文的基础上,实现一个基本的聊天室的功能。

聊天室需求描述:

聊天客户端:发送消息给所有其他客户端,接收其他客户端的消息

实现说明:

要想实现上面的聊天室的功能,我们需要一个服务端,和客户端

服务端:接收客户端的消息,并转发给其他客户端

客户端:发送消息给服务端,接收服务端的消息

由于基于BIO,那么服务端都需要用两个线程,来分别进行收发消息

代码如下:

服务端:

java">import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.LinkedList;
import java.util.List;/*** 基于BIO的TCP网络通信的服务端,可以接收多个客户端连接,通过字节流接收客户端发送的消息;* 并发每个客户端的数据,转发给其余所有的客户端* 一个客户端需要使用一个线程* todo:线程资源复用; 字符流readLine 没有换行符阻塞的问题** @author freddy*/
class ChatServer {// 存放所有和服务端建立连接的客户端,客户端断开,需要去除public static List<Socket> clients = new LinkedList<>();public static void main(String[] args) throws IOException {// 开启server 监听端口ServerSocket serverSocket = new ServerSocket(9999);while (true) {Socket client = serverSocket.accept(); // 阻塞操作,需要新的线程处理客户端// 客户端保存,方便后面转发数据clients.add(client);// 接收Client数据,并转发new Thread(new ServerThread(client, clients)).start();}}
}/*** 服务端的线程,一个客户端对应一个*/
class ServerThread implements Runnable {Socket socket;List<Socket> clients;public ServerThread(Socket socket, List<Socket> clients) {this.socket = socket;this.clients = clients;}@Overridepublic void run() {// 获取输入流程,读取用户输入// 持续接收Client数据,并打印System.out.println("server had a client" + socket);try (InputStream inputStream = socket.getInputStream()) {byte[] buffer = new byte[1024];int len;// read操作阻塞,直到有数据可读// -1 表示流关闭,或者读到文件末尾while ((len = inputStream.read(buffer)) != -1) {System.out.println("serer receive data from " + socket + " : " + new String(buffer, 0, len));// 转发数据到其他Clientfor (Socket client : clients) {if (client != socket) {client.getOutputStream().write(new String(buffer, 0, len).getBytes());}}}} catch (IOException e) {System.out.println(socket + " disconnect ");// 去除当前clientclients.remove(socket);}}
}

客户端代码:

java">import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;/*** 基于BIO的TCP网络通信的客户端,接收控制台输入的数据,然后通过字节流发送给服务端** @author freddy*/
class ChatClient {public static void main(String[] args) throws IOException {// 连接serverSocket serverSocket = new Socket("localhost", 9999);System.out.println("client connected to server");// 读取用户在控制台上的输入,并发送给服务器new Thread(new ClientThread(serverSocket)).start();// 接收服务端发送过来的数据try (InputStream serverSocketInputStream = serverSocket.getInputStream();) {byte[] buffer = new byte[1024];int len;while ((len = serverSocketInputStream.read(buffer)) != -1) {System.out.println("client receive data from server" + serverSocketInputStream + " : " + new String(buffer, 0, len));}}}
}class ClientThread implements Runnable {private Socket serverSocket;public ClientThread(Socket serverSocket) {this.serverSocket = serverSocket;}@Overridepublic void run() {// 读取用户在控制台上的输入,并发送给服务器InputStream in = System.in;byte[] buffer = new byte[1024];int len;try (OutputStream outputStream = serverSocket.getOutputStream();) {// read操作阻塞,直到有数据可读,由于后面还要接收服务端转发过来的数据,这两个操作都是阻塞的,所以需要两个线程while ((len = in.read(buffer)) != -1) {System.out.println("client receive data from console" + in + " : " + new String(buffer, 0, len));// 发送数据给服务器端outputStream.write(new String(buffer, 0, len).getBytes()); // 此时buffer中是有换行符}} catch (IOException e) {throw new RuntimeException(e);}}
}

测试:

先开启服务端,再开启两个客户端,在客户端1的控制台发送i'm client1,在客户端1的控制台发送this is client2,通过日志可以看到,聊天室的功能符合要求:


http://www.ppmy.cn/news/1440361.html

相关文章

再谈C语言——理解指针(二)

指针变量类型的意义 指针变量的⼤⼩和类型⽆关&#xff0c;只要是指针变量&#xff0c;在同⼀个平台下&#xff0c;⼤⼩都是⼀样的&#xff0c;为什么还要有各种各样的指针类型呢&#xff1f; 其实指针类型是有特殊意义的&#xff0c;我们接下来继续学习。 指针的解引⽤ 对⽐…

代码浮现和改进

复现就是对着开源代码跑&#xff0c;保证参考的开源代码质量较高&#xff0c;排除个人原因还跑不下来的就不用复现&#xff0c;估计作者自己也复现不出来。 改动代码的话&#xff0c;新手一般可以从修改几个层的参数&#xff0c;甚至调整超参数做起。熟悉了代码结构之后可以根…

Windows API函数之网络类函数

一. API之网络函数 1.1、WNetAddConnection函数 &#xff08;1&#xff09;函数的概述&#xff1a; WNetAddConnection是一个Windows API函数&#xff0c;用于添加一个新的网络连接。它通常用于连接到网络资源&#xff0c;如网络驱动器或共享文件夹。该函数将创建的网络连接存…

数据结构——双端队列

数据结构——双端队列 什么是双端队列双端队列的实现双端队列的使用场景 我们今天来看队列的变形——双端队列&#xff1a; 什么是双端队列 双端队列&#xff08;Double-Ended Queue, 简称deque&#xff09;是一种特殊的数据结构&#xff0c;它结合了队列&#xff08;Queue&a…

深度学习框架TensorFlow和PyTorch的选取

大家好&#xff0c;当涉及到深度学习框架时&#xff0c;TensorFlow和PyTorch是最受欢迎的两个选择。它们都是功能强大的开源库&#xff0c;使开发人员和研究人员能够构建和训练用于各种应用的神经网络。本文将探讨TensorFlow和PyTorch之间的主要区别&#xff0c;帮助你做出明智…

配置网络设备的密码设置以及忘记密码的恢复方式以及实现全网互通

1.实验拓扑图&#xff1a; 2.实验需求&#xff1a; 1.推荐步骤 1.1配置IP&#xff1a; 不过多说了&#xff0c;较为基础&#xff08;略&#xff09; 2.推荐步骤 2.所有网络设备配置console接口密码 首先进入全局模式&#xff0c;输入以下代码(进入接口console接口0给其配置密…

OneFlow新概念清单,AI深度学习的革命性突破(AI写作)

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

【计算机网络】MAC地址简介

MAC&#xff08;Medium Access Control&#xff09;&#xff0c;即媒介访问控制&#xff0c;是计算机网络通信中的重要概念。每个NIC&#xff08;Network Interface Card&#xff09;&#xff0c;即网络适配器&#xff0c;都具有独自且不变的MAC地址&#xff08;烧录的&#xf…

【软考】面向对象设计

目录 1. 说明2. 面向对象设计的活动3. 面向对象设计的原则3.1 单一责任原则3.2 开放-封闭原则3.3 里氏替换原则3.4 依赖倒置原则3.5 接口分离原则3.6 重用发布等价原则3.7 共同封闭原则3.8 共同重用原则3.9 无环依赖原则3.10 稳定依赖原则3.11 稳定抽象原则 1. 说明 1.面向对象…

CTFHub Web 信息泄漏(一)

目录遍历 打开题目 点击开始寻找flag 发现在flag_in_here页面中有四个文件夹 点击打开第一个文件夹 发现里面还有四个文件夹 再次点击打开第一个文件夹 里面什么都没有 尝试对所有文件夹依次都点击打开 在2/4中发现flag.txt 点击打开即可得到flag 不太懂这题的难点&#…

(学习日记)UCOSIII函数解释(USER文件夹搜索版)CTRL+F

写在前面: 由于时间的不足与学习的碎片化,写博客变得有些奢侈。 但是对于记录学习(忘了以后能快速复习)的渴望一天天变得强烈。 既然如此 不如以天为单位,以时间为顺序,仅仅将博客当做一个知识学习的目录,记录笔者认为最通俗、最有帮助的资料,并尽量总结几句话指明本质…

【Android】android 10 jar_sdk_library添加

前言 当前项目遇到客户&#xff0c;Android 10 平台&#xff0c;需要封装jar_sdk_library给第三方应用使用。其中jar_sdk_library中存在aidl文件。遇到无法编译通过问题。 解决 system/tools/aidl修改 Android.bp修改

钡铼IOy系列模块与云平台结合,实现工业设备远程运维与预测性维护

在当今数字化、智能化趋势下&#xff0c;工业设备的运维模式正在经历一场深刻变革。钡铼技术有限公司以其创新研发的IOy系列模块为核心&#xff0c;巧妙地将多元信号类型自由组合与云平台深度融合&#xff0c;成功构建了一套高效、精准的工业设备远程运维与预测性维护体系。 一…

Unity 数据持久化——persistentDataPath储存路径

Unity中&#xff1a; StreamingAssets的文件夹,特点是:只能读,不能写. persistentDataPath可读可写&#xff08;但是,此文件夹在Editor阶段没有&#xff0c;手机安装App后自动生成&#xff09; 可以将一些必需的文件先放在StreamingAssets,在App安装后Copy到persistentDataP…

STM32修改主频的方法

大家都知道STM32F103C8T6的主频是72M&#xff0c;那怎么样才能在程序中获得这个主频的值呢&#xff1f;怎么样才能更改主频的值呢&#xff1f; 如图找到主频的变量&#xff0c;然后显示这个变量就是显示主频了。 #include "stm32f10x.h" // Device…

【ARM 裸机】BSP 工程管理

回顾一下上一节&#xff1a;【ARM 裸机】NXP 官方 SDK 使用&#xff0c;我们发现工程文件夹里面各种文件非常凌乱&#xff1b; 那么为了模块化整理代码&#xff0c;使得同一个属性的文件存放在同一个目录里面&#xff0c;所以学习 BSP 工程管理非常有必要。 1、准备工作 新建…

五、Flask类视图和Restful

Restful 安装pip install flask-restful # exts.py from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate from flask_restful import Apidb SQLAlchemy() migrate Migrate() api Api()def init_exts(app):db.init_app(appapp)migrate.init_app(ap…

Java安全之Mojarra JSF反序列化

JavaServer Faces&#xff0c;新一代的Java Web应用技术标准&#xff0c;吸收了很多Java Servlet以及其他的Web应用框架的特性。JSF为Web应用开发定义了一个事件驱动的、基于组件的模型。 其中常用的是Sun&#xff08;现在的Oracle&#xff09;发布的Mojarra和Apache发布的MyF…

Android 自定义view 中增加属性,初始化时读取

因为自定义View 有正向和反向两个状态&#xff0c;所以需要在初始化时区分加载哪个layout 在Android中&#xff0c;要在自定义View中增加属性&#xff0c;你需要完成以下步骤&#xff1a; 在res/values/attrs.xml文件中定义属性。 在自定义View的构造函数中获取这些属性。 在…

【bugfix】error in chunk.js from uglifyjs

检查是否是因为新安装的包不支持es5&#xff0c;通过babel 或者 fork 打包输出 es5以兼容老项目。