当前位置: 首页 > news >正文

【网络原理】使用Java基于TCP搭建简单客户端与服务器通信

目录

  • 🎄API介绍
    • 🌸ServerSocket API
    • 🌸Socket API
  • 🍀TCP中的长短连接
  • 🌳建立TCP回显客户端与服务器
    • 🌸TCP搭建服务器
    • 🌸TCP搭建客户端
  • ⭕总结

TCP服务器与客户端的搭建需要借助以下API

🎄API介绍

🌸ServerSocket API

ServerSocket 是创建TCP服务端Socket的API。

ServerSocket 构造方法

方法签名方法说明
ServerSocket(int port)创建一个服务端流套接字Socket,并绑定到指定端口

ServerSocket 方法:

方法签名方法说明
Socket accept()开始监听指定端口(创建时绑定的端口),有客户端连接后,返回一个服务端Socket对象,并基于该Socket建立与客户端的连接,否则阻塞等待
void close()关闭此套接字

🌸Socket API

Socket 是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。

不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。

Socket 构造方法:

方法签名方法说明
Socket(String host, intport)创建一个客户端流套接字Socket,并与对应IP的主机上,对应端口的进程建立连接

Socket 方法:

方法签名方法说明
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流

🍀TCP中的长短连接

博主在前面的博文里面说到,TCP是面向连接的通信方式,TCP发送数据时,需要先建立连接,而这个连接又分为长短连接:

  • 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。

  • 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据

对比以上长短连接,两者区别如下:

  • 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。

  • 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。

  • 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等

拓展:

  • 基于BIO(同步阻塞IO)的长连接会一直占用系统资源。对于并发要求很高的服务端系统来说,这样的消耗是不能承受的。

  • 由于每个连接都需要不停的阻塞等待接收数据,所以每个连接都会在一个线程中运行。一次阻塞等待对应着一次请求、响应,不停处理也就是长连接的特性:一直不关闭连接,不停的处理请求

  • 实际应用时,服务端一般是基于NIO(即同步非阻塞IO)来实现长连接,性能可以极大的提升。

🌳建立TCP回显客户端与服务器

🌸TCP搭建服务器

我们分为以下几步来实现:

  1. 创建TcpEchoServer类来表示我们的服务器,并创建ServerSocket对象,初始值为null
  2. 在TcpEchoServer的构造方法里进行ServerSocket对象的实例化
  3. 用一个start()方法表示启动程序
  4. 在该方法内我们首先要使用accept()进行连接,并用Socket对象进行接收
  5. 我们再用一个processConnection(Socket clientSocket)方法处理我们的连接

由于我们的TCP传输是以流的形式传播的,所以我们这里用到了读写数据流的方法来进行书写,不会这一部分的小伙伴,可以去看看博主所写【Java EE】文件内容的读写⸺数据流进行查看学习

接下来我们书写这个processConnection(Socket clientSocket)方法

  1. 读取请求,构造输入流的Scanner,并判断后面如果没有数据就关闭连接
  2. 然后我们将读取的数据交给我们的 response()构造响应
  3. 响应后的数据写入该套接字的输出流中,最后flush(),进行刷新,确保写入

为了释放资源,我们每一次交互完毕都需要对我们的套接字进行关闭,这里我们使用fially来进行处理

