Java【网络原理】(3)网络编程续


目录

1.前言

2.正文

2.1ServerSocket类

2.2Socket类

2.3Tcp回显服务器

2.3.1TcpEchoServer

2.3.2TcpEchoClient

3.小结


1.前言

哈喽大家好,今天继续进行计算机网络的初阶学习,今天学习的是tcp回显服务器的实现,正文开始

2.正文

在正式讲解Tcp回显服务器,还要介绍两个包,一个是ServerSocket包,这个包是专门给服务器用的,Socket包是服务器和客户端都会用,下文详解。

2.1ServerSocket类

Java中的ServerSocket类是用于在服务器端监听客户端连接请求的核心类,属于java.net包。它允许服务器应用程序在指定端口上等待客户端的连接,并为每个连接创建一个Socket对象进行通信。


核心作用

  • 监听端口:绑定到特定端口,等待客户端连接。

  • 接受连接:通过accept()方法阻塞等待客户端连接,返回代表客户端的Socket对象。

  • 管理连接队列:通过backlog参数设置等待连接队列的最大长度。

关键方法

  1. 构造方法

    • ServerSocket(int port):绑定到指定端口。

    • ServerSocket(int port, int backlog):指定端口和连接队列长度。

    • ServerSocket(int port, int backlog, InetAddress bindAddr):绑定到特定IP地址的端口。

  2. 核心方法

    • Socket accept():阻塞等待客户端连接,返回连接的Socket对象。

    • void bind(SocketAddress endpoint):绑定到指定地址和端口。

    • void close():关闭服务器套接字。

    • int getLocalPort():获取监听的端口号。

    • void setSoTimeout(int timeout):设置accept()的超时时间(毫秒)。

使用流程

  1. 创建ServerSocket并绑定端口。

  2. 循环调用accept()接受客户端连接。

  3. 为每个连接的Socket启动新线程处理请求。

  4. 处理完成后关闭资源。

2.2Socket类

Java中的Socket类是用于实现网络通信的核心类,属于java.net包。它代表客户端与服务器之间的一个连接,允许通过输入流和输出流进行双向数据传输。Socket类通常与ServerSocket类配合使用,实现客户端-服务器模型的通信。


核心作用

  • 建立连接:连接到服务器端的指定IP地址和端口。

  • 数据传输:通过输入流(InputStream)和输出流(OutputStream)进行数据交换。

  • 关闭连接:释放资源并终止通信。

关键方法

  1. 构造方法

    • Socket(String host, int port):连接到指定主机和端口。

    • Socket(InetAddress address, int port):使用InetAddress对象连接到指定主机和端口。

    • Socket(String host, int port, InetAddress localAddr, int localPort):绑定到本地地址和端口,同时连接到远程主机。

  2. 核心方法

    • InputStream getInputStream():获取输入流,用于读取服务器发送的数据。

    • OutputStream getOutputStream():获取输出流,用于向服务器发送数据。

    • void close():关闭套接字,释放资源。

    • void shutdownInput():关闭输入流。

    • void shutdownOutput():关闭输出流。

    • boolean isConnected():检查是否已连接。

    • boolean isClosed():检查是否已关闭。

使用流程

  1. 创建Socket对象并连接到服务器。

  2. 获取输入流和输出流进行数据交换。

  3. 处理数据并完成通信。

  4. 关闭Socket和相关资源。

2.3Tcp回显服务器

2.3.1TcpEchoServer

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;/*** TCP回显服务器实现类* 功能:接收客户端消息并原样返回(回显)*/
public class TcpEchoServer {private ServerSocket serverSocket = null;  // 服务器套接字对象// 构造方法:初始化服务器并绑定端口public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);  // 创建ServerSocket并绑定指定端口}/*** 启动服务器核心逻辑*/public void start() throws IOException {System.out.println("启动服务器");// 创建线程池(动态调整线程数量,适合短任务)ExecutorService executorService = Executors.newCachedThreadPool();// 持续监听客户端连接while (true) {// 阻塞等待客户端连接Socket clientSocket = serverSocket.accept();// 将客户端连接提交给线程池处理executorService.submit(() -> {try {processConnection(clientSocket);  // 处理单个客户端连接} catch (IOException e) {e.printStackTrace();}});}}/*** 处理单个客户端连接的完整生命周期* @param clientSocket 客户端套接字对象*/private void processConnection(Socket clientSocket) throws IOException {// 打印客户端连接信息System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());// 使用try-with-resources自动关闭流try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {// 使用Scanner和PrintWriter包装流对象Scanner scanner = new Scanner(inputStream);    // 输入流扫描器PrintWriter printWriter = new PrintWriter(outputStream);  // 输出流写入器// 持续处理客户端请求while (true) {// 1. 检测连接状态(若输入流中没有数据,说明客户端断开)if (!scanner.hasNext()) {System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}// 2. 读取请求并处理String request = scanner.next();    // 读取客户端请求(空格分隔)String response = process(request); // 处理请求生成响应// 3. 返回响应给客户端printWriter.println(response);  // 写入响应printWriter.flush();            // 强制刷新缓冲区}} catch (IOException e) {throw new RuntimeException(e);} finally {try {clientSocket.close();  // 确保关闭客户端套接字} catch (IOException e) {throw new RuntimeException(e);}}}/*** 处理请求的核心逻辑(示例为简单回显)* @param request 客户端请求内容* @return 返回与请求相同的字符串*/private String process(String request) {// 此处可添加业务逻辑(示例直接返回原内容)return request;}/*** 主方法:启动服务器实例*/public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);  // 创建服务器实例(端口9090)tcpEchoServer.start();  // 启动服务器}
}

