【JavaEE初阶 - 网络原理】用 TCP Socket 写个网络计算器,你就懂协议了
个人主页User_芊芊君子欢迎大家点赞评论收藏⭐文章系列专栏JavaEE文章目录摘要代码示例约定好协议请求Request:响应Response:服务器:客户端:总结摘要只懂协议理论不动手等于没学。本文基于 Java TCPSocket从零实现一个网络版计算器约定运算符操作数的请求格式与运算结果的响应格式完成 Request/Response 的序列化与反序列化服务端用线程池支持多客户端并发客户端从控制台循环读取输入。文末附完整可运行代码与运行效果图。代码示例约定好协议明确传递的数据请求运算符±*/操作数响应运算结果组织传输数据格式自定义文本格式请求运算符操作数1操作数\n响应结果\n请求Request:package application; //表示一个请求 public class Request { private String operator; private double num1; private double num2; public Request(String operator, double num1, double num2) { this.operator operator; this.num1 num1; this.num2 num2; } //对象--字符串 public String covertToString(){ //String.format():类似printf但只是构造到String中没有打印 return String.format(%s,%f,%f\n,operator,num1,num2); } public static Request convertFromString(String request){ //1.获取参数 String[] split request.split(,);//切分 String opertor split[0]; double num1 Double.parseDouble(split[1]);//字符串转成double double num2 Double.parseDouble(split[2]); //2.创建对象 return new Request(opertor,num1,num2); } public String getOperator() { return operator; } public double getNum1() { return num1; } public double getNum2() { return num2; } }响应Response:package application; public class Response { private double result; Response(double result){ this.result result; } //转换成字符串 public String convertToString(){ return String.format(%f\n,result); } //把字符串转换成对象 public static Response convertFromString(String response){ double result Double.parseDouble(response); return new Response(result); } public double getResult() { return result; } }服务器:package application; 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; public class TcpCalcServer { private ServerSocket serverSocket null; public TcpCalcServer(int port)throws IOException{ serverSocket new ServerSocket(port); } public void start() throws IOException{ System.out.println(服务器启动); ExecutorService service Executors.newCachedThreadPool(); while (true){ Socket socket serverSocket.accept(); service.submit(()-{ try { processConnection(socket); } catch (IOException e) { throw new RuntimeException(e); } }); } } private void processConnection(Socket socket) throws IOException { System.out.printf([%s:%d 客户端上线],socket.getInetAddress().toString(),socket.getPort()); try (InputStream inputStream socket.getInputStream(); OutputStream outputStream socket.getOutputStream()){ Scanner scanner new Scanner(inputStream); PrintWriter printWriter new PrintWriter(outputStream); while (true){ //1.读取请求并解析 if (!scanner.hasNext()){ break; } String requestString scanner.next(); //反序列化 Request request Request.convertFromString(requestString); //2.根据请求计算响应 Response response process(request); //3.把响应写回客户端 String responseString response.convertToString(); //构造String时已经带了\n,直接print写入即可 printWriter.print(responseString); printWriter.flush(); } }catch (IOException e){ e.printStackTrace(); }finally { System.out.printf([%s:%d] 客户端下线!\n,socket.getInetAddress().toString(),socket.getPort()); socket.close(); } } private Response process(Request request) { //根据参数和运算符完成计算构造响应 if(request.getOperator().equals()){ return new Response(request.getNum1() request.getNum2()); }else if(request.getOperator().equals(-)){ return new Response(request.getNum1() - request.getNum2()); }else if(request.getOperator().equals(*)){ return new Response(request.getNum1() * request.getNum2()); }else if(request.getOperator().equals(/)){ return new Response(request.getNum1() / request.getNum2()); }else { throw new RuntimeException(不支持的运算符request.getOperator()); } } public static void main(String[] args) throws IOException { TcpCalcServer server new TcpCalcServer(9090); server.start(); } }客户端:package application; 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 TcpCalcClient { private Socket socket null; public TcpCalcClient(String serverIp,int serverPort) throws IOException { socket new Socket(serverIp,serverPort); } public void start(){ System.out.println(客户端运行中); try (InputStream inputStream socket.getInputStream(); OutputStream outputStream socket.getOutputStream()){ Scanner scannerConsole new Scanner(System.in); Scanner scannerNetwork new Scanner(inputStream); PrintWriter printWriter new PrintWriter(outputStream); while (true){ //1.从控制台读取用户输入内容 System.out.println(请输入要进行的运算 - * /); String operator scannerConsole.next(); System.out.println(请输入第一个数字); double num1 scannerConsole.nextDouble(); System.out.println(请输入第二个数字); double num2 scannerConsole.nextDouble(); //2.构造请求并发送 Request request new Request(operator,num1,num2); String requsetString request.covertToString(); printWriter.println(requsetString); printWriter.flush(); //3.读取服务器响应结果 if(!scannerNetwork.hasNext()){ break; } String responseString scannerNetwork.next(); Response response Response.convertFromString(responseString); //4.打印响应结果 System.out.println(response.getResult()); } }catch (IOException e){ e.printStackTrace(); } } public static void main(String[] args) throws IOException { TcpCalcClient client new TcpCalcClient(127.0.0.1,9090); client.start(); } }总结一个标准的网络程序 协议设计 序列化/反序列化 Socket 收发循环。服务端固定 accept → 读请求 → 算响应 → 写回的流程客户端则是 构造请求 → 发送 → 等响应 → 展示。多客户端并发借助线程池即可实现。这套骨架就是以后写任何 TCP业务服务端的模板。

