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

回显服务器

.

在这里插入图片描述

写一个应用程序,让这个程序可以使用网络通信,这里就需要调用传输层提供的api,传输层提供协议,主要是两个:
UDP,TCP,它们分别提供了一套不同的api,socket api.

UDP和TCP

UDP:无连接,不可靠传输,面向数据报,全双工
TCP:有连接,可靠传输,面向字节流,全双工
一个客户端可以连接多个服务器,一个服务器也可以连接多个客户端(多对多)

连接(connection)

链接(link)快捷方式
windows上只有软链接(符号链接),通过一个文件,文件的内容保存另一个文件的路径,实现软链接
Linux除了支持软连接,还支持硬链接(两个路径,共享同一个inode节点)

可靠传输和不可靠传输

可靠传输,不是说,A给B发信息100%能收到,而是A尽可能的把消息传给B,并且在传输失败或者成功的时候,A能够感知得到
这里的可靠与否,不能说明谁好谁坏,可靠传输想要实现,也是需要一定的成本,所以,有舍才有的,我们应该将这两种属性视为各自的特性
TCP和文件操作类似,都是"流"式的(由于这里传输的单位是字节,称为字节流)
比如:
通过TCP读写100字节的数据
可以一次读100字节
一次读写50字节,分两次
一次读写10字节,分10次
UDP是面向数据报,读写的基本单位,是一个UDP数据报(包含了一系列是数/属性)
全双工:一个通道,可以双向通信
半双工:一个通道,只能单向通信
UDP更简单,先认识UDP的socket api
两个核心的类:
1.DatagramSocket
操作系统,使用文件这样的概念,来管理一些硬件资源,网卡,操作系统也是使用文件的方式来管理网卡的,
表示网卡这样的文件,称为socket文件
Java中的socket对象,对应着系统里的socket文件(最终还是要落到网卡上)
要进行网络通信,必须得先有socket对象
在这里插入图片描述
一个客户端的主机,上面运行的程序有很多,可能存在手动指定的端口号被别的程序占用的了,让系统分配,更为合适
在这里插入图片描述

2.DatagramPacket
表示UDP数据报,代表了系统中设定的UDP数据报的二进制数据

方法签名方法说明
DatagramPacket(byte[]buf, int length)构造一个DatagramPacket以用来接收数据报,接收的数据保存在字节数组(第一个参数buf)中,接收指定长度(第二个参数length)
DatagramPacket(byte[]buf, int offset, int length,SocketAddress address)构造一个DatagramPacket以用来发送数据报,发送的数据为字节数组(第一个参数buf)中,从0到指定长度(第二个参数length)。address指定目的主机的IP和端口号

在这里插入图片描述
接下来,开始手动编写一个UDP客户端服务器

回显服务器

UDP版本

服务器

