回显服务器的制作方法
文章目录
- 客户端和服务器
- TCP和UDP的特点
- UDP socket api的使用
- DatagramSocket
- DatagramPacket
- InetSocketAddress API
- 做一个简单的回显服务器
- UDP版本的回显服务器
- TCP版本的回显服务器
客户端和服务器
在网络中,主动发起通信的一方是客户端,被动接受的这一方叫做服务器。
- 客户端给服务器发送的数据是请求(request)
- 服务器给客户端返回的数据叫响应(response)
客户端和服务器的交互有多种模式
- 一问一答: 一个请求对应一个响应 。多在网站开发中用到
- 一问多答:一个请求对应多个相应。主要涉及“下载”的场景中
- 多问一答:多个请求队对应一个响应 。涉及到“上传”的场景中
- 多问多答:多个请求对应多个响应。用到“远程控制”和“远程桌面”中
TCP和UDP的特点
要想进行网络编程,需要使用系统的api,本质上是传输层提供的。传输层用到的协议主要是TCP和UDP。这两个协议的差别挺大,所提供的api也有一定的差别。先从本质上看看TCP和UDP的特点有哪些差别。
- TCP的特点是 有连接,可靠传输,面向字节流,全双工。
- UDP的特点是 无连接,不可靠传输,面向数据报,全双工。
有连接/无连接
举个例子,打电话,需要对方同意后才能打通电话,打电话的过程需要对方确认接听或者不接听,连接的特点就是双方都能认同,而无连接的规则向发微信,自己只管发送,不用在意对方是否同意接收。同理,计算机中的网络连接,就是通信双方,各自保存对方的信息,客户端就有一些数据结构,记录了谁是自己的服务器,服务器也有一些数据结构,记录了谁是自己的客户端。可靠传输/不可靠传输
网络上存在异常情况是非常多的,无论使用什么硬件技术都无法100%保证数据能从A发送到B。此处所说的可靠传输是指尽可能的完成数据传输,即不管数据有没有传输到,A都能清楚的知道。面向字节流/面向数据报
此处提到的字节流和文件中的字节流是一样的。网络中传输数据的基本单位就是字节。
面向数据报:每次传输的基本单位是一个数据报(有一系列字节构成的)特定的结构。全双工/半双工
一个信道可以双向通信,是全双工。只能单向通信是半双工。
UDP socket api的使用
socket api的中文意思是"网络编程套接字",操作系统中有一类文件叫socket文件,它抽象了网卡这样的硬件设备,而进行网络通信最核心的硬件设备就是网卡,通过网卡发送数据就是写socket文件,通过网卡接收数据就是读socket文件。在UDP中,核心的api有两个类,分别是DatagramSocket和DatagramPacket。下面看看这两个类的使用和注意事项。
DatagramSocket
这个类的作用主要是对soclet文件的读写,也就是借助网卡发送接收数据。接收发送接收数据的单位就是DatagramSocket.。
datagramSocket的构造方法
DatagramSocket的方法
DatagramPacket
UDP是面向数据报的,每次发送接收数据的基本单位,就是一个udp数据报,此时表示了一个UDP数据报
DatagramPacket的构造方法
DatagramPacket方法
InetSocketAddress API
做一个简单的回显服务器
UDP版本的回显服务器
回显服务器是客户端发送什么请求,服务器就返回什么响应。做这个服务器的目的是学习UDP socket
api的使用和理解网络编程中客户端和服务器的基本工作流程
服务器的基本逻辑
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoServer {private DatagramSocket socket = null;public UdpEchoServer(int port) throws SocketException {socket = new DatagramSocket(port);}// 服务器的启动逻辑.public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 每次循环, 就是处理一个请求-响应过程.// 1. 读取请求并解析DatagramPacket requestPacket = new DatagramPacket(new byte[4096], 4096);socket.receive(requestPacket);// 读到的字节数组, 转成 String 方便后续的逻辑处理.String request = new String(requestPacket.getData(), 0, requestPacket.getLength());// 2. 根据请求计算响应 (对于 回显服务器来说, 这一步啥都不用做)String response = process(request);// 3. 把响应返回到客户端.// 构造一个 DatagramPacket 作为响应对象DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), response.getBytes().length,requestPacket.getSocketAddress());socket.send(responsePacket);// 打印日志System.out.printf("[%s:%d] req: %s, resp: %s\n", requestPacket.getAddress().toString(),requestPacket.getPort(), request, response);}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {UdpEchoServer server = new UdpEchoServer(9090);server.start();}
}
首先创建DatagramSocket对象,接下来要使用socket对象来操作网卡。在创建对象的时候需要手动指定端口。在网络编程中,服务器一般需要手动指定端口,而客户端一般不需要。一个主机的一个端口只能被一个进程绑定,而一个进程可以绑定多个端口。
一个服务器一般都是24时运行的,直接使用while(true)可以不用退出。很多时候要重启一个服务器可以直接杀死进程。
此处 receive就从网卡能读取到一个 UDP 数据报就被放到了 requestPacket 对象中其中 UDP 数据报的载荷部分就被放到 requestPacket 内置的字节数组中了。另外报头部分,也会被 requestPacket 的其他属性保存。除了 UDP 报头之外,还有其他信息,比如收到的数据源 IP 是啥
通过 requestPacket 还能知道数据从哪里来的(源 ip 源端口)基于字节数组构造出 String字节数组里面保存的内容也不一定就是二进制数据,也可能是文本数据把文本数据交给 String 来保存,恰到好处~~
这里得到的长度是 requestPacket 中的有效长度,不一定是 40964096 是最大长度。一定是要使用有效长度来构造这里的 String使用最大长度就会生成一个非常长的 String 后半部分都是空白。通过process()方法构造响应,这是一个回显服务器,直接返回请求就可以。
通过requestPacket.getSocketAddress())获得对应客户端的ip和端口。是把请求的源ip和源端口作为响应的目的ip和目的端口。
总结
- 上述代码中,可以看到,UDP 是无连接的通信 UDP socket 自身不保存对端的IP 和端口.而是在每个数据报中有一个~.另外代码中也没有“建立连接”"接受连接”操作
- 不可靠传输,代码中体现不到的.
- 面向数据报,send和receive 都是以 DatagramPacket 为单位
- 全双工:一个 socket 既可以发送又可以接收
客户端的基本逻辑
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIp;private int serverPort;// 此处 ip 使用的字符串, 点分十进制风格. "192.168.2.100"public UdpEchoClient(String serverIp, int serverPort) throws SocketException {//请求的目的IP和目的端口this.serverIp = serverIp;this.serverPort = serverPort;socket = new DatagramSocket();}public void start() throws IOException {System.out.println("客户端启动");Scanner scanner = new Scanner(System.in);while (true) {// 要做四个事情System.out.print("-> "); // 表示提示用户接下来要输入内容.// 2. 从控制台读取要发送的请求数据.if (!scanner.hasNext()) {break;}String request = scanner.next();// 3. 构造请求并发送.DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIp), serverPort);socket.send(requestPacket);// 4. 读取服务器的响应.DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 5. 把响应显示到控制台上.String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.println(response);}}public static void main(String[] args) throws IOException {UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);client.start();}
}
三种DatagramSocket对象的构造方法
网络通信的基本流程
- 服务器启动.启动之后,立即进入 while 循,执行到 receive,进入阻塞,此时没有任何客户端发来请求呢。
- 客户端启动.启动之后,立即进入 while 循环,执行到 hasNext 这里进入阻塞,此时用户没有在控制台输入任何内容
- 用户在客户端的控制台中输入字符串,按下回车此时 hasNext 阻塞解除,next 会返回刚才输入的内容基于用户输入的内容,构造出一个 DatagramPacket 对象,并进行 send 。send执行完毕之后,继续执行到
reeive 操作,等待服务器返回的响应数据此时服务器还没返回响应呢,这里也会阻塞)- 服务器收到请求之后,就会从 receive 的阻塞中返回返回之后,就会根据读到的 DataqramPacket 对象,构造 String request, 通过 process 方法构造一个 String response再根据 response 构造一个
DatagramPacket表示响应对象, 再通过 send 来进行发送给客户端。执行这个过程中,客户端也始终在阻塞等待- 客户端从 receive 中返回执行.就能够得到服务器返回的响应并且打印倒控制台上于此同时,服务器进入下一次循环,也要进入到第二次的 receive 阳塞等待下个请求了
TCP版本的回显服务器
tcp中的长短连接
TCP发送数据时,需要先建立连接,什么时候关闭连接就决定是短连接还是长连接:
- 短连接:每次接收到数据并返回响应后,都关闭连接,即是短连接。也就是说,短连接只能一次收发数据。
- 长连接:不关闭连接,一直保持连接状态,双方不停的收发数据,即是长连接。也就是说,长连接可以多次收发数据。
对比以上长短连接,两者区别如下:
- 建立连接、关闭连接的耗时:短连接每次请求、响应都需要建立连接,关闭连接;而长连接只需要第一次建立连接,之后的请求、响应都可以直接传输。相对来说建立连接,关闭连接也是要耗时的,长连接效率更高。
- 主动发送请求不同:短连接一般是客户端主动向服务端发送请求;而长连接可以是客户端主动发送请求,也可以是服务端主动发。
- 两者的使用场景有不同:短连接适用于客户端请求频率不高的场景,如浏览网页等。长连接适用于 客户端与服务端通信频繁的场景,如聊天室,实时游戏等服务器的处理逻辑。
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 TcpEchoServer {private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");ExecutorService pool = Executors.newCachedThreadPool();while (true) {// 通过 accept 方法来 "接听电话", 然后才能进行通信Socket clientSocket = serverSocket.accept();
// Thread t = new Thread(() -> {
// processConnection(clientSocket);
// });
// t.start();pool.submit(new Runnable() {@Overridepublic void run() {processConnection(clientSocket);}});}}// 通过这个方法来处理一次连接. 连接建立的过程中就会涉及到多次的请求响应交互.private void processConnection(Socket clientSocket) {System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());// 循环的读取客户端的请求并返回响应.try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {while (true) {Scanner scanner = new Scanner(inputStream);if (!scanner.hasNext()) {// 读取完毕. 客户端断开连接, 就会产生读取完毕.System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());break;}// 1. 读取请求并解析. 这里注意隐藏的约定. next 读的时候要读到空白符才会结束.// 因此就要求客户端发来的请求必须带有空白符结尾. 比如 \n 或者空格.String request = scanner.next();// 2. 根据请求计算响应String response = process(request);// 3. 把响应返回给客户端// 通过这种方式可以写回, 但是这种方式不方便给返回的响应中添加 \n// outputStream.write(response.getBytes(), 0, response.getBytes().length);// 也可以给 outputStream 套上一层, 完成更方便的写入.PrintWriter printWriter = new PrintWriter(outputStream);printWriter.println(response);printWriter.flush();System.out.printf("[%s:%d] req: %s, resp: %s\n", clientSocket.getInetAddress(), clientSocket.getPort(),request, response);}} catch (IOException e) {throw new RuntimeException(e);} finally {try {clientSocket.close();} catch (IOException e) {throw new RuntimeException(e);}}}public String process(String request) {return request;}public static void main(String[] args) throws IOException {TcpEchoServer server = new TcpEchoServer(9090);server.start();}
}
- 在服务器代码中,ServerSocket是创建服务端Socket的api。Socket是客户端Socket,或服务端中接收到客户端建立连接(accept方法)的请求后,返回的服务端Socket.
不管是客户端还是服务端Socket,都是双方建立连接以后,保存的对端信息,及用来与对方收发数据的。- 当客户端发送请求的时候,内核就会发起建立连接的请求,服务器的内核会配合客户端的工作来建立连接,而内核的连接不是决定性的,还需要应用程序把这个连接接受,通过accept方法来接受连接。accept方法方法是会阻塞等待的,当没有客户端发起请求的时候此时就会阻塞。
- 上面的操作也表现出Tcp是有连接的。
- Tcp是面向字节流的。这里的字节流和文件中的字节流完全一致。使用和文件操作一样的类和方法来针对Tcp Socket的读和写。
- InputStream是往网卡上读数据,OutputStream是往网卡上写数据。
客户端的处理逻辑
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 {// 此处可以把这里的 ip 和 port 直接传给 socket 对象.// 由于 tcp 是有连接的. 因此 socket 里面就会保存好这俩信息.// 因此此处 TcpEchoClient 类就不必保存.socket = new Socket(serverIp, serverPort);}public void start() {System.out.println("客户端启动!");try (InputStream inputStream = socket.getInputStream()) {try (OutputStream outputStream = socket.getOutputStream()) {Scanner scannerConsole = new Scanner(System.in);Scanner scannerNetwork = new Scanner(inputStream);PrintWriter writer = new PrintWriter(outputStream);while (true) {// 这里的流程和 UDP 的客户端类似.// 1. 从控制台读取输入的字符串System.out.print("-> ");if (!scannerConsole.hasNext()) {break;}String request = scannerConsole.next();// 2. 把请求发给服务器. 这里需要使用 println 来发送. 为了让发送的请求末尾带有 \n// 这里是和服务器的 scanner.next 呼应的.writer.println(request);// 通过这个 flush 主动刷新缓冲区, 确保数据真的发出去了.writer.flush();// 3. 从服务器读取响应. 这里也是和服务器返回响应的逻辑对应.String response = scannerNetwork.next();// 4. 把响应显示出来System.out.println(response);}}} catch (IOException e) {throw new RuntimeException(e);}}public static void main(String[] args) throws IOException {TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);client.start();}
}
在TCP回显服务器中,需要注意下面几种情况
- 在上面代码中,PrintWriter中内置了缓冲区,IO操作都是很低效的,为了让低效的操作少一些,会引入一个缓冲区,先把写入网卡的数据王道缓冲区中,等达到一定的数量在一次发送出去,但如果发送的数据太少,缓冲区没有满,可能导致数据发送不出去,使用flush方法可以冲刷缓冲区,确保每条消息都能发送出去。
- ServerSocket在整个程序中,只有唯一一个对象,并且这个对象的生命周期伴随着整个程序,这个对象无法提前关闭,只有程序结束,随着进程的销毁一起结束。而clientSocket是每个客户端一个,随着客户端越来越多,如果不释放可能会占满文件描述符表。需要使用close方法关闭。
- 解决多个客户端向一个服务器发送请求的问题
上面的问题核心思路就是使用多线程,单个线程无法及给客户端提供服务,又能快速调用第二次accept,使用多线程,主线程就负责执行accept,其他线程就负责给客户端提供服务。如果客户端比较多就会频繁的创建销毁线程,就可以使用线程池解决频繁创建销毁线程的问题。
相关文章:

回显服务器的制作方法
文章目录 客户端和服务器TCP和UDP的特点UDP socket api的使用DatagramSocketDatagramPacketInetSocketAddress API 做一个简单的回显服务器UDP版本的回显服务器TCP版本的回显服务器 客户端和服务器 在网络中,主动发起通信的一方是客户端,被动接受的这一方…...

w28DVWA-csrf实例
DVWA-csrf实例 low级别 修改密码:修改的密码通过get请求,暴露在url上。 写一个简单的html文件,里面伪装修改密码的文字,代码如下: <html><body><a href"http://dvwa:7001/vulnerabilities/csr…...
子网络划分与互通,上网行为审计
网络环境需求:在办公网络环境中,由于公司部门的划分,以及服务器、电脑、手机等设备类型,一般都需要划分多个网段,便于进行网络管理,并提升网络通信效率。各个子网段管理员控制设备的接入,子网段之间需要进行局域网通信,发送消息和文件,通常使用飞秋。服务器网段,禁止…...
如何快速删除node_module依赖包
利用npm:输入 npm install rimraf -g rimraf node_modules...
async/await 的用法
一、async和await定义 async 是异步的意思,而 await 是等待的意思,await 用于等待一个异步任务执行完成的结果。 1.async/await 是一种编写异步代码的新方法(以前是采用回调和 promise)。 2. async/await 是建立在 promise 的基础…...