相关新闻

拓氪科技:游戏海外推广服务商该如何选型避坑?

拓氪科技:游戏海外推广服务商该如何选型避坑?

全球移动游戏产业格局持续迭代,粗放式规模化买量的出海增长模式已然落幕。伴随海外各区域市场监管政策收紧、用户审美与消费需求升级、流量获客成本逐年攀升,单一的广告投放、流量采购模式,已无法支撑游戏产品的长效运营与价值增长。当下游戏…

2026/10/18 23:17:24 阅读更多 →
Git bug分支:线上故障修复的标准化工程实践

Git bug分支:线上故障修复的标准化工程实践

1. 项目概述:什么是“bug分支”?它真需要单独一讲吗?“Git中的bug分支”这个标题乍看有点奇怪——Git本身没有叫“bug分支”的内置概念,它不像main、develop那样是约定俗成的默认分支名。但恰恰是这种“不存在的名词”&#xff0c…

2026/10/18 23:17:24 阅读更多 →
基于Claude Code的knowledge-work-plugins插件化知识工作流设计与实操

基于Claude Code的knowledge-work-plugins插件化知识工作流设计与实操

1. 从“knowledge-work-plugins”说起:这个项目到底在解决什么问题第一次看到knowledge-work-plugins这个仓库名的时候,我脑子里冒出来的第一个念头是:这不就是把“知识工作”这件事拆成一个个可插拔的模块吗?后来翻了一圈 Claude…

2026/10/18 23:17:24 阅读更多 →

最新新闻

STATA外部命令资源库搭建:从adopath到源码管理的完整方案

STATA外部命令资源库搭建:从adopath到源码管理的完整方案

简介:面向使用STATA开展数据分析、统计与计量经济学研究的学者、研究人员及学生,这份外部命令资源库将分散在官方社区、个人主页等处的第三方扩展工具汇集一处,有效解决外部命令获取渠道不一、版本兼容难查等问题,降低建模前的环境…

2026/10/19 0:46:07 阅读更多 →
MATLAB实现电力系统潮流计算:从导纳矩阵到牛顿法收敛

MATLAB实现电力系统潮流计算:从导纳矩阵到牛顿法收敛

简介:本资源是一份面向电气工程专业本科生及电力系统初学者的MATLAB实践教学文档,聚焦电力系统核心基础——潮流计算的原理实现与编程落地。文档完整阐述牛顿-拉夫逊法(直角坐标形式)的数学建模逻辑、节点导纳矩阵构建方法、程序变…

2026/10/19 0:46:07 阅读更多 →
豆包读取电商客服聊天窗口:本机客户端走本地端口即可完成会话监听

豆包读取电商客服聊天窗口:本机客户端走本地端口即可完成会话监听

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:45:07 阅读更多 →
【Mac】vscode 配置 GD32E230CXXX 开发环境:从工具链到烧录的完整落地

【Mac】vscode 配置 GD32E230CXXX 开发环境:从工具链到烧录的完整落地

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:45:07 阅读更多 →
大模型本地部署体积对照:从0.5B到70B量化版本配置清单

大模型本地部署体积对照:从0.5B到70B量化版本配置清单

大模型本地部署这件事,聊起来都是算力、精度、上下文,但真正动手之前,第一道门槛其实是“机器能不能装下”。我最近把一套开源模型家族的多个版本在本地环境里来回实测了几轮,从最小的0.5B到70B量化版都跑过一遍,最后整…

2026/10/19 0:44:06 阅读更多 →
疲劳驾驶数据集图片与XML标注不匹配?清洗与YOLO转换指南

疲劳驾驶数据集图片与XML标注不匹配?清洗与YOLO转换指南

简介:这是一份面向深度学习和图像识别入门练习的疲劳驾驶监测数据集,包含人体疲劳状态下的真实照片,可重点将打哈欠时的张嘴状态与闭眼状态作为疲劳判定标准,适合有一定Python基础、正在学习目标检测或图像分类的初学者&#xff0…

2026/10/19 0:44:06 阅读更多 →

日新闻

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

频率跟踪型PWM电源设计:臭氧发生器谐振点漂移与软开关实现

简介:本资源为电源技术方向的学术研究文档,聚焦介质阻挡放电型臭氧发生器电源的频率跟踪型PWM控制策略,面向电力电子、高压电源及臭氧应用领域的科研人员与工程技术人员。针对负载呈容性、等效电容随外加电压升高而增大、谐振频率随之漂移的难…

2026/10/19 0:00:47 阅读更多 →
Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

Vibe Coding 遇上 TaoToken:把开发者思维圣殿的灵感流接入统一 Key 通道

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/19 0:00:47 阅读更多 →
HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

HundredCV-Chat话题建模实战教程:利用4,871个内置话题标签构建主题分析系统

【免费下载链接】HundredCV-Chat 项目地址: https://ai.gitcode.com/hf_mirrors/Jax-dan/HundredCV-Chat 点击查看 免费下载 HundredCV-Chat 是一个由 100 位青年简历数据开发而来的中文多轮对话数据集,共包含 24,750 组日常闲聊对话和 4,871 个话题标签…

2026/10/19 0:00:47 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 12:16:16 阅读更多 →