【Java 网络编程】TCP 服务器端 客户端 简单示例(二)

简介: 【Java 网络编程】TCP 服务器端 客户端 简单示例(二)

IX ServerSocket 服务器端同时与多个客户端交互方案


将与单个客户端交互的操作封装到线程中 , 每当与一个新的客户端建立连接 , 就开启一个异步线程处理与该客户端之间的交互 ;


客户端处理线程 :


 

/**
     * 异步线程 , 处理单个客户端连接
     * 如果多个客户端连接 , 就需要创建多个该类, 同时处理多个客户端连接
     */
    public static class ClientHandler extends Thread{
        //1. 客户端 Socket 连接
        private Socket clientSocket;
        public ClientHandler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }
    }


无限循环等待客户端连接 , 一旦连接成功 , 就开启一个异步线程 ;


         

//II. 等待客户端连接, 注意此处是无限循环连接
            while(true){
                //1. 收到一个客户端连接请求 , 获取 客户端 Socket 连接
                Socket clientSocket = serverSocket.accept();
                //2. 将 Socket 连接传入 ClientHandler 线程 , 异步处理与客户端交互操作
                ClientHandler clientHandler = new ClientHandler(clientSocket);
                //3. 启动 与客户端 Socket 交互处理 异步线程
                clientHandler.start();
            }




X Socket 客户端代码示例


import java.io.*;
import java.net.*;
/**
 * 客户端
 */