核心思路讲解:


整体架构设计:

该代码实现了一个多线程TCP回显服务器,核心功能是接收客户端发送的文本消息,并将消息原样返回(回显)。其架构设计遵循经典客户端-服务器模型,核心特点包括:

  • 多线程处理:通过线程池动态分配线程,避免单线程阻塞导致的性能瓶颈。

  • 资源自动管理:利用try-with-resources确保流和套接字的自动释放。

  • 松耦合设计:将连接处理(processConnection)与业务逻辑(process)分离,便于扩展。


核心组件解析:

(1) ServerSocket 的职责

  • 端口监听:绑定到指定端口(如9090),通过accept()阻塞等待客户端连接。

  • 连接队列管理:默认使用操作系统提供的连接队列(通过backlog参数可调整队列长度)。

  • 生命周期控制:服务器运行时持续监听,直到进程终止(代码中未实现优雅关闭逻辑)。

(2) Socket 连接处理

  • 双向通信:每个客户端连接对应一个Socket对象,通过其输入流(InputStream)和输出流(OutputStream)实现数据交换。

  • 连接状态检测:通过scanner.hasNext()判断客户端是否断开(输入流关闭时返回false)。

(3) 线程池的作用

  • 动态资源分配Executors.newCachedThreadPool()创建的线程池会根据任务量自动扩展/收缩:

    • 空闲线程默认存活60秒后被回收。

    • 适合短生命周期任务(如HTTP请求)。

  • 避免线程爆炸:相比为每个连接直接创建new Thread(),线程池能有效控制系统资源占用。


3. 关键流程详解:

(1) 启动阶段

  1. 初始化ServerSocket并绑定端口。

  2. 创建线程池,进入无限循环等待连接。

(2) 连接处理阶段

  1. 接受连接accept()返回客户端Socket对象。

  2. 提交任务:将processConnection方法包装为任务提交到线程池。

  3. 处理请求

    • 通过Scanner逐词读取客户端请求(空格分隔)。

    • 调用process()生成响应(此处简单回显)。

    • 通过PrintWriter写回响应并强制刷新缓冲区。

(3) 连接终止

  1. 客户端主动断开scanner.hasNext()检测到输入流结束,跳出循环关闭连接。

  2. 异常处理:捕获IOException并关闭套接字,防止资源泄漏。