JAVA面试汇总总结更新中ing
本人面试积累面试题 基础RocketMQSpring登录技能操作线程事务微服务JVMKAFKAMYSQLRedislinux 基础 1.面向对象的三个特征 封装,继承,多态,有时候也会加上抽象。 2.多态的好处 允许不同类对象对同一消息做出响应,即同一消息可以根…...

vue-利用属性(v-if)控制表单(el-form-item)显示/隐藏
表单控制属性 v-if 示例: 通过switch组件作为开关,控制表单的显示与隐藏 <el-form-item label"创建数据集"><el-switch v-model"selectFormVisible"></el-switch></el-form-item><el-form-item label&…...

数据结构-邻接矩阵
介绍 邻接矩阵,是表示图的一种常见方式,具体表现为一个记录了各顶点连接情况的呈正方形的矩阵。 假设一共有以下顶点,其连接关系如图所示 那么,怎么表示它们之间的连接关系呢? 我们发现,各条边所连接的都…...

基于CNN-GRU-Attention的时间序列回归预测matlab仿真
目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 CNN(卷积神经网络)部分 4.2 GRU(门控循环单元)部分 4.3 Attention机制部分 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版…...

Docker部署Halo容器并结合内网穿透实现公网访问本地个人博客
文章目录 1. Docker部署Halo1.1 检查Docker版本如果未安装Docker可参考已安装Docker步骤:1.2 在Docker中部署Halo 2. Linux安装Cpolar2.1 打开服务器防火墙2.2 安装cpolar内网穿透 3. 配置Halo个人博客公网地址4. 固定Halo公网地址 本文主要介绍如何在CentOS 7系统使…...
纯css实现文字左右循环滚动播放效果
思路:由两个span模块组成,第一个为空的span内容,为的是实现第二个span内容缓慢出现的效果。 代码如下: <div class"scrollingStyle"><span class"first-marquee"></span><span class&q…...