代码如下:

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;public class TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("启动服务器");Socket socket = serverSocket.accept();processConnection(socket);}// 使用这个方法来处理一个连接.// 这一个连接对应到一个客户端. 但是这里可能会涉及到多次交互.private void processConnection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress().toString(), clientSocket.getPort());// 基于上述 socket 对象和客户端进行通信try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {// 由于要处理多个请求和响应, 也是使用循环来进行.while (true) {// 1. 读取请求Scanner scanner = new Scanner(inputStream);if (!scanner.hasNext()) {// 没有下个数据, 说明读完了. (客户端关闭了连接)System.out.printf("[%s:%d] 客户端下线! \n", clientSocket.getInetAddress().toString(), clientSocket.getPort());break;}// 注意!! 此处使用 next 是一直读取到换行符/空格/其他空白符结束, 但是最终返回结果里不包含上述 空白符 .String request = scanner.next();// 2. 根据请求构造响应String response = process(request);// 3. 返回响应结果.//    OutputStream 没有 write String 这样的功能. 可以把 String 里的字节数组拿出来, 进行写入;//    也可以用字符流来转换一下.PrintWriter printWriter = new PrintWriter(outputStream);// 此处使用 println 来写入. 让结果中带有一个 \n 换行. 方便对端来接收解析.printWriter.println(response);// flush 用来刷新缓冲区, 保证当前写入的数据, 确实是发送出去了.printWriter.flush();System.out.printf("[%s:%d] req: %s; resp: %s \n", clientSocket.getInetAddress().toString(), clientSocket.getPort(),request, response);}} catch (IOException e) {e.printStackTrace();} finally {// 更合适的做法, 是把 close 放到 finally 里面, 保证一定能够执行到!!try {clientSocket.close();clientSocket.close();} catch (IOException e) {e.printStackTrace();}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}

🌸TCP搭建客户端

搭建客户端我们也可以分为以下几步:

  1. 创建TcpEchoClient类表示我们的客户端,创建Soket对象用于与客户端通信·
  2. 再TcpEchoClient构造方法里进行实例化Socket的对象
  3. 创建start()方法用于我们的操作
  4. 读取键盘所要输入的数据
  5. 将所读的数据通过输出流进行写入
  6. 读取响应的输入流,进行打印
  7. main函数中进行启动
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 {private Socket socket = null;public TcpEchoClient(String serverIp, int serverPort) throws IOException {// Socket 构造方法, 能够识别 点分十进制格式的 IP 地址. 比 DatagramPacket 更方便.// new 这个对象的同时, 就会进行 TCP 连接操作.socket = new Socket(serverIp, serverPort);}public void start() {System.out.println("客户端启动!");Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {while (true) {// 1. 先从键盘上读取用户输入的内容System.out.print("> ");String request = scanner.next();if (request.equals("exit")) {System.out.println("goodbye");break;}// 2. 把读到的内容构造成请求, 发送给服务器.PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(request);// 此处加上 flush 保证数据确实发送出去了.printWriter.flush();// 3. 读取服务器的响应Scanner respScanner = new Scanner(inputStream);String response = respScanner.next();// 4. 把响应内容显示到界面上System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

⭕总结

关于《【网络原理】使用Java基于TCP实现简单客户端与服务器通信》就讲解到这儿,感谢大家的支持,欢迎各位留言交流以及批评指正,如果文章对您有帮助或者觉得作者写的还不错可以点一下关注,点赞,收藏支持一下!

相关文章:

【网络原理】使用Java基于TCP搭建简单客户端与服务器通信

目录 🎄API介绍🌸ServerSocket API🌸Socket API 🍀TCP中的长短连接🌳建立TCP回显客户端与服务器🌸TCP搭建服务器🌸TCP搭建客户端 ⭕总结 TCP服务器与客户端的搭建需要借助以下API 🎄…...

Hadoop生态系统主要是什么?

Hadoop生态系统主要由以下几部分组成: Hadoop HDFS:这是Hadoop的核心组件之一,是一个用于存储大数据的分布式文件系统。它可以在廉价的硬件上提供高度的容错性,通过数据复制和故障切换实现数据的高可用性。 MapReduce&#xff1a…...

GlusterFS分布式文件系统

前言 存储可分为文件存储和对象存储,常见的文件存储相关技术有:nfs、lvm、raid;常见的对象存储相关技术有:gfs、ceph、fdfs、nas、oss、s3、switch。GlusterFS 归类为文件存储系统,它提供了一种强大的方式来管理和存储…...

spark本地模拟多个task时如何启动多个Excutor

1、首先在9090端口下启动Excutor,作为第一个Excutor 2、然后修改9090端口为:9091,如下图点击Edit Configration 3、然后按下图操作 , 4、修改一下名字 5、点击apply,🆗 6、检查下面圈1是否是刚刚我们新建的MyExcutor(2…...

RocketMQ笔记(八)SpringBoot整合RocketMQ广播消费消息

目录 一、简介1.1、消费模式 二、消费者2.1、maven依赖2.2、application配置2.3、消费监听 三、生产者3.1、发送消息3.2、运行结果 四、其他 一、简介 在之前的文章中,我们讲过了,同步发送单条消息,异步发送单条消息,发送单向消息…...

Appium如何自动判断浏览器驱动

问题:有的测试机chrome是这个版本,有的是另一个版本,怎么能让自动判断去跑呢?? 解决办法:使用appium的chromedriverExecutableDir和chromedriverChromeMappingFile 切忌使用chromedriverExecutableDir和c…...

MVCC-多版本并发控制

MVCC(多版本并发控制)简介 在数据库系统中,并发控制是一个非常重要的话题。为了提高系统的并发性能和吞吐量,现代数据库系统通常使用多种技术来实现对数据的安全访问,其中一种重要的技术就是多版本并发控制&#xff0…...

c++找最高成绩

根据给定的程序&#xff0c;写成相关的成员函数&#xff0c;完成指定功能。 函数接口定义&#xff1a; 定义max函数&#xff0c;实现输出最高成绩对应的学号以及最高成绩值。 裁判测试程序样例&#xff1a; #include <iostream> using namespace std; class Student{…...

前端saas化部署

在项目中难免会遇到一些特殊的需求&#xff0c;例如同一套代码需要同时部署上两个不同的域名A和B。A和B的不同之处仅在于&#xff0c;例如一些背景图片&#xff0c;logo&#xff0c;展示模块的不同&#xff0c;其他业务逻辑是和展示模块是完全一样的。此时我们当然可以考虑单独…...

[Java基础揉碎]Math类

目录 基本介绍 方法一览(均为静态方法) 1) abs 绝对值 2) pow 求幂 3) ceil 向上取整 4) floor 向下取整 5) round 四舍五入 6) sqrt 求开方 7) random求随机数 8) max 求两个数的最大值 9) min 求两个数的最小值 基本介绍 Math类包含用于执行基本数学运算的方法&…...