2.3.2TcpEchoClient

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;public class TcpEchoClient {// 定义一个Socket对象,用于与服务器建立连接private Socket socket = null;// 构造函数,用于初始化客户端并连接到指定的服务器IP和端口private TcpEchoClient(String serverIp, int serverPort) throws IOException {// 创建一个Socket对象,连接到指定的服务器IP和端口socket = new Socket(serverIp, serverPort);}// 启动客户端,开始与服务器进行通信public void start() {// 创建一个Scanner对象,用于从控制台读取用户输入Scanner scanner = new Scanner(System.in);try (// 获取Socket的输入流,用于接收服务器发送的数据InputStream inputStream = socket.getInputStream();// 获取Socket的输出流,用于向服务器发送数据OutputStream outputStream = socket.getOutputStream()) {// 创建一个Scanner对象,用于从输入流中读取服务器发送的数据Scanner scannerNet = new Scanner(inputStream);// 创建一个PrintWriter对象,用于向输出流中写入数据PrintWriter writer = new PrintWriter(outputStream);// 进入一个无限循环,持续与服务器进行通信while (true) {// 从控制台读取用户输入的数据String request = scanner.next();// 将用户输入的数据发送到服务器writer.println(request);// 刷新输出流,确保数据被发送writer.flush();// 从服务器读取响应数据String response = scannerNet.next();// 将服务器返回的响应数据打印到控制台System.out.println(response);}} catch (IOException e) {// 如果发生IO异常,抛出运行时异常throw new RuntimeException(e);}}// 主函数,程序的入口public static void main(String[] args) throws IOException {// 创建一个TcpEchoClient对象,连接到本地服务器的9090端口TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);// 启动客户端,开始与服务器通信client.start();}
}

 核心思路讲解:

  1. Socket连接

    • TcpEchoClient的构造函数中,通过new Socket(serverIp, serverPort)创建一个Socket对象,连接到指定的服务器IP和端口。这个Socket对象将用于后续的通信。

  2. 输入输出流

    • start方法中,通过socket.getInputStream()socket.getOutputStream()分别获取Socket的输入流和输出流。输入流用于接收服务器发送的数据,输出流用于向服务器发送数据。

  3. 用户输入与服务器通信

    • 使用Scanner从控制台读取用户输入的数据,并通过PrintWriter将数据发送到服务器。

    • 使用Scanner从输入流中读取服务器返回的响应数据,并将其打印到控制台。

  4. 循环通信

    • 通过一个无限循环while (true),客户端可以持续与服务器进行通信。每次循环中,客户端都会读取用户输入,发送到服务器,并等待服务器的响应。

  5. 异常处理

    • 如果在通信过程中发生IO异常,代码会捕获该异常并抛出运行时异常。

  6. 主函数

    • main函数中,创建一个TcpEchoClient对象,并连接到本地服务器的9090端口。然后调用start方法,启动客户端与服务器的通信。

3.小结

今天的分享到这里就结束了,喜欢的小伙伴不要忘记点点赞点个关注,你的鼓励就是对我最大的支持,加油!

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

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

相关文章

C++11新特性 8.final关键字、override关键字

一.final 用法: 1.修饰函数 只能修饰虚函数,阻止子类重写这个函数,final关键字写在函数名的后面。 即该虚函数不可以再被重写。 注意:一般不会在基类中使用,不然没有意义,因为只能修饰虚函数。 2.修饰…

Python实现网络通信:Socket模块与TCP/IP协议全解析

Langchain系列文章目录 01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南 02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖 03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南 04-玩转 LangChai…

click house扩容方案

《ClickHouse扩容方案解析》 当我们谈论数据库的时候,尤其是像ClickHouse这样专为处理大规模数据分析而设计的列式存储数据库时,扩容是一个不可避免的话题。随着数据量的增长和查询复杂度的提升,原有的硬件资源可能不足以支撑高效的查询响应…

【AGI】智谱开源2025:一场AI技术民主化的革命正在到来

智谱开源2025:一场AI技术民主化的革命正在到来 引言:开源,一场技术平权的革命一、CogView4:中文AI生成的里程碑1. 破解汉字生成的“AI魔咒”2. 开源协议与生态赋能 二、AutoGLM:人机交互的范式跃迁1. 自然语言驱动的跨…

java8中young gc的垃圾回收器选型,您了解嘛

在 Java 8 的 Young GC(新生代垃圾回收)场景中,对于 ToC的场景,即需要尽可能减少垃圾回收停顿时间以满足业务响应要求的场景,以下几种收集器各有特点,通常 Parnew和 G1 young表现较为出色,下面详…

【数学 矩阵快速幂】P7108 移花接木|普及+

本文涉及知识点 数学 移花接木 题目背景 遥远的圣地生长着一棵不为人知的灵树,或有万山之高。 但有一日,藏匿于根系的腐朽力量爆发,灵树已无法支撑往日屹立冲天的高度。 题目描述 灵树最初的形态可以看作一棵高度为 10 10 10 10 {10}…