【Java EE初阶二十二】https的简单理解
1. 初识https 当前网络上,主要都是 HTTPS 了,很少能见到 HTTP.实际上 HTTPS 也是基于 HTTP.只不过 HTTPS 在 HTTP 的基础之上, 引入了"加密"机制;引入 HTTPS 防止你的数据被黑客篡改 ; HTTPS 就是一个重要的保护措施.之所以能够安全, 最关键的…...
系统学习Python——装饰器:类装饰器-[跟踪对象接口:基础知识]
分类目录:《系统学习Python》总目录 文章《系统学习Python——装饰器:类装饰器-[单例类:基础知识]》的单例示例阐明了如何使用类装饰器来管理一个类的所有实例。类装饰器的另一个常用场景是为每个生成的实例扩展接口。类装饰器基本上可以在实…...
go-redis 使用 redis 6.0.14 版本错误: consider implementing encoding.BinaryMarshaler
使用方法 err : bp.data.redis.Get(ctx, policyKey).Scan(&result)起初在 redis 5.x.x 版本并没有遇到错误,但是在切换 redis 实例之后就出现了错误(他们之间只是版本不同)。 修复方法 看错误日志的描述,大概含义就是需要我们…...

计网 - 域名解析的工作流程
文章目录 Pre引言1. DNS是什么2. 域名结构3. 域名解析的工作流程4. 常见的DNS记录类型5. DNS安全6. 未来的发展趋势 Pre 计网 - DNS 域名解析系统 引言 在我们日常使用互联网时,经常会输入各种域名来访问网站、发送电子邮件或连接其他网络服务。然而,我…...