public class Client {
    /**
     * 客户端入口函数
     * @param args
     */
    public static void main(String[] args){
        try {
            //I. 连接
            //1. 创建 Socket 对象
            Socket socket = new Socket();
            //2. 设置 Socket 的超时时间
            socket.setSoTimeout(5000);
            //3. 创建连接的端点 , 该端点包括 IP 地址和端口号
            InetSocketAddress inetSocketAddress =
                    new InetSocketAddress(
                            Inet4Address.getLocalHost(),   //本机IP地址
                            8000                      //端口号
                    );
            //4.. 连接服务器端点 , 并设置超时时间
            socket.connect(inetSocketAddress, 5000);
            //5. 如果连接成功会继续执行下面的操作, 如果失败会根据失败情况抛出异常
            //II. 获取 Socket 连接两个端点的属性, IP 地址和端口号
            //1. 获取服务器 IP 地址
            InetAddress serverAddress = socket.getInetAddress();
            //2. 获取服务器端口号
            int serverPort = socket.getPort();
            //3. 获取客户端 IP 地址
            InetAddress clientAddress = socket.getLocalAddress();
            //4. 获取客户端端口号
            int clientPort = socket.getLocalPort();
            System.out.println("服务器连接成功\n服务器地址 : " + serverAddress +
                    " , 服务器端口号 : " + serverAddress +
                    "\n客户端地址 : " + clientAddress + " , 客户端端口号 : " + clientPort);
            //向服务器端发送数据
            sendToServer(socket);
            //III. 关闭 Socket 连接
            socket.close();
            System.out.println("客户端 Socket 连接关闭");
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            //客户端可能挂了 , 需要重启
        }
    }
    public static void sendToServer(Socket socket){
        try {
            //I. 获取用户控制台输入信息
            //1. 获取控制台输入流
            InputStream is = System.in;
            //2. 该输入流会阻塞 , 等待用户控制台输入
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //II. 将用户输入信息上传到服务器
            //4. 获取客户端的输出流 , 用于向服务器端写出数据
            OutputStream os = socket.getOutputStream();
            //5. 创建打印流 , 用于向服务器端写出字符
            PrintStream ps = new PrintStream(os);
            //III. 从服务器获取信息 , 这里循环读取数据, 接收到 服务器端的 quit 字符串才退出
            //1. 获取服务器端输入流
            InputStream isFromServer = socket.getInputStream();
            //2. 将输入流转为 BufferedReader
            BufferedReader brFromServer = new BufferedReader(new InputStreamReader(isFromServer));
            //3. 循环控制变量 , 退出时设置为 false
            boolean isReadFromServer = true;
            while (isReadFromServer){
                //4. 阻塞命令行 , 等待用户输入一行数据, 并存入 string 对象中
                String string = br.readLine();
                //5. 通过打印流 , 将该字符串传输给服务器端
                ps.println(string);
                //6. 阻塞控制台 , 从服务器读取一行数据
                String stringFromServer = brFromServer.readLine();
                //7. 根据服务器返回的数据进行不同操作
                if("quit".equals(stringFromServer)){
                    //停止循环
                    isReadFromServer = false;
                }else{
                    System.out.println(stringFromServer);
                }
            }
            //IV. 释放资源
            br.close();
            ps.close();
            brFromServer.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}





XI Socket 服务器端代码示例


import java.io.*;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
 * 服务器端
 */
public class Server {
    /**
     * 服务器端入口函数
     * @param args
     */
    public static void main(String[] args){
        try {
            //I. 创建服务器套接字, 并监听端口
            //1. 创建服务器套接字 , 只需要指定端口即可 , 不需要指定 IP 地址
            //      其 IP 地址就是本机的 IP 地址 , 如果机器有多个 IP 地址
            //      如果没有指定 IP 地址 , 那么会监听所有的 IP 地址的指定端口号
            ServerSocket serverSocket = new ServerSocket(8000);
            //2. 获取服务器端 IP 地址
            InetAddress inetAddress = serverSocket.getInetAddress();
            //3. 获取服务器端口号
            int localPort = serverSocket.getLocalPort();
            System.out.println("服务器开启\nIP 地址 : " + inetAddress + " , 端口号 : " + localPort);
            //II. 等待客户端连接, 注意此处是无限循环连接
            while(true){
                //1. 收到一个客户端连接请求 , 获取 客户端 Socket 连接
                Socket clientSocket = serverSocket.accept();
                //2. 将 Socket 连接传入 ClientHandler 线程 , 异步处理与客户端交互操作
                ClientHandler clientHandler = new ClientHandler(clientSocket);
                //3. 启动 与客户端 Socket 交互处理 异步线程
                clientHandler.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    /**
     * 异步线程 , 处理单个客户端连接
     * 如果多个客户端连接 , 就需要创建多个该类, 同时处理多个客户端连接
     */
    public static class ClientHandler extends Thread{
        //1. 客户端 Socket 连接
        private Socket clientSocket;
        //2. 循环控制变量
        private boolean loopFlag = true;
        public ClientHandler(Socket clientSocket) {
            this.clientSocket = clientSocket;
        }
        @Override
        public void run() {
            super.run();
            //I. 获取客户端相关信息
            //1. 获取客户端的 IP 地址
            InetAddress inetAddress = clientSocket.getInetAddress();
            //2. 获取客户端的端口号
            int port = clientSocket.getPort();
            //3. 打印客户端的信息
            System.out.println("客户端信息 : \nIP 地址 : " + inetAddress + " , 端口号 : " + port);
            try {
                //II. 创建与客户端交互的输入输出流
                //1. 获取客户端 Socket 输出流 , 用于向客户端发送数据
                OutputStream os = clientSocket.getOutputStream();
                //2. 创建打印流 , 用于向客户端输出数据
                PrintStream ps = new PrintStream(os);
                //3. 获取客户端 Socket 输入流 , 用于接收客户端数据
                InputStream is = clientSocket.getInputStream();
                //4. 获取客户端的字符输入流 , 该输入流可以阻塞等待客户端输入
                BufferedReader br = new BufferedReader(new InputStreamReader(is));
                //III. 循环处理与客户端交互的信息
                while (loopFlag){
                    //1. 等待客户端输入
                    String string = br.readLine();
                    //2. 处理客户端输入
                    if("quit".equals(string)){
                        //如果客户端发送退出, 那么停止循环, 将该信息在送回客户端
                        loopFlag = false;
                        //将信息发送到客户端
                        ps.println("quit");
                    }else{
                        //将信息打印到控制台
                        System.out.println(string);
                        //将发送成功信息返回给客户端
                        ps.println("发送成功 , 大小 " + string.length() + " 字节");
                    }
                }
                //IV. 关闭相关资源
                ps.close();
                br.close();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                try {
                    //如果出现异常 , 将该 Socket 关闭
                    clientSocket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("客户端退出 : \nIP 地址 : " + inetAddress + " , 端口号 : " + port);
        }
    }
}





XII 运行客户端与服务器端代码


1. 编译两个 Java 代码 : 选择菜单栏 -> Build -> Rebuild Project 选项 , 获取到 Client.class 和 Server.class 文件 ;




2. 字节码文件地址 : 编译后的 class 字节码文件在工程目录的 out\production\classes 目录下 ;




打开两个命令行界面 , 首先进入该目录 , 先运行服务器端 , 在命令行中输入 java Server , 即开启了服务器端 ; 再打开客户端 , 在另一个命令行中运行 java Client , 即开启了客户端 ;




客户端输入文字 , 与服务器端交互 :


image.png

目录
相关文章
|
1月前
|
JSON 网络协议 安全
【Java】(10)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
111 1
|
1月前
|
JSON 网络协议 安全
【Java基础】(1)进程与线程的关系、Tread类;讲解基本线程安全、网络编程内容;JSON序列化与反序列化
几乎所有的操作系统都支持进程的概念,进程是处于运行过程中的程序,并且具有一定的独立功能,进程是系统进行资源分配和调度的一个独立单位一般而言,进程包含如下三个特征。独立性动态性并发性。
119 1
|
5月前
|
JSON 中间件 Go
Go 网络编程:HTTP服务与客户端开发
Go 语言的 `net/http` 包功能强大,可快速构建高并发 HTTP 服务。本文从创建简单 HTTP 服务入手,逐步讲解请求与响应对象、URL 参数处理、自定义路由、JSON 接口、静态文件服务、中间件编写及 HTTPS 配置等内容。通过示例代码展示如何使用 `http.HandleFunc`、`http.ServeMux`、`http.Client` 等工具实现常见功能,帮助开发者掌握构建高效 Web 应用的核心技能。
306 61
|
5月前
|
运维 网络协议 Go
Go网络编程:基于TCP的网络服务端与客户端
本文介绍了使用 Go 语言的 `net` 包开发 TCP 网络服务的基础与进阶内容。首先简述了 TCP 协议的基本概念和通信流程,接着详细讲解了服务端与客户端的开发步骤,并提供了简单回显服务的示例代码。同时,文章探讨了服务端并发处理连接的方法,以及粘包/拆包、异常检测、超时控制等进阶技巧。最后通过群聊服务端的实战案例巩固知识点,并总结了 TCP 在高可靠性场景中的优势及 Go 并发模型带来的便利性。
|
Ubuntu 网络协议 Unix
02理解网络IO:实现服务与客户端通信
网络IO指客户端与服务端通过网络进行数据收发的过程,常见于微信、QQ等应用。本文详解如何用C语言实现一个支持多客户端连接的TCP服务端,涉及socket编程、线程处理及通信流程,并分析“一消息一线程”模式的优缺点。
244 0
|
8月前
|
Java Linux 定位技术
Minecraft配置文件参数说明(JAVA服务器篇)
Minecraft JAVA版服务器启动后会生成server.properties配置文件,位于minecraft_server/根目录下。该文件包含多项关键设置,如游戏模式(gamemode)、最大玩家数(max-players)、难度(difficulty)等。此文档详细说明了各配置项的功能与默认值,帮助用户高效管理服务器环境。
1873 60
|
8月前
|
前端开发 Cloud Native Java
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
Java||Springboot读取本地目录的文件和文件结构,读取服务器文档目录数据供前端渲染的API实现
|
8月前
|
存储 网络协议 安全
Java网络编程,多线程,IO流综合小项目一一ChatBoxes
**项目介绍**:本项目实现了一个基于TCP协议的C/S架构控制台聊天室,支持局域网内多客户端同时聊天。用户需注册并登录,用户名唯一,密码格式为字母开头加纯数字。登录后可实时聊天,服务端负责验证用户信息并转发消息。 **项目亮点**: - **C/S架构**:客户端与服务端通过TCP连接通信。 - **多线程**:采用多线程处理多个客户端的并发请求,确保实时交互。 - **IO流**:使用BufferedReader和BufferedWriter进行数据传输,确保高效稳定的通信。 - **线程安全**:通过同步代码块和锁机制保证共享数据的安全性。
312 23
|
9月前
|
监控 Linux PHP
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
【02】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-2月12日优雅草简化Centos stream8安装zabbix7教程-本搭建教程非docker搭建教程-优雅草solution
265 20
|
9月前
|
监控 关系型数据库 MySQL
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
【01】客户端服务端C语言-go语言-web端PHP语言整合内容发布-优雅草网络设备监控系统-硬件设备实时监控系统运营版发布-本产品基于企业级开源项目Zabbix深度二开-分步骤实现预计10篇合集-自营版
233 0

热门文章

最新文章