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

基于 Socket 网络编程

基于 Socket 网络编程

  • 前言
  • 一、基于Socket的网络通信传输(传输层)
  • 二、UDP 的数据报套接字编程
    • 1、UDP 套接字编程 API
    • 2、使用 UDP Socket 实现简单通信
  • 三、TCP 流套接字编程
    • 1、TCP 流套接字编程 API
    • 2、使用 TCP Socket 实现简单通信
    • 3、使用 Tcp 协议进行网络传输的“五大要点”

前言

我们再进行网络编程时,主要是编写“应用层”代码,如果真正要发送这个数据,需要上层协议调用下层协议,也就是应用层调用传输层,传输层给应用层提供一组 API,统称为 Socket API

一、基于Socket的网络通信传输(传输层)

Socket 套接字,是由系统提供用于网络通信的技术,是基于 TCP/IP 协议的网络通信的基本操作单元。基于Socket 套接字的网络程序开发就是网络编程。

在这一块,我们对于传输层协议,主要学习两种 Socket 套接字:

数据报套接字:使用传输层UDP协议。UDP,即 User Datagram Protocol(用户数据报协议),传输层协议。
以下为UDP的特点(细节后续介绍):

  1. 无连接:使用 udp 通信的双方,不需要刻意保存对端的相关信息。
  2. 不可靠传输:不关注结果
  3. 面向数据报:以一个 udp 数据报为基本单位
  4. 全双工:双向通信(有接收缓冲区,无发送缓冲区)
  5. 大小受限:一次最多传输 64k

流套接字:使用传输层TCP协议。TCP,即 Transmission Control Protocol(传输控制协议),传输层协议。
以下为TCP的特点(细节后续介绍):

  1. 有连接:使用 TCP 通信双方,则需要刻意各自记录了对方的信息
  2. 可靠传输:发送后尽可能的传输过去,失败了也知道
  3. 面向字节流:以字节流为传输的基本单位,读写方式非常灵活
  4. 全双工:双向通信(有接收缓冲区,也有发送缓冲区)
  5. 大小不限

二、UDP 的数据报套接字编程

DatagramSocket 是UDP Socket,用于发送和接收UDP数据报。

这里的 Socket 我们可以类比于 File 对象理解,我们知道如果我们是不能直接操作硬盘的,如果想要操作硬盘就需要借助 File。对象间接操作。Socket 也是类似,它对应于网卡这个硬件设备,如果我们想要操作网卡,就需要一个 Socket 对象间接操作网卡。向 socket 对象中1写数据,就相当于通过网卡发送消息。从 socket 对象中读数据,就相当于通过网卡接收消息。

1、UDP 套接字编程 API

(1)DatagramSocket
DatagramSocket 构造方法

方法签名方法说明
DatagramSocket()创建一个UDP数据报套接字的Socket,绑定到本机任意一个随机端口(一般用于客户端)
DatagramSocket(int port)创建一个UDP数据报套接字的Socket,绑定到本机指定的端口(一般用于服务端)

说明:对于服务器,一般要手动指定一个固定的端口,客户端则不要求。类似于我去食堂吃饭,给我提供食物的窗口就是一个服务器,而我是接收食物的消费者,可看做是客户端,窗口需要有一个固定的窗口号,便于我找到它,而我在享受食物时,没有固定的座位,哪里有空位就做哪里。

DatagramSocket 方法

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字

(2)DatagramPacket
DatagramPacket 是 UDP Socket 发送和接收的数据报

DatagramPacket构造方法

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

DatagramPacket方法

方法签名方法说明
InetAddress getAddress()从接收的数据报中,获取发送端主机IP地址;或从发送的数据报中,获取接收端主机IP地址
int getPort()从接收的数据报中,获取发送端主机的端口号;或从发送的数据报中,获取接收端主机端口号
byte[] getData()获取数据报中的数据

2、使用 UDP Socket 实现简单通信

