Java网络编程(二)Socket 套接字(TCP和UDP),以及TCP的回显
Socket 套接字(TCP和UDP),以及TCP的回显
- Socket 套接字
- 数据报套接字UDP
- TCP流套接字编程
- TCP的长短连接
- 实现一个简单回显服务器
Socket 套接字
我们软件工作者,着重编写的是应用层的代码,但是发送这个数据,我们就需要将应用层传输到传输层,也就意味着我们需要调用应用层的API,统称为 Socket API。
套接字的分类:
- 流套接字:使用传输层TCP协议
特点:- 有连接:使用 TCP 通信的双方,需要时刻保存对方的相关消息
- 可靠传输:尽可能的将数据传输过去,如果没有传输过去,自己也知道没有传输,然后通过设定可以重新传输
- 面向字节流:以字节为传输的基本单位,读写方式更为灵活
- 全双工:一条路径,双向通信
- 数据报套接字:使用传输层UDP协议
特点:- 有连接:使用 UDP 通信的双方,不需要时刻保存对方的相关消息
- 不可靠传输:只关注是否传输了数据,至于是否传输成功,并不专注
- 面向数据报:以一个UDP数据报为基本单位
- 全双工:一条路径,双向通信
- 原始套接字:原始套接字用于自定义传输层协议,用于读写内核没有处理的IP协议数据。
所有特点自己定义
什么是全双工和半双工?
全双工:一条路径,双向通信
半双工:一条路径,单向通信
网络传输数据的基本单位:报(Datagram)、包(Packet)、段(Segment)、帧(Frame)
Socket 对象,相当于系统中Socket文件,这个文件并非对应到硬盘上的某个数据存储区域,而是对应到网卡这个硬件设备
- 往这个Socket·对象中写数据,相当于通过网卡发送消息
- 从这个Socket·对象中读数据,相当于通过网卡接收消息
这个图不是我画,摘抄了网上现有的)
数据报套接字UDP
java中使用UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使用DatagramPacket 作为发送或接收的UDP数据报 。DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。
DatagramSocket API:
- DatagramSocket 构造方法
- DatagramSocket 方法:
DatagramPacket API:(DatagramPacket是UDP Socket发送和接收的数据报)
-
DatagramPacket 构造方法:
-
DatagramPacket 方法:
构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创
建
InetSocketAddress API:
- InetSocketAddress ( SocketAddress 的子类 )构造方法:
UDP服务器:
注意:
- 服务器的端口必须不变,客户端这边则不需要手动指定,系统自动分配
- socket是文件,也需要关闭
public class UdpServer { //服务器socket要绑定固定的端口 private static final int PORT = 8888; public static void main(String[] args) throws IOException { // 1.创建服务端DatagramSocket,指定端口,可以发送及接收UDP数据报 DatagramSocket socket = new DatagramSocket(PORT); //不停的接收客户端udp数据报 while (true){ // 2.创建数据报,用于接收客户端发送的数据 byte[] bytes = new byte[1024];//1m=1024kb, 1kb=1024byte, UDP最多64k(包含UDP首部8byte) DatagramPacket packet = new DatagramPacket(bytes, bytes.length); System.out.println("---------------------------------------------------"); System.out.println("等待接收UDP数据报..."); // 3.等待接收客户端发送的UDP数据报,该方法在接收到数据报之前会一直阻塞,接收到数据报以后,DatagramPacket对象,包含数据(bytes)和客户端ip、端口号 socket.receive(packet); System.out.printf("客户端IP:%s%n", packet.getAddress().getHostAddress()); System.out.printf("客户端端口号:%s%n", packet.getPort()); System.out.printf("客户端发送的原生数据为:%s%n", Arrays.toString(packet.getData())); System.out.printf("客户端发送的文本数据为:%s%n", new String(packet.getData())); } }
}
一旦服务器一起动,调用start方法,就会立即执行到,receive这里,但是如果此时还有没有客户端发来的数据,receive就会阻塞等待,一直持续到有数据发过来。
细节:网卡这里收到数据,就会进行分用,解析UDP这一层 看到端口号,然后将数据放入接收缓冲区,然后将数据到了参数中的DatagramSocket 对象中
UDP客户端:
public class UdpClient { // 服务端socket地址,包含域名或IP,及端口号 private static final SocketAddress ADDRESS = new InetSocketAddress("localhost", 8888); public static void main(String[] args) throws IOException { // 4.创建客户端DatagramSocket,开启随机端口就行,可以发送及接收UDP数据报 DatagramSocket socket = new DatagramSocket(); // 5-1.准备要发送的数据 byte[] bytes = "hello world!".getBytes(); // 5-2.组装要发送的UDP数据报,包含数据,及发送的服务端信息(服务器IP+端口号) DatagramPacket packet = new DatagramPacket(bytes, bytes.length, ADDRESS); // 6.发送UDP数据报 socket.send(packet); }
}
TCP流套接字编程
ServerSocket API:
ServerSocket 是创建TCP服务端Socket的API。
- ServerSocket 构造方法:
- ServerSocket 方法:
accept:意思就是接受,本质上是三次握手后面的文章会说。
Socket API:
Socket 是客户端 Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket。
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。
- Socket 构造方法:
- host 表示服务器的 IP 地址
- port 表示服务器的端口
- Socket 方法:
- 从InputStream这里读数据,就相当于从网卡接收
- 往OutputStream这里写数据,就相当于从网卡发送
TCP的长短连接
TCP发送数据时,需要先建立连接,而什么时候关闭连接就决定是短连接还是长连接。
短连接:每次接收数据并返回响应后,都关闭连接。也就是说,短连接只能一次收发。
- 连接客户端和服务器
- 对于客户端来说。要发送一个请求,然后接收一个响应
- 对于服务器来说。会收到一个请求,然后返回一个响应
- 然后关闭连接
长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以
多次收发数据
- 连接客户端和服务器
- 可以客户端一直发送请求,并获取服务器的响应
- 可以服务器一直发送请求,并获取客户端的响应
- 没有一方主动停止,不关闭
长连接和短连接的区别:
- 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
- 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
- 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于客户端与服务端通信频繁的场景,如聊天室,实时游戏等。
实现一个简单回显服务器
public class TcpEchoServer {//serverSocket 就是外场拉客的小哥(类似集合),只有一个//clientSocket 内场服务的人(),会给每个客服分配一个private ServerSocket serverSocket=null;//1public TcpEchoServer(int port) throws IOException {serverSocket=new ServerSocket(port);}public void start() throws IOException {ExecutorService executorService= Executors.newCachedThreadPool();System.out.println("服务器启动");while (true){Socket clientSocket=serverSocket.accept();//如果直接调用,该方法会影响这个循环的二次执行.导致accept不及时了//创建新的线程,用新的线程来调用processConnetion//每次来一个新的客户端都搞一个新的线程即可
/* Thread t=new Thread(()->{try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}});t.start();*///创建一个线程池,从池子中拿取线程executorService.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {throw new RuntimeException(e);}}});}}//通过这个方法处理一个链接//读取请求//根据请求计算响应//把响应返回给客户端private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d] 客户端上线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());try(InputStream inputStream=clientSocket.getInputStream();OutputStream outputStream=clientSocket.getOutputStream()) {//没有这两个也可以,但是代价就是得一个字节一个字节的处理,找到那个是结束符//将字节流包装成了字符流Scanner scanner=new Scanner(inputStream);PrintWriter printWriter=new PrintWriter(outputStream);while (true){//3//读取请求if (!scanner.hasNext()){//读取的流到了结尾了System.out.printf("[%s:%d] 客户端下线",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}//直接使用scanner读取一段字符串String request=scanner.next();//往后读,一直读到空白符,空格,换行,翻页符....都算空白符//5//根据请求计算响应String response=process(request);//把响应返回给客户端printWriter.println(response);//刷新缓冲区printWriter.flush();System.out.printf("[%s:%d] req:%s; resp:%s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort(),request,response);}} catch (IOException e) {throw new RuntimeException(e);}finally {clientSocket.close();}}private String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);tcpEchoServer.start();}}
补充一点:
硬件的读写速度:
- 内存 > 硬盘 > 网卡
读写硬盘和网卡口可以视为 IO 操作。
- printWriter.println(response);----》写网卡
因为网卡读写速度慢,如果平凡的写入,读出对于效率太慢了。为了提高IO操作的效率,此时就需要引入一个内存构成的缓冲区。等缓冲区达到一定数量,就统一写入网卡中。
缓存(cache)!=缓冲区(buffer)
- 缓存:只能读
- 缓冲区:可以读也可以写。
相关文章:

Java网络编程(二)Socket 套接字(TCP和UDP),以及TCP的回显
Socket 套接字(TCP和UDP),以及TCP的回显 Socket 套接字数据报套接字UDPTCP流套接字编程TCP的长短连接实现一个简单回显服务器 Socket 套接字 我们软件工作者,着重编写的是应用层的代码,但是发送这个数据,我…...

C++ - 多态语法 - 虚函数使用介绍
多态简单介绍 多态就是多种形态,是不同的对象去完成同一个动作所产生的结果可能有多种。这种多种的形态我们称之为多态。 比如:我们在买票的时候的时候,可能有成人全价,儿童半价,军人免票等等。对于成人,儿…...
php获取客户端ip地址及ip所在国家、省份、城市、县区
摘要 获取客户端ip地址,然后使用这个ip地址获取所在的国家、省份、城市,可以在网站中实现IP属地,发布地等功能。 本文的获取IP地址信息均采自网络上免费的IP查询网站,通过其API或者网页HTML解析出的ip地址信息。 代码 <?p…...
Error: Port Library failed to initialize: -86
最近遇到一个很奇怪的错误,这里记录一下,以备以后再次遇到 Error: Port Library failed to initialize: -86 Error: Could not create the Java Virtual Machine. Error: A fatal exception has occurred. Program will exit.背景是,就是一普…...
SOME/IP 支持两种序列化方式:TLV 和 TV
SOME/IP 是一种基于 IP 的可扩展面向服务的中间件协议,它可以在车载以太网中实现 ECU 之间的高效通信和互操作性。 SOME/IP 的序列化方式是指将数据结构或对象按照一定的规则转换成字节序列的过程,以便在网络中传输和解析。 SOME/IP 支持两种序列化方式:TLV 和 TV。 TLV是…...

Unity之3D物理导航系统
一 介绍 Unity自带寻路(导航)系统是unity官方自带的一种寻路系统。我们可以通过它来制作简单的寻路,比如可以制作点击某个位置,让角色自动的绕开障碍走到目标点的效果,比如可以制作敌人AI,让它可以通过NavMesh绕开障碍追击我方单…...
9.4黄金行情是否反转?今日多空如何布局?
近期有哪些消息面影响黄金走势?今日黄金多空该如何研判? 黄金消息面解析:周一(9月4日)亚市盘中,现货黄金震荡走高,延续上周涨势,一度刷新日内高点至1946.16美元/盎司。周三,ISM将发布服务业P…...

Win10下使用vim9
作为一个经常与文字打交道的Writer,你在学会Vim的基本操作之后,就一定会爱上Vim的。 以下是Windows10_64位(专业版)环境中安装、使用Vim9的全过程,分享一下: 一、下载、安装Vim9 去Vim官网去下载最新的Vi…...

Flink+Flink CDC版本升级的依赖问题总结
之前使用Flink1.13Flink CDC2.0同步MySQL数据,想测试一下最新的几个版本。但是各种依赖冲突的报错,经过一段时间的调试,终于解决,现在总结一下。 1、flink1.15前后jar包名称不一样 flink-streaming-java、flink-clients、flink-…...

Matlab论文插图绘制模板第112期—带阴影标记的图
之前的文章中,分享了Matlab带线标记的图: 进一步,本期分享的是带阴影标记的图。 先来看一下成品效果: 特别提示:本期内容『数据代码』已上传资源群中,加群的朋友请自行下载。有需要的朋友可以关注同名公号…...

专业运动耳机哪个牌子好、专业运动耳机推荐
在进行运动时,倾听音乐实际上是一种放松大脑、放松身体的小技巧。毕竟运动是一个耗费体力最多的活动,整个过程也往往令人感到乏味。如果有音乐作伴,你的运动就会变得更加轻松愉快。那么,哪种耳机适合运动呢?我正好对此…...

【SQL应知应会】索引 • Oracle版:B-树索引;位图索引;函数索引;单列与复合索引;分区索引
欢迎来到爱书不爱输的程序猿的博客, 本博客致力于知识分享,与更多的人进行学习交流 本文免费学习,自发文起3天后,会收录于SQL应知应会专栏,本专栏主要用于记录对于数据库的一些学习,有基础也有进阶,有MySQL也有Oracle 索引 • MySQL版 前言一、Oracle索引1.索引概述及分类…...

用ChatGPT做一个Chrome扩展 | 京东云技术团队
用ChatGPT做了个Chrome Extension 最近科技圈儿最火的话题莫过于ChatGPT了。 最近又发布了GPT-4,发布会上的Demo着实吸睛。 笔记本上手画个网页原型,直接生成网页。网友直呼:前端失业了! 但我觉着啊,真就外行看热闹…...

动态库的制作与使用及 动态库加载失败解决
加载动态库时有时会出现error while loading shared libraries:libcalc.so:可以通过lld命令查看动态库的依赖关系,发现libcalc.so时not found 原因 查找的优先级是DT_RPATH->LD_LIBRARY_PATH->/etc/ld.so.cache->/lib/,/usr/lib 找不到一个优…...

404 not found nginx(dist打包后,刷新和跳转都是404 not found nginx的问题) 解决方案(打包发布在服务器)
当我们执行了yarn run build之后,生成dist文件 我们将代码放入nginx-1.24.0下面的html中 然后我们就配置conf文件下的nginx.conf 配置方面不介绍了,主要问题是因为没有加这句话 问题分析 index index.htm index.html; index 就是根目录,也就…...

《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》全文翻译
《Chain-of-Thought Prompting Elicits Reasoning in Large Language Models》- Chain-of-Thought Prompting Elicits Reasoning in Large Language Models 论文信息摘要1. 介绍2. 思维链提示3. 算术推理3.1 实验设置3.2 结果3.3 消融研究3.4 思想链的稳健性 4. 常识推理5. 符号…...

MySQL——笔试测试题
解析: 要查询各科目的最大分数,可以使用如下的SQL语句: SELECT coursename, MAX(score) FROM t_stuscore GROUP BY coursename; 这条SQL语句使用了MAX()聚合函数来获取每个科目的最大分数,并使用GROUP BY子句按照科目进行分组…...

WangEditor在Vue前端的应用
1、在Vue项目中安装WangEditor 对于Vue2: npm install wangeditor/editor-for-vue --save 或者 yarn add wangeditor/editor-for-vue 对于Vue3: npm install wangeditor/editor-for-vuenext --save 或者 yarn add wangeditor/editor-for-vuenext 2、将Wa…...
初学python的感受
目录 初学感受学习计划学习目标 初学感受 刚学python的我惊讶的发现编程语言之间竟有如此多的相似之处,因此在学python的时候相对于学C语言时要轻松的多,虽然二者也有一些不同之处,但是我想只要对二者稍微区分的话应该不会搞混的,并且在学习的过程中也可以借鉴学C语言的方法去…...
SpringSecurity中注解讲解
文章目录 1 EnableGlobalMethodSecurity1.1 PreAuthorize1.1.1 开启注解1.1.2 使用注解原生方法1.1.3 使用注解自定义方法 1.2 PostAuthorize1.3 Secured 2 其他注解2.1 PostFilter2.2 PreFilter 3 权限表达式 1 EnableGlobalMethodSecurity EnableGlobalMethodSecurity 是 Sp…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...

Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error
在前端开发中,JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作(如 Promise、async/await 等),开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝(r…...