package network;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class UdpEchoSerevr {DatagramSocket socket = null;public UdpEchoSerevr(int port) throws SocketException {//这里抛出的异常,最常见的情况是端口号被占用socket = new DatagramSocket(port);}//使用下面的start取调用服务器public void start() throws IOException {System.out.println("服务器启动!");//反复的,长期的执行针对客户端请求处理的逻辑.while(true){DatagramPacket packet = new DatagramPacket(new byte[4096],4096);//一个服务器,在执行过程中,主要执行的是三个核心任务//1.读取请求,并解析//下面这个方法中的参数DatagramPacket是一个"输出型参数"//传入receive的是一个空的对象//receive内部就会把这个空的对象的内容给填充上,//当receive执行结束的时候,就会得到一个装满内容的DatagramPacketsocket.receive(packet);//要将数据报转换为字符串的前提是,客户端发的数据就是一个文本的字符串String request = new String(packet.getData(),0,packet.getLength());//2.根据请求,计算响应String response = process(request);//3.把响应写回给客户端//此时要告知网卡,要发送给客户端的内容是什么,要发给谁//getSocketAddress可以得到客户端主机的ip和端口号DatagramPacket responseRequest = new DatagramPacket(response.getBytes(),response.getBytes().length,packet.getSocketAddress());socket.send(responseRequest);System.out.printf("[%s:%d] req: %s,resp: %s\n",packet.getAddress().toString(),packet.getPort(),request,response);}}public String process(String request){return request;}public static void main(String[] args) throws IOException {UdpEchoSerevr serevr = new UdpEchoSerevr(9090);serevr.start();}
}

客户端

package network;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {DatagramSocket socket = null;private String serevrIP;private int serverPort;public UdpEchoClient(String IP,int Port) throws SocketException {serevrIP = IP;serverPort = Port;socket = new DatagramSocket();}public void start() throws IOException {Scanner scanner = new Scanner(System.in);System.out.println("客户端启动!");while(true){System.out.println("->");String request = scanner.next();//构造UDP发送的数据报时,需要传入 SocketAddress ,该对象可以使用 InetSocketAddress 来创建。//构造请求对象,并发给服务器DatagramPacket requestPacket = new DatagramPacket(request.getBytes(),request.getBytes().length,InetAddress.getByName(serevrIP),serverPort);socket.send(requestPacket);//读取服务器的响应,并解析出响应内容DatagramPacket responsePacket = new DatagramPacket(new byte[4096],4096);socket.receive(requestPacket);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("192.168.38.196" ,9090);client.start();}
}

字典服务器

package network;import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;public class UdpditServer extends UdpEchoSerevr{public static HashMap<String,String> hashMap = new HashMap<>();public UdpditServer(int port) throws SocketException {super(port);hashMap.put("cat","猫");hashMap.put("dog","狗");hashMap.put("girl","女孩");hashMap.put("boy","男孩");}@Overridepublic String process(String request) {return hashMap.getOrDefault(request,"没有查到相关信息");}public static void main(String[] args) throws IOException {UdpditServer udpditServer = new UdpditServer(9090);udpditServer.start();}
}

TCP版本

分量要比UDP更重,用到更多的协议
TCP提供的API主要也是有两个类:
ServerSocket(给服务器使用的socket)
Socket(既会给服务器使用,也会给客户端使用)
这里不需要专门的类来表示TCP数据报,因为TCP是进行字节流传输的,是一个字节一个字节的进行传输的,而一个TCP数据报,就是一个字节数组

服务器

package network;import java.io.*;
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 ExecutorService service = Executors.newCachedThreadPool();private ServerSocket serverSocket = null;public TcpEchoServer(int port) throws IOException {serverSocket =new ServerSocket(port);}public void start() throws IOException {//进入start方法后,第一件事不是读取客户端的请求,而是处理客户端的"连接"//内核中的"连接",就像一个一个"代办事项",这些代办事项在一个队列 的数据结构中,//应用程序就要一个一个的完成这些任务,要完成任务,就要先取出这些任务//取出任务,需要用到下面这个方法//当客户端和服务器进行数据交互的时候,就会进行"握手"//"握手"成功后,就会生成一个这样的代办事项,称为"连接"//客户端的应用程序在生成serversocket文件的时候,socket内部会有一个队列,用来管理上述的"连接"//每个socket都有这样一个队列,各自独立//当没有客户端的时候,就会进入阻塞Socket clientSocket = serverSocket.accept();//accept是把内核中已经建立好的连接,从serverSocket的队列中给拿到应用程序中,但是这里的返回值并非是一个"connection"对象//而是一个socket对象,通过这个socket对象和对方进行网络通信service.submit(new Runnable() {@Overridepublic void run() {try {processConnection(clientSocket);} catch (IOException e) {e.printStackTrace();}}});}//通过这个方法,来处理连接的逻辑private void processConnection(Socket clientSocket) throws IOException {System.out.printf("[%s:%d]客户端上线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());//接下来,就可以进行读取请求,根据请求计算响应,返回响应//socket内部包含两个字节流对象,可以把这两个字节流获取到,完成后续的工作try(InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()){//一次连接中,可能会涉及到多次请求/响应while (true){//1.读取请求并解析,为了方便读取,直接使用ScannerScanner scanner = new Scanner(inputStream);if (!scanner.hasNext()){//读取完毕,客户端下线System.out.printf("[%s:%d]客户端下线!",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}//这个代码暗含一个规定,客户端发过来的数据,必须是一个文本数据,同时,还得带有空白符作为分割(比如换行)String request = scanner.next();//next就是读取数据,一直读到空白符结束//2.根据请求计算响应String response = process(request);//3.把响应写回给客户端,把outputStream使用PrinterWriter包裹一下,方便进行发数据PrintWriter writer = new PrintWriter(outputStream);//此处使用PrintWriter的println方法,把响应返回给客户端//次数用println就是为了在结尾加上一个\n,为方便客户端读取响应,使用Scanner.next读取writer.println(response);//这里还需要加一个"刷新缓冲区"的操作//IO操作是比较消耗资源的,相比于访问内存,进行IO次数越多,程序的速度就越慢,//使用一块内存作为缓冲区,写数据的时候,先写道缓冲区内进行一波缓冲,统一进行IO//PrintWriter内置了缓冲区,手动刷新,确保这里的数据是真的通过网卡发出去了,而不是残留在内存缓冲区中writer.flush();//不加这一句也不一定错,缓冲区满了的时候,也会触发刷新,程序退出也会}}catch (IOException e){e.printStackTrace();}finally {//每次读取一个连接,都会创建一个socket,会很占用内存,因此,需要确保及时被closeclientSocket.close();}}public String process(String request){return request;}public static void main(String[] args) throws IOException {TcpEchoServer tcpEchoServer = new TcpEchoServer(9090);tcpEchoServer.start();}
}

客户端

package network;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 {//这个new操作之后,就完成了TCP的连接socket = new Socket(ServerIp,ServerPort);}public void start(){System.out.println("客户端启动!");try(InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()){while (true){//1.从控制台输入字符串System.out.println("->");Scanner scanner = new Scanner(System.in);String request = scanner.next();//2.把请求发送给服务器PrintWriter writer = new PrintWriter(outputStream);writer.println(request);writer.flush();//3.读取服务器的响应,并打印Scanner scanner1 = new Scanner(inputStream);String response = scanner1.next();System.out.println(response);}} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) throws IOException {TcpEchoClient tcpEchoClient = new TcpEchoClient("127.0.0.1",9090);tcpEchoClient.start();}
}

解决高并发问题:
1.开源:引入更多的硬件资源.
2.节流:提供单位硬件资源能够处理的请求数(IO多路复用)

相关文章:

回显服务器

. 写一个应用程序,让这个程序可以使用网络通信,这里就需要调用传输层提供的api,传输层提供协议,主要是两个: UDP,TCP,它们分别提供了一套不同的api,socket api. UDP和TCP UDP:无连接,不可靠传输,面向数据报,全双工 TCP:有连接,可靠传输,面向字节流,全双工 一个客户端可以连接…...

c#,dotnet, DataMatrix 类型二维码深度识别,OCR,(基于 Halcon)

代码中部分调用的 c 函数参数&#xff0c;具体说明自行研究~&#xff08;我也是参考的其他资源&#xff0c;还没研究透彻&#xff09; 例如&#xff1a;HOperatorSet.GenRectangle2() &#xff0c; 2000, 2000, 0, 2000, 2000 这些数字应该是选取的图片解析范围、尺寸&#xff…...

亿道丨三防平板电脑厂商哪家好丨麒麟系统三防平板PAD

随着科技的飞速发展&#xff0c;人们对于移动设备的需求越来越高。然而&#xff0c;在不同的行业应用场景下&#xff0c;常规的智能平板往往无法满足特殊的工作要求。&#xff0c;亿道三防平板&#xff0c;将高可靠性与卓越性能高度结合&#xff0c;为各行各业提供卓越的移动解…...

什么是hash冲突?以及解决方案

哈希冲突是指在哈希表中&#xff0c;两个或更多个不同的键被映射到了同一个哈希桶的情况。这种情况可能会导致数据丢失或者检索效率下降&#xff0c;因为不同的键被映射到了同一个位置&#xff0c;需要额外的操作来处理这种冲突。 解决哈希冲突的常见方法包括&#xff1a; 开放…...

C# CAD交互界面-模态窗体与非模态窗体调用方式

运行环境Visual Studio 2022 c# cad2016 一、模态窗体调用方式&#xff1a; 当一个模态窗体打开时&#xff0c;它会阻塞主窗体的所有输入&#xff0c;直到关闭该模态窗体为止。例如&#xff0c;弹出一个对话框让用户必须完成某些操作后才能继续使用主程序。 [CommandMethod(&q…...

19个Web前端交互式3D JavaScript框架和库

JavaScript &#xff08;JS&#xff09; 是一种轻量级的解释&#xff08;或即时编译&#xff09;编程语言&#xff0c;是世界上最流行的编程语言。JavaScript 是一种基于原型的多范式、单线程的动态语言&#xff0c;支持面向对象、命令式和声明式&#xff08;例如函数式编程&am…...

PaddleSeg分割框架解读[01] 核心设计解析

文章目录 PaddleSeg分割框架解读[01] 核心设计解析tools/train.pypaddleseg/cvlibs/config.pypaddleseg/cvlibs/builder.pypaddleseg/cvlibs/manager.pyPaddleSeg分割框架解读[01] 核心设计解析 tools/train.py import argparse import random import numpy as np import cv2…...

新鲜出炉:小巧优雅的 css-in-js库StyledFc

StyledFc 一个简单的运行时css-in-js库&#xff0c;用于封装react组件 零依赖非常小&#xff0c;< 3kb.运行时生成css支持css变量支持类似less的嵌套css样式支持props动态css支持typescript 演示 安装 pnpm add styledfc # or npm install styledfc # or yarn add styl…...

Python编程实验四:函数的使用

目录 一、实验目的与要求 二、实验内容 三、主要程序清单和程序运行结果 第1题 第2题 第3题 第4题 第5题 四、实验结果分析与体会 一、实验目的与要求 &#xff08;1&#xff09;通过本次实验&#xff0c;学生应掌握函数的定义与调用的基本语法&#xff0c;能根据需要…...

SVN服务备份

hotcopy备份 window批处理 保存以下内容到svn_buckup.bat&#xff0c;确保内容的路径正确&#xff0c;最后双击bat文件进行备份即可 echo offrem SVN安装路径 set svn"C:\Program Files\VisualSVN Server\bin"rem 仓库根目录 set homeE:\Repositories\WorkSpacere…...

FIDO2入门以及相关概念 Client to Authenticator Protocol

​ 本文根据官方文档的定义以及我疑惑的问题做出的相关整理的问答&#xff0c;可能会有偏差&#xff0c;请以官网为准。 官网文档网址&#xff1a;Client to Authenticator Protocol (CTAP) ​ FIDO是什么 FIDO&#xff08;Fast Identity Online&#xff09;是一组开放标准和…...

Linux系统入门:嵌入式系统的操作系统选型

&#xff08;本文为简单介绍&#xff0c;内容来源网络和AI模型生成&#xff09; Linux是一种开源的操作系统,它建立在Unix操作系统的基础之上,采用了Unix的很多理念和设计思想。与商业操作系统如Windows相比,Linux系统资源占用少,运行高效稳定,且Linux系统免费开源,使用和传播…...

数据结构——时间复杂度

前言&#xff1a; 当谈到数据结构和算法时&#xff0c;时间复杂度是一个至关重要的概念。时间复杂度是衡量算法执行时间随输入规模增长而变化的度量&#xff0c;它指示了算法的效率和性能。在本篇博客中&#xff0c;我们将深入探讨时间复杂度的相关知识&#xff0c;并结合C语言…...

《剑指Offer》笔记题解思路技巧优化 Java版本——新版leetcode_Part_5

《剑指Offer》笔记&题解&思路&技巧&优化_Part_5 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题&#x1f7e2;1. LCR 158. 库存管理 II——数组中出现次数超过一…...

ubuntu上安装docker

在 Ubuntu 上安装 Docker&#xff0c;可以按照以下步骤进行操作&#xff1a; 更新软件包列表&#xff1a;运行以下命令来更新系统的软件包列表&#xff1a; sudo apt update安装必要的依赖项&#xff1a;运行以下命令来安装 Docker 所需的依赖项&#xff1a; sudo apt install …...

【Docker】Linux主机部署Docker

Docker部署 1.二进制文件部署 到如下地址&#xff0c;下载二进制包。 Docker官网&#xff1a;https://docs.docker.com/engine/install/binaries/ 网易镜像源&#xff1a;https://mirrors.163.com/docker-ce/linux/static/stable/x86_64/ 下载好的二进制包上传到主机&#xf…...

vue前端docx库生成word表格 并合并单元格的例子

Vue.js 是一个流行的前端JavaScript框架&#xff0c;用于构建用户界面和单页应用程序。在Vue中生成Word表格并合并单元格&#xff0c;通常需要使用额外的库&#xff0c;如docx&#xff0c;它是一个用于创建和修改Word文档&#xff08;.docx&#xff09;的JavaScript库。 …...

FastGPT配置文件及OneAPI程序:

FastGPT配置文件及OneAPI程序&#xff1a;百度网盘 请输入提取码 提取码&#xff1a;wuhe 创建fastgpt目录&#xff1a;mkdir fastgpt 切换到fastgpt目录&#xff1a;cd fastgpt 下载docker-compose文件&#xff1a;curl -O https://raw.githubusercontent.com/labring/Fast…...

Positive Semidefinite Matrices 什么是半正定矩阵?(undone)

参考视频&#xff1a;https://www.bilibili.com/video/BV1Vg41197ew/?vd_source7a1a0bc74158c6993c7355c5490fc600 参考资料(半正定矩阵的定义)&#xff1a;https://baike.baidu.com/item/%E5%8D%8A%E6%AD%A3%E5%AE%9A%E7%9F%A9%E9%98%B5/2152711?frge_ala 看看半正定矩阵的…...

shapely 笔记:STR TREE

数据结构笔记&#xff1a;R树-CSDN博客 1 基本介绍 使用Sort-Tile-Recursive (STR) 算法创建的仅查询的R-tree空间索引该树索引每个几何图形的边界框。树在初始化时直接构建&#xff0c;且一旦创建后不能添加或移除节点所有操作返回输入几何图形的索引边界框限于二维并且是轴…...

neo4j常用代码

1】查版本&#xff1a; CALL dbms.components() YIELD name, versions RETURN name, versions; 2】清数据&#xff1a; MATCH ()-[r]->() DELETE r; MATCH (n) DETACH DELETE n; 3】NEO4J 操作入门_neo4j查看历史执行命令-CSDN博客 :play --首页 :help match/keys/com…...

OpenAI划时代大模型——文本生成视频模型Sora作品欣赏(五)

Sora介绍 Sora是一个能以文本描述生成视频的人工智能模型,由美国人工智能研究机构OpenAI开发。 Sora这一名称源于日文“空”(そら sora),即天空之意,以示其无限的创造潜力。其背后的技术是在OpenAI的文本到图像生成模型DALL-E基础上开发而成的。模型的训练数据既包含公开…...

Less预处理器教程

学习源码可以看我的个人前端学习笔记 (github.com):qdxzw/frontlearningNotes 觉得有帮助的同学&#xff0c;可以点心心支持一下哈 一、Less介绍 less官方文档 lesscss.org/ less中文文档 less.bootcss.com/ less是一种css预处理器&#xff0c;它扩展了css语言&#xff0c…...

PCL 计算点云AABB包围盒的体积

目录 一、AABB包围盒二、代码实现三、结果展示四、相关链接本文由CSDN点云侠原创,原文链接。爬虫自重,把自己当个人。 一、AABB包围盒 AABB包围盒又称了 轴对齐包围盒,是点云包围盒里最简单的一种,其计算方法也极其简单。获取包围盒之后,根据包围盒的长宽高进行体积计算即…...

论软件测试工程师 重要性!

在生活中&#xff0c;我们常常会遇到以下几种窘迫时刻&#xff1a; 准备骑共享单车出行&#xff0c;却发现扫码开锁半天&#xff0c;车子都没有反应&#xff1b;手机导航打车&#xff0c;却发现地图定位偏差很大&#xff0c;司机总是跑错地方&#xff1b;买个水&#xff0c;却…...

防御第六次作业-防火墙综合实验(av、url过滤、dns过滤)

目录 拓扑图&#xff1a; 要求&#xff1a; 8 9 10 11 拓扑图 要求 前7个要求在上一篇博客&#xff1b; 8.分公司内部的客户端可以通过域名访问到内部的服务器 9.假设内网用户需要通过外网的web服务器和pop3邮件服务器下载文件和邮件&#xff0c;内网的FTP服务器也需要…...

打码半年,开源一款自定义大屏设计软件!

hi&#xff0c;大家好&#xff0c;我是Tduck马马。 最近我们开源了一款大屏软件-TReport&#xff0c;与大家分享。 TReport是一款基于Vue3技术栈的数据可视化系统&#xff0c;支持静态、动态api等数据源&#xff1b;可用于数据可视化分析、报表分析、海报设计使用。 提供自定…...

云计算基础-大页内存

大页内存功能概述 什么是大页内存 简单来说&#xff0c;就是通过增大操作系统页的大小来减小页表&#xff0c;从而避免快表缺失 主要应用场景 主要运用于内存密集型业务的虚拟机&#xff0c;比如对于运行数据库系统的虚拟机&#xff0c;采用HugePages(大页)后&#xff0c;可…...

数据结构-邻接链表

介绍 邻接矩阵是运用较多的一种储存图的方法&#xff0c;但如果一张网图边数较少&#xff0c;就会出现二维矩阵中大部分数据为0的情况&#xff0c;浪费储存空间 为了避免空间浪费&#xff0c;也可以采用数组与链表结合的方式来存储图 假设有这样一张图 我们可以先用一个数组…...

十三、集合进阶——单列集合 及 数据结构

单列集合 及 数据结构 13.1 集合体系结构13.1.2 单列集合1. Collection2.Collection 的遍历方式迭代器遍历增强for遍历Lambda表达式遍历 3.List集合List集合的特有方法List集合的遍历方式五种遍历方式对比 4.数据结构1).栈2).队列3&#xff09;数组4&#xff09;链表小结5&…...