下面我们在 Java 中使用 UDP 协议实现的一个简单的客户端和服务端的通信。

下面的 服务器-客户端 代码看起来挺复杂,其实和数据库中的 JDBC 差不多,都是固定的套路,尽管之后在写更复杂的 服务器-客户端 程序,也都是在这个基础上拓展。例如下面的 UDP Socket 通过传输层实现网络通信,代码无非就下面几个步骤:

1.对于服务器:
(1)读取请求并解析
(2)根据请求计算响应
(3)把响应结果发送到客户端
2.对于客户端:
(1)构造并发送请求
(2)接收服务器返回的响应并解析响应

服务器程序:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;// Echo-回显服务器。客户端发了个请求,服务器返回一个一模一样的响应。
public class UdpEchoSever {// 需要先定义一个 socket 对象,使用网络通信,必须要使用 socekt 对象private DatagramSocket socket = null;// 绑定一个端口号,不一定能成功,比如某个端口号已经被别的进程占用了,此时这里的绑定操作就会出错。// 需要注意的是:同一个主机上,一个端口,同一时刻,只能被一个进程绑定。public UdpEchoSever(int port) throws SocketException {socket = new DatagramSocket(port);}// 启动服务器主逻辑public void start() throws IOException {System.out.println("服务器启动!");while (true) {// 每次循环,做三件事// 1. 读取请求并解析//    构造一个空的DatagramPacket对象,用来接收客户端请求DatagramPacket requestPacket = new DatagramPacket(new byte[4096],4096);//    从网卡上接收请求 此处的 requestPacket 为输出型参数socket.receive(requestPacket);//    这里为了方便处理这个请求,将数据包转化为 StringString request = new String(requestPacket.getData(),0,requestPacket.getLength());// 2. 根据请求计算响应String response = process(request);// 3. 把响应结果写回到客户端//    根据 response 字符串,构造一个 DatagramPacket//    和请求 packet 不同,此处构造响应的时候,需要指定这个包要发给谁DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),response.getBytes().length,// requestPacket 是从客户端这里收来的,getSocketAddress 会得到客户端的 ip 何为端口requestPacket.getSocketAddress());socket.send(responsePacket);// 方面查看,打印一下日志// ip 和 端口号 + 请求内容 + 响应内容System.out.printf("[%s:%d] req: %s, resp: %s\n",requestPacket.getAddress().toString(),requestPacket.getPort(),request,response);}}// process是请求处理方法,这是服务器中的一个关键环节!!!public String process(String request) {return request;}// 主函数public static void main(String[] args) throws IOException {UdpEchoSever udpEchoSever = new UdpEchoSever(9090);udpEchoSever.start();}
}

客户端程序:

import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class UdpEchoClient {private DatagramSocket socket = null;private String serverIP;private int serverPort;// 客户端启动, 需要知道服务器在哪里!!public UdpEchoClient(String serverIP, int serverPort) throws SocketException {// 对于客户端来说, 不需要显示关联端口.// 不代表没有端口, 而是系统自动分配了个空闲的端口.socket = new DatagramSocket();this.serverIP = serverIP;this.serverPort = serverPort;}public void start() throws IOException {// 通过这个客户端可以多次和服务器进行交互.Scanner scanner = new Scanner(System.in);while (true) {// 1. 先从控制台, 读取一个字符串过来//    先打印一个提示符, 提示用户要输入内容System.out.print("-> ");String request = scanner.next();// 2. 把字符串构造成 UDP packet, 并进行发送.DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,InetAddress.getByName(serverIP), serverPort);socket.send(requestPacket);// 3. 客户端尝试读取服务器返回的响应DatagramPacket responsePacket = new DatagramPacket(new byte[4096], 4096);socket.receive(responsePacket);// 4. 把响应数据转换成 String 显示出来.String response = new String(responsePacket.getData(), 0, responsePacket.getLength());System.out.printf("req: %s, resp: %s\n", request, response);}}public static void main(String[] args) throws IOException {// 127.0.0.1 是一个特殊的IP地址,表示本机的回环地址。UdpEchoClient udpEchoClient = new UdpEchoClient("127.0.0.1", 9090);udpEchoClient.start();}
}