2025-03-09 学习记录--C/C++-PTA 习题10-7 十进制转换二进制

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h>void dectobin( int n );int main() {int n;scanf(…

前端 | CORS 跨域问题解决

问题&#xff1a;Access to fetch at http://localhost:3000/save from origin http://localhost:5174 has been blocked by CORS policy: Response to preflight request doesnt pass access control check: No Access-Control-Allow-Origin header is present on the request…

fastapi房产销售系统

说明&#xff1a; 我希望用fastapi写几个接口&#xff0c;查询房产交易系统的几条数据&#xff0c;然后在postman里面测试 查询客户所有预约记录&#xff08;含房源信息&#xff09;需要对应销售经理查询客户所有订单&#xff08;含房源信息&#xff09;统计销售经理名下所有房…

导轨式ARM工业控制器:组态软件平台的“神经中枢”

工业自动化领域&#xff0c;组态软件平台扮演着至关重要的角色。它不仅是工业控制系统的“大脑”&#xff0c;更是实现智能化、高效化生产的关键工具。而作为组态软件平台的硬件支撑&#xff0c;导轨式ARM工控机&#xff08;以下简称“工控机”&#xff09;凭借其紧凑的设计、强…

每日一题——矩阵置零问题的原地算法

矩阵置零问题的原地算法 问题描述示例约束条件进阶要求 问题分析难点分析解题思路 代码实现代码说明 测试用例测试用例 1测试用例 2测试用例 3 总结 问题描述 给定一个 m x n 的矩阵&#xff0c;如果矩阵中的某个元素为 0&#xff0c;则需要将其所在的行和列的所有元素都置为 …

Springboot中的@Value注解:用法与潜在问题探索

在Spring Boot开发中&#xff0c;有个非常实用的注解&#xff0c;那就是Value&#xff01;它可以帮助我们轻松地从配置文件中读取属性值。想象一下&#xff0c;在应用程序中管理各种配置&#xff0c;比如数据库连接信息、服务URL或者API密钥等&#xff0c;使用Value是多么方便呀…

C++后端服务器开发技术栈有哪些?有哪些资源或开源库拿来用?

一、 C后台服务器开发是一个涉及多方面技术选择的复杂领域&#xff0c;特别是在高性能、高并发的场景下。以下是C后台服务器开发的一种常见技术路线&#xff0c;涵盖了从基础到高级的技术栈。 1. 基础技术栈 C标准库 C11/C14/C17/C20&#xff1a;使用现代C特性&#xff0c;如…

25年携程校招社招求职能力北森测评材料计算部分:备考要点与误区解析

在求职过程中&#xff0c;能力测评是筛选候选人的重要环节之一。对于携程这样的知名企业&#xff0c;其能力测评中的材料计算部分尤为关键。许多求职者在备考时容易陷入误区&#xff0c;导致在考试中表现不佳。本文将深入解析材料计算部分的实际考察方向&#xff0c;并提供针对…

golang进阶知识专项-理解值传递

在 Go 语言中&#xff0c;所有函数的参数传递都是值传递&#xff08;Pass by Value&#xff09;。当你将一个变量作为参数传递给函数时&#xff0c;实际上传递的是该变量的副本&#xff0c;而不是变量本身。理解这一点对于避免常见的编程错误至关重要。根据不同的类型&#xff…

RuoYi框架添加自己的模块(学生管理系统CRUD)

RuoYi框架添加自己的模块&#xff08;学生管理系统&#xff09; 框架顺利运行 首先肯定要顺利运行框架了&#xff0c;这个我不多说了 设计数据库表 在ry数据库中添加表tb_student 表字段如图所示 如图所示 注意id字段是自增的 注释部分是后面成功后前端要展示的部分 导入…

中级网络工程师面试题参考示例(1)

一、基础理论 1. OSI七层模型与TCP/IP四层模型的区别是什么&#xff1f;请举例说明第三层&#xff08;网络层&#xff09;和第四层&#xff08;传输层&#xff09;的核心协议。 参考答案&#xff1a; OSI七层模型分为物理层、数据链路层、网络层、传输层、会话层、表示层、应用…

RHCE9.0版本笔记5:防火墙的本地/远程登录方式

一、防火墙登录方式全景图 华为防火墙支持多种管理访问方式&#xff0c;根据安全等级和场景需求可分为&#xff1a; graph LR A[管理方式] --> B[本地登录] A --> C[远程登录] B --> B1(Console) B --> B2(Web) C --> C1(SSH) C --> C2(Telnet) C --> C…

2025最新群智能优化算法:山羊优化算法(Goat Optimization Algorithm, GOA)求解23个经典函数测试集,MATLAB

一、山羊优化算法 山羊优化算法&#xff08;Goat Optimization Algorithm, GOA&#xff09;是2025年提出的一种新型生物启发式元启发式算法&#xff0c;灵感来源于山羊在恶劣和资源有限环境中的适应性行为。该算法旨在通过模拟山羊的觅食策略、移动模式和躲避寄生虫的能力&…

博弈论算法

一、减法游戏 初始有一个数 n。 两个玩家轮流操作&#xff0c;每次可以减去 1 到 9 之间的任意整数。 将数减到 0 的玩家获胜。 可以发现规律&#xff1a; 减法游戏只需要判断当前数取模是否为0&#xff0c;即可快速判断胜负。 例题&#xff1a; Leetcode 292. Nim 游戏 …