MyBatis输入映射

1 parameterType parameterType&#xff1a;接口中方法参数的类型&#xff0c;类型必须是完全限定名或别名&#xff08;稍后讲别名&#xff09;。该属性非必须&#xff0c;因为Mybatis框架能自行判断具体传入语句的参数&#xff0c;默认值为未设置&#xff08;unset)。<sel…...

金三银四,程序员求职季

随着春天的脚步渐近&#xff0c;对于许多程序员来说&#xff0c;一年中最繁忙、最重要的面试季节也随之而来。金三银四&#xff0c;即三月和四月&#xff0c;被广大程序员视为求职的黄金时期。在这两个月里&#xff0c;各大公司纷纷开放招聘&#xff0c;求职者们则通过一轮又一…...

[react优化] 避免组件或数据多次渲染/计算

代码如下 点击视图x➕1,导致视图更新, 视图更细导致a也重新大量计算!!这很浪费时间 function App() {const [x, setX] useState(3)const y x 2console.log(重新渲染, x, y);console.time(timer)let a 0for (let index 0; index < 1000000000; index) {a}console.timeE…...

「意」起出发 丨意大利OXO城市展厅盛大启幕,成都设计圈共襄盛举

4月8日&#xff0c;主题为“「意」起出发「智」见OXO”的意大利OXO城市展厅发布会在成都大悦城OXO成都城市展厅隆重举办。 大会现场&#xff0c;成都装饰协会领导&#xff0c;喜尔康董事长吴锡山&#xff0c;天合智能副董事长罗洁&#xff0c;意大利OXO卫浴市场部总监兰彬&…...

你不知道的JavaScript---深入理解 JavaScript 作用域

你好&#xff0c;我是小白Coding日志&#xff0c;一个热爱技术的程序员。在这里&#xff0c;我分享自己在编程和技术世界中的学习心得和体会。希望我的文章能够给你带来一些灵感和帮助。欢迎来到我的博客&#xff0c;一起在技术的世界里探索前行吧&#xff01; 1. 什么是作用域…...

FPGA(Verilog)实现按键消抖

实现按键消抖功能&#xff1a; 1.滤除按键按下时的噪声和松开时的噪声信号。 2.获取已消抖的按键按下的标志信号。 3.实现已消抖的按键的连续功能。 Verilog实现 模块端口 key_filter(input wire clk ,input wire rst_n ,input wire key_in , //按下按键时为0output …...

第十二届蓝桥杯大赛软件赛省赛C/C++大学B组

第十二届蓝桥杯大赛软件赛省赛C/C 大学 B 组 文章目录 第十二届蓝桥杯大赛软件赛省赛C/C 大学 B 组1、空间2、卡片3、直线4、货物摆放5、路径6、时间显示7、砝码称重8、杨辉三角形9、双向排序10、括号序列 1、空间 1MB 1024KB 1KB 1024byte 1byte8bit // cout<<"2…...

面了钉钉搜广增算法岗(暑期实习),秒挂。。。。

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…...

前端实现流文件下载的完整指南

在现代Web开发中&#xff0c;经常会遇到需要从服务器下载文件的情况。有时候这些文件是事先存储好的&#xff0c;可以通过简单的URL链接直接下载&#xff1b;但有时候&#xff0c;我们需要从数据流中动态生成文件并将其提供给用户。本篇博客将介绍如何在前端实现流文件下载的完…...

Kotlin:常用标准库函数(let、run、with、apply、also)

一、let 扩展函数 Kotlin标准库函数let可用于范围确定和空检查。当调用对象时&#xff0c;let执行给定的代码块并返回其最后一个表达式的结果。对象可以通过引用(默认情况下)或自定义名称在块中访问。 let扩展函数源码 let.kt文件代码 fun main() {println("isEmpty $is…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

如何在看板中有效管理突发紧急任务

在看板中有效管理突发紧急任务需要&#xff1a;设立专门的紧急任务通道、重新调整任务优先级、保持适度的WIP&#xff08;Work-in-Progress&#xff09;弹性、优化任务处理流程、提高团队应对突发情况的敏捷性。其中&#xff0c;设立专门的紧急任务通道尤为重要&#xff0c;这能…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...

力扣-35.搜索插入位置

题目描述 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...

Mobile ALOHA全身模仿学习

一、题目 Mobile ALOHA&#xff1a;通过低成本全身远程操作学习双手移动操作 传统模仿学习&#xff08;Imitation Learning&#xff09;缺点&#xff1a;聚焦与桌面操作&#xff0c;缺乏通用任务所需的移动性和灵活性 本论文优点&#xff1a;&#xff08;1&#xff09;在ALOHA…...

三分算法与DeepSeek辅助证明是单峰函数

前置 单峰函数有唯一的最大值&#xff0c;最大值左侧的数值严格单调递增&#xff0c;最大值右侧的数值严格单调递减。 单谷函数有唯一的最小值&#xff0c;最小值左侧的数值严格单调递减&#xff0c;最小值右侧的数值严格单调递增。 三分的本质 三分和二分一样都是通过不断缩…...

脑机新手指南(七):OpenBCI_GUI:从环境搭建到数据可视化(上)

一、OpenBCI_GUI 项目概述 &#xff08;一&#xff09;项目背景与目标 OpenBCI 是一个开源的脑电信号采集硬件平台&#xff0c;其配套的 OpenBCI_GUI 则是专为该硬件设计的图形化界面工具。对于研究人员、开发者和学生而言&#xff0c;首次接触 OpenBCI 设备时&#xff0c;往…...

深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏

一、引言 在深度学习中&#xff0c;我们训练出的神经网络往往非常庞大&#xff08;比如像 ResNet、YOLOv8、Vision Transformer&#xff09;&#xff0c;虽然精度很高&#xff0c;但“太重”了&#xff0c;运行起来很慢&#xff0c;占用内存大&#xff0c;不适合部署到手机、摄…...