对于UDP Echo Sever 来说,socket 对象的生命周期伴随整个程序的不需要 close。这个 socket 对象是出了循环就不用了,但是循环结束就意味着 start 结束,意味着 main 方法结束,意味着进程结束,进程结束所有文件资源就自动释放了。

三、TCP 流套接字编程

1、TCP 流套接字编程 API

(1)SeverSocket
ServerSocket 是创建TCP服务端Socket的API。

ServerSocket构造方法

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

ServerSocket 方法

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

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

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

Socket 构造方法

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

Socket 方法

方法签名方法说明
int getPort()返回此套接字连接到的远程端口号
InetAddress getInetAddress()返回套接字所连接的地址
InputStream getInputStream()返回此套接字的输入流
OutputStream getOutputStream()返回此套接字的输出流
void close()关闭此套接字

2、使用 TCP Socket 实现简单通信

下面我们同样写一个简单的基于 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 TcpEchoSever {// 这里有个比喻:// severSocket 看做是外场拉客的小哥// clientSocket 看做内场服务的小姐姐// severSocket 只有一个,clientSocket 会给每个客户端都分配一个private ServerSocket serverSocket = null;public TcpEchoSever(int port) throws IOException {serverSocket = new ServerSocket(port);}public void start() throws IOException {System.out.println("服务器启动!");ExecutorService pool = Executors.newCachedThreadPool();while (true) {Socket clientSocket = serverSocket.accept();// 如果直接调用,该方法会影响这个循环的二次执行,导致 accept 不及时// 创建新线程,用新线程调用 processConnection// 每次来一个新的客户端都创建一个新线程// 1.方案一:每次创建线程(每次创建销毁,开销较大)
//            Thread t = new Thread(()->{
//                processConnection(clientSocket);
//            });
//            t.start();// 2.方案二:使用线程池pool.submit(()->{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());// try () 这种写法,( ) 中允许写多个流对象,使用 ; 分割try (InputStream inputStream = clientSocket.getInputStream();OutputStream outputStream = clientSocket.getOutputStream()) {// 为了简单,把字节流包装成了更方便的字符流Scanner scanner = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);// 一次可能发来多个请求,这里规定以 \n 为分隔符while (true) {// 1.读取请求// 特殊处理一下:if (!scanner.hasNext()) {// 读取的流到了结尾(对端关闭了)System.out.printf("[%s:%d] 客户端下线!\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());break;}// 直接使用 scanner 读取一段字符串String request = scanner.next();// 2.根据请求计算响应String response = process(request);// 3.把响应写会给客户端,不要忘了,响应里也是要带上换行的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 {// 关闭连接clientSocket.close();}}// 处理请求public String process(String request) {return request;}// 主方法public static void main(String[] args) throws IOException {TcpEchoSever tcpEchoSever = new TcpEchoSever(9090);tcpEchoSever.start();}}

客户端程序:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.Scanner;// idea 中默认一个程序只能启动一个,启动多个客户端可配置一下 IDEA。public class TcpEchoClient {private Socket socket = null;// ***只有这里会建立连接,和 Udp 不同***public TcpEchoClient(String severIp, int port) throws IOException {// 这个操作就相当于让客户端和服务器建立 TCP 连接// 这里的链接连上了,accept 就会返回socket = new Socket(severIp,port);}public void start() {Scanner scanner = new Scanner(System.in);try (InputStream inputStream = socket.getInputStream();OutputStream outputStream = socket.getOutputStream()) {// 将字节流包装成字符流Scanner scannerFromSocket = new Scanner(inputStream);PrintWriter printWriter = new PrintWriter(outputStream);while (true) {// 1.从键盘上读取用户输入的内容System.out.print("->");String request = scanner.next();// 2.把读取的内容构成请求,发给服务器//   注意:这里的发送,是带换行的!printWriter.println(request);// 写网卡为全缓冲,这里使用flush刷新printWriter.flush();// 3.从服务器读取响应内容String response = scannerFromSocket.next();// 4. 把响应的结果显示到控制台上System.out.printf("req: %s ; resq: %s\n",request,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();}}

3、使用 Tcp 协议进行网络传输的“五大要点”

(1)自定义简单的应用层协议
对于客户端及服务端应用程序来说,请求和响应,需要约定一致的数据格式,上述为了简单,做了如下简单约定:

  1. 每个请求是个字符串
  2. 请求和请求之间,使用\n(换行符)分割

由于是回显服务器,响应和请求是一模一样的,因此也遵循上述规则。

(2)写网卡是全缓冲(写文件也是全缓冲)

为了提高IO效率,引入了缓冲区,使用缓冲区可以减少IO次数,提高整体的效率。上述 printWriter.println(“内容”) 过后,内容就被写入到了缓冲区,如果不刷新缓冲区,就要等到缓冲区满,自动刷新到网卡中,所以执行上述程序可能就会出现只请求不响应的情况,为了解决这个问题,我们可以在每次写网卡后,手动进行刷新:printWriter.flush()

(3)长连接 与 短连接

长连接和短连接是指在网络编程中不同的连接方式。

短连接指客户端与服务器建立连接后,在完成一次请求-响应操作之后就会断开连接。每次请求都需要重新建立连接,这种方式可以保证连接使用的资源较少,但也对服务器的压力较大。常用于小数据量的频繁通信场景,例如HTTP协议。

而长连接则是指客户端与服务器建立连接后,在一段时间内可以保持连接状态,多次请求-响应操作共用这一个连接。这种方式相对于短连接可以减少连接建立、关闭的次数,提高了通信效率,但是缺点是需要维护连接的状态,如果长时间没有交互,则需要进行心跳检测等机制来维持连接状态。常用于对实时性要求较高的通信场景,例如即时通讯、游戏等。

在上述TCP协议中使用到长连接。

(4)使用多线程

上述例子的服务器中使用到了多线程,如果不使用多线程,代码可能产生 BUG。因为上述 start 的 while 循环,是用来循环的接收连接,而下面的 processConnection 内部也有一个循环用来循环的处理连接。假设现在来了一个连接,start 方法接收连接后其中的 processConnection 就开始循环的处理这个连接,直到这个连接关闭,但是如果这个期间又有别的客户端进行新的连接,由于当前start中的第一次循环还没结束,就会导致一直阻塞,使其他连接处理不及时。为了解决上述问题,一个很好的办法就是使用多线程,为每个连接都分配一个线程独立处理。

(5)频繁创建,生命周期又短资源的需要 close 及时释放

  • 像上述使用 UDP 协议进行网络通信这种,生命周期伴随整个程序的不需要 close。
  • 在这里,使用 TCP 进行网络通信时,服务器那里的每个 Socket 对象只是给一个连接提供服务的,可能会有很多个连接。在这种情况下,服务器会为每个连接都创建一个新的 Socket 对象,作为后续通信的基础。当这个连接不再需要服务时,需要将相应的 Socket 对象关闭,以便及时释放资源。

相关文章:

基于 Socket 网络编程

基于 Socket 网络编程 前言一、基于Socket的网络通信传输(传输层)二、UDP 的数据报套接字编程1、UDP 套接字编程 API2、使用 UDP Socket 实现简单通信 三、TCP 流套接字编程1、TCP 流套接字编程 API2、使用 TCP Socket 实现简单通信3、使用 Tcp 协议进行…...

关于C#.Net网页跳转的7种方法

一、目前在ASP.NET中页面传值共有这么几种方式:1.Response.Redirect("http://www.hao123.com",false); 目标页面和原页面可以在2个服务器上,可输入网址或相对路径。后面的bool值为是否停止执行当前页。 跳转向新的页面,原窗口被代…...

使用acme.sh申请免费ssl证书(Cloudflare方式API自动验证增加DNS Record到期证书到期自动重新申请)

下载acme.sh curl https://get.acme.sh | sh -s emailmyexample.comcd ~/.acme.sh/获取Cloudflare密钥 Preferences | Cloudflare 登录选择账户详情选择API Token选择创建令牌选择区域DNS模板,并设置编辑写入权限生成并复制令牌备用回到首页概览界面下部获取账号…...

【C语言】进阶——结构体+枚举+联合

①前言: 在之前【C语言】初阶——结构体 ,简单介绍了结构体。而C语言中结构体的内容还有更深层次的内容。 一.结构体 结构体(struct)是由一系列具有相同类型或不同类型的数据项构成的数据集合,这些数据项称为结构体的成员。 1.结构体的声明 …...

Socket编程基础(1)

目录 预备知识 socket通信的本质 认识TCP协议和UDP协议 网络字节序 socket编程流程 socket编程时常见的函数 服务端绑定 整数IP和字符串IP 客户端套接字的创建和绑定 预备知识 理解源IP和目的IP 源IP指的是发送数据包的主机的IP地址,目的IP指的是接收数据包…...

无线通信——Mesh自组网的由来

阴差阳错找到了一个工作,是做无线通信的,因为无线设备采用Mesh,还没怎么接触过,网上搜索下发现Mesh的使用场景不多,大部分都是用在家里路由器上面。所以写了片关于Mesh网的文档。Mesh网可应用在无网络区域的地方&#…...

LRU、LFU 内存淘汰算法的设计与实现

1、背景介绍 LRU、LFU都是内存管理淘汰算法,内存管理是计算机技术中重要的一环,也是多数操作系统中必备的模块。应用场景:假设 给定你一定内存空间,需要你维护一些缓存数据,LRU、LFU就是在内存已经满了的情况下&#…...

常用工具使用

ubuntu 1.1 ubuntu与windows 互相复制问题 方法一、 打开虚拟机 ,点击上方导航栏 ‘虚拟机’ 查看VMware Tools是否安装,安装即可 方法二、 apt-get autoremove open-vm-tools apt-get install open-vm-tools apt-get install open-vm-tools-desktop…...

HashMap源码解析_jdk1.8(一)

HashMap解析 HashMap源码解析_jdk1.8(一)哈希常用数据结构查找/插入/删除性能比较。哈希冲突 HashMap的数据结构HashMap相关变量size和capacity HashMap源码解析_jdk1.8(一) 哈希 Hash,一般翻译做“散列”&#xff0…...

Android最好用的日志打印库(自动追踪日志代码位置)

给大家推荐一个自己写的日志打印的库,我愿称之为最强日志打印库:BytUtilLog Byt是Big一统的缩写,大一统日志打印库,哈哈!搞个笑,很早就写好了,但后面忙起来就忘了写一篇文章推一下它了&#xff…...

面试官的哪些举动,暗示你通过了面试?

其实在求职过程中都会发现,求职者面试时间一般在20分钟以上,如果求职者较多,可能会在10分钟左右。(会在介绍以往工作上减少时间,内容主要以简单介绍,薪资要求,能力评价,到岗时间等等) 拿面试时…...

​旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著想象和世界一样宽广

​旅行季《乡村振兴战略下传统村落文化旅游设计》许少辉八一新著想象和世界一样宽广...

Linux学习第19天:Linux并发与竞争实例: 没有规矩不成方圆

Linux版本号4.1.15 芯片I.MX6ULL 大叔学Linux 品人间百味 思文短情长 先说点题外话,上周参加行业年会,停更了一周。接下来的周五就要开启国庆中秋双节模式,所以有的时候,尤其是工作以后…...

Unity添加自定义菜单按钮

如果你想在Unity编辑器中添加自定义菜单按钮,你可以使用Unity的MenuSystem API。这是一个简单的示例: 首先需要引用using UnityEditor; using UnityEngine; using UnityEditor; 两个命名空间 然后在方法前添加 [MenuItem("原菜单名/自定义名…...

PHP8的类与对象的基本操作之类的实例化-PHP8知识详解

定义完类和方法后,并不是真正创建一个对象。类和对象可以描述为如下关系。类用来描述具有相同数据结构和特征的“一组对象”,“类”是“对象”的抽象,而“对象”是“类”的具体实例,即一个类中的对象具有相同的“型”,…...

C/S架构学习之TCP服务器

TCP服务器的实现流程:一、创建套接字(socket函数):通信域选择IPV4网络协议、套接字类型选择流式; int sockfd socket(AF_INET,SOCK_STREAM,0); //通信域选择IPV4、套接字类型选择流式二、填充服务器的网络信息结构体&…...

基于微信小程序的线上教育课程付费商城(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序(小蔡coding)有保障的售后福利 代码参考源码获取 前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…...

Linux基础指令(五)

目录 前言1. 打包和压缩1.1 是什么1.2 为什么1.3 怎么办? 2. zip & unzip3. tar 指令结语: 前言 欢迎各位伙伴来到学习 Linux 指令的 第五天!!! 在上一篇文章 Linux基本指令(四) 当中,我们学习了 fin…...

C语言结构体的一些鲜为人知的小秘密

目录 一、结构体内存对齐规则: 1.1范例 1.2结构体内存对齐规则 1.3自定义默认对齐数 二、位段 2.1什么是位段 2.2位段的内存分配 2.3位段的不足 三、枚举和联合体 3.1枚举 3.1.1枚举类型的定义 3.1.2枚举类型的使用 3.2联合体 3.2.1联合体的定义 3.…...

kubernetes问题(一)-探究Pod被驱逐的原因及解决方法

1 k8s evicted是什么 k8s evicted是Kubernetes中的一个组件,主要用于处理Pod驱逐的情况。在Kubernetes中,当Node节点资源不够用时,为了保证整个集群的运行稳定,会按照一定的优先级和策略将其中的Pod驱逐出去。这时就需要一个组件…...

大话软工笔记—需求分析概述

需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者:Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位:中南大学地球科学与信息物理学院论文标题:BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接:https://arxiv.…...

8k长序列建模,蛋白质语言模型Prot42仅利用目标蛋白序列即可生成高亲和力结合剂

蛋白质结合剂(如抗体、抑制肽)在疾病诊断、成像分析及靶向药物递送等关键场景中发挥着不可替代的作用。传统上,高特异性蛋白质结合剂的开发高度依赖噬菌体展示、定向进化等实验技术,但这类方法普遍面临资源消耗巨大、研发周期冗长…...

大语言模型如何处理长文本?常用文本分割技术详解

为什么需要文本分割? 引言:为什么需要文本分割?一、基础文本分割方法1. 按段落分割(Paragraph Splitting)2. 按句子分割(Sentence Splitting)二、高级文本分割策略3. 重叠分割(Sliding Window)4. 递归分割(Recursive Splitting)三、生产级工具推荐5. 使用LangChain的…...

使用van-uploader 的UI组件,结合vue2如何实现图片上传组件的封装

以下是基于 vant-ui&#xff08;适配 Vue2 版本 &#xff09;实现截图中照片上传预览、删除功能&#xff0c;并封装成可复用组件的完整代码&#xff0c;包含样式和逻辑实现&#xff0c;可直接在 Vue2 项目中使用&#xff1a; 1. 封装的图片上传组件 ImageUploader.vue <te…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

android13 app的触摸问题定位分析流程

一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...