普中51单片机学习(EEPROM)
EEPROM IIC串行总线的组成及工作原理 I2C总线的数据传送 数据位的有效性规定 I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许…...
智能风控体系之供应链业务模式
供应链金融是一种针对中小企业的新型融资模式,将资金流有效整合到供应链管理的过程中,既为供应链各环节企业提供贸易资金服务,又为供应链弱势企业提供新型贷款融资服务,以核心客户为依托,以真实贸易背景为前提…...
最少停车数(C 语言)
题目描述 特定大小的停车场,数组cars[]表示,其中1表示有车,0表示没车。车辆大小不一,小车占一个车位(长度1),货车占两个车位(长度2),卡车占三个车位…...

MAC M1安装vmware和centos7虚拟机并配置静态ip
一、下载vmware和centos7镜像 1、VMWare Fusion 官网的下载地址是:下载地址 下载好之后注册需要秘钥,在官网注册后使用免费的个人秘钥 2、centos7 下载地址: https://biosyxh.cn:5001/sharing/pAlcCGNJf 二、虚拟机安装 直接将下…...

java 课程签到管理系统Myeclipse开发mysql数据库web结构jsp编程servlet计算机网页项目
一、源码特点 java 课程签到管理系统是一套完善的java web信息管理系统 采用serlvetdaobean,对理解JSP java编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发࿰…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析
这门怎么题库答案不全啊日 来简单学一下子来 一、选择题(可多选) 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘:专注于发现数据中…...
Golang dig框架与GraphQL的完美结合
将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用,可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器,能够帮助开发者更好地管理复杂的依赖关系,而 GraphQL 则是一种用于 API 的查询语言,能够提…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...

Cloudflare 从 Nginx 到 Pingora:性能、效率与安全的全面升级
在互联网的快速发展中,高性能、高效率和高安全性的网络服务成为了各大互联网基础设施提供商的核心追求。Cloudflare 作为全球领先的互联网安全和基础设施公司,近期做出了一个重大技术决策:弃用长期使用的 Nginx,转而采用其内部开发…...
【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)
要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况,可以通过以下几种方式模拟或触发: 1. 增加CPU负载 运行大量计算密集型任务,例如: 使用多线程循环执行复杂计算(如数学运算、加密解密等)。运行图…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)
RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发,后来由Pivotal Software Inc.(现为VMware子公司)接管。RabbitMQ 是一个开源的消息代理和队列服务器,用 Erlang 语言编写。广泛应用于各种分布…...