网络编程套接字(含Java示例)

news2024/12/24 21:36:00

文章目录

  • Socket套接字
    • 概念
    • 分类
      • 流式套接字:使用传输层TCP协议
      • 数据报套接字:使用传输层UDP协议
      • Unix域套接字
  • TCP vs UDP
    • 有连接 vs 无连接
    • 可靠传输 vs 不可靠传输
    • 面向字节流 vs 面向数据报
    • 全双工 vs 半双工
  • UDP数据报套接字编程
    • DatagramSocket
    • DatagramPacket
    • 代码示例
  • TCP流套接字编程
    • ServerSocket(专门给服务器用的)
    • Socket(客户端和服务器都要用)
    • 代码示例

Socket套接字

概念

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

分类

Socket套接字针对传输层协议主要划分为如下三类:

流式套接字:使用传输层TCP协议

TCP,即Transmission Control Protocol(传输控制协议)
以下为TCP的特点:

  • 有连接
  • 可靠传输
  • 面向字节流
  • 有接收缓冲区,也有发送缓冲区
  • 大小不限
  • 全双工

数据报套接字:使用传输层UDP协议

UDP,即User Datagram Protocol(用户数据报协议)
以下为UDP的特点:

  • 无连接
  • 不可靠传输
  • 面向数据报
  • 有接收缓冲区,无发送缓冲区
  • 大小受限:⼀次最多传输64k
  • 全双工

Unix域套接字

不能跨主机通信,只是本地主机上的进程和进程之间的通信方式(现在使用很少了)

TCP vs UDP

TCP和UDP都是传输层协议,都是给应用层提供服务的。但是这两个协议差异非常大,因此我们就需要两套API来分别表示

特点:

  • TCP:有连接,可靠传输,面向字节流,全双工
  • UDP:无连接,不可靠传输,面向数据报,全双工

有连接 vs 无连接

  • 有连接就好比打电话,得对面接通了,然后才能通信。可以选择接通也可以选择直接挂掉,通信双方保存对方的信息
  • 无连接就好比发短信/发微信,不需要"先接通",直接就可以发送,无法拒绝,通信双方不需要保存对方的信息

计算机的连接(Connection),认为是,要建立连接的双方各自保存对方的信息。此时,就认为是建立了一个"抽象的连接"。双方把对方的信息删除掉就是断开连接

“链接”(link)是网络中常用的词语,指利用技术手段将网址、文字、图片等与相应的网页联系起来,一点击网址、文字、图片等就出现网页页面。

可靠传输 vs 不可靠传输

首先要区分 可靠 != 安全

  • 可靠:尽力做到数据完整地到达对方,而不是确保。在网络通信的过程中,可能存在很多意外情况,比如丢包(传输的过程中会经过很多的交换机和路由器进行转发。如果路由器/交换机转发的数据量超出自己的硬件极限水平,此时,多出来的数据就会被直接丢弃掉),为了减少丢包就引入"可靠传输"
  • 安全:传输的数据是否容易被黑客截获掉;一旦被截获之后,是否会造成严重的影响

TCP内部就提供了一系列的机制来实现可靠传输,但如果出现网线断开的情况,纵使软件再可靠也无济于事
UDP是不可靠传输。传输数据的时候压根不关心对方是否收到,发了就完了
可靠传输的效率会大打折扣,所以UDP的效率比TCP高

面向字节流 vs 面向数据报

字节流可以简单的理解为,传输数据是基于IO流。流式数据的特征就是在IO流没有关闭的情况下,是无边界的数据,可以多次发送,也可以分开多次接收。

数据报可以简单的理解为,⼀次发送全部数据报,⼀次接收全部的数据报,发送⼀块数据假如100个字节,必须⼀次发送,接收也必须⼀次接收100个字节,而不能分100次,每次接收1个字节。

全双工 vs 半双工

  • 全双工:一条链路,能够进行双向通信(TCP,UDP都是全双工),能同时接收数据和发送数据
  • 半双工:一条链路,只能进行单向通信,要么接收数据,要么发送数据,不能同时进行

UDP数据报套接字编程

java中使用UDP协议通信,主要基于 DatagramSocket 类来创建数据报套接字,并使用DatagramPacket 作为发送或接收的UDP数据报
socket API都是系统提供的,不同的系统提供的API不一样。Java对系统的这些API进一步封装了

DatagramSocket

构造方法:

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

方法:

方法签名方法说明
void receive(DatagramPacket p)从此套接字接收数据报(如果没有接收到数据报,该方法会阻塞等待)
void send(DatagramPacket p)从此套接字发送数据报包(不会阻塞等待,直接发送)
void close()关闭此数据报套接字,socket也是一种文件,如果不关闭会占用文件描述符表一个表项

系统中本身就有socket这样的概念,系统中的socket可以理解成是一种文件,是"网卡"这个硬件设备的抽象表现形式,针对socket文件的读写操作就相当于针对网卡这个硬件设备进行读写。DatagramSocket就是对于操作系统的socket概念的封装,可以视为是"操作网卡"的遥控器,针对这个对象进行读写操作,就是针对网卡进行读写操作

"遥控属性"这样的概念,计算机中起了个专门的名字:“句柄”(handle)
磁盘上的普通文件就是硬盘的抽象表现形式。可以直接操作硬盘,但不方便。借助文件这个"遥控器"就可以很方便地完成了

DatagramPacket

DatagramPacket是DatagramSocket发送和接收的数据报。是针对UDP数据报的一个抽象表示。一个DatagramPacket对象就相当于一个UDP数据报,一次发送/接收,就是传输了一个DatagramPacket对象

构造方法:

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

方法:

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

构造UDP发送的数据报时,第四个参数需要传入 SocketAddress ,该对象可以使用 InetSocketAddress(Socket地址,包含IP地址和端口号)来创建

代码示例

网络程序就会有客户端,也有服务器
Echo称为"回显",意思就是请求发了啥,响应就是啥。这个过程,没有计算,也没有业务逻辑,这是最简单的客户端-服务器程序,只是单纯地去认识socket API的用法。一般的服务器,给ta发送不同的请求会返回不同的响应

服务器完整代码:

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[1024], 1024);
            //如果没有客户端发送请求,服务器的代码就会在receive这里阻塞,这里的阻塞是系统内核控制的。直到有客户端发来请求为止
            socket.receive(requestPacket);
            //为了方便在Java代码中处理(进行打印),可以把上述数据报中的二进制数据拿出来构造成String
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            //2.根据请求计算响应
            String response = process(request);
            //3.把响应返回客户端
            //由于UDP,UDP socket自身没有记录请求方的ip和端口号等信息,但是DatagramPacket这个对象里有
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(), 0, response.getBytes().length,
                    requestPacket.getSocketAddress());

            socket.send(responsePacket);
            // 记录⽇志, ⽅便观察程序执行效果
            System.out.printf("[%s:%d] req=%s, resp=%s\n", requestPacket.getAddress(), 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();
    }
}

在这里插入图片描述
网络编程本质上也是IO操作

在这里插入图片描述
服务器程序,需要在程序启动时把端口号确定下来,因为客户端要能知道服务器在哪才能发起请求
程序猿可以自行指定端口号,只要确保:

  • 端口号是合法的,在1~65535之间
  • 不能和其他进程使用的端口号冲突

可以先随便写个端口号试试,如果程序运行没有出现任何异常说明是不冲突的。如果冲突了就会抛出异常,换别的端口号即可

在这里插入图片描述

DatagramPacket这个对象是一个UDP数据报,包含两个部分:

  • 报头通过类的属性来表示
  • DatagramPacket构造方法传递的字节数组作为持有载荷的空间

在这里插入图片描述
String有一个版本的构造方法可以通过字节数组来构造,字节数组转String会根据编码格式转换为对应的字符

在这里插入图片描述
这个方法返回的对象InetSocketAddress里面就包含了IP和端口号

客户端完整代码:

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 {
        // 这个 new 操作, 就不再指定端⼝了. 让系统⾃动分配⼀个空闲端⼝
        socket = new DatagramSocket();
        this.serverIp = serverIp;
        this.serverPort = serverPort;
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);
        while (true) {
            System.out.println("请输入要发送的请求: ");
            //1.从控制台读取用户输入
            String request = scanner.nextLine();
            //2.构造请求并发送
            //构造请求数据报的时候,不光要有数据,还要有"目标"
            //InetAddress对象提供了getByName工厂方法,把上述字符串格式的ip地址转成Java能识别的InetAddress对象,这个对象里有ip地址(按照32位整数的形式来保存)
            DatagramPacket requestPacket = new DatagramPacket(request.getBytes(), 0, request.getBytes().length,
                    InetAddress.getByName(serverIp), serverPort);
            socket.send(requestPacket);
            //3.读取响应数据
            DatagramPacket responsePacket = new DatagramPacket(new byte[1024], 1024);
            //此处的receive也会阻塞,阻塞直到响应到达为止。这是系统内核完成好了的功能
            socket.receive(responsePacket);
            //4.显示响应到控制台上
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.println(response);
        }
    }
    public static void main(String[] args) throws IOException {
        //服务器和客户端在一个主机上,就用环回ip"127.0.0.1",如果不在同一个主机上,服务器ip是啥就写啥
        //此处端口号写的是服务器在创建socket对象时指定的端口号
        UdpEchoClient client = new UdpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

构造客户端的socket对象时,没有指定端口号,不代表没有。操作系统自动分配了一个不冲突的端口号,这个自动分配的端口号,每次启动程序可能不一样

  • 服务器要有固定端口号,是因为客户端要主动给服务器发送请求,如果服务器端口号不固定,每次都变,此时客户端就不知道请求发给谁了。服务器是在自己的电脑上的,就算端口冲突也可以自行调整
  • 客户端的端口号让系统自动分配,是因为给客户端指定的端口号可能和客户端所在电脑上的其他程序冲突,一旦端口冲突就会导致程序启动不了

为什么客户端和服务器程序都没有调用close?

因为DatagramSocket的生命周期和整个程序的生命周期是一样的,只要客户端/服务器在运行着,这个socket对象就不能释放。如果把进程结束掉,就意味着进程持有的所有资源都释放了,包括持有的内存和文件,也就不需要额外调用close。如果在某个程序中,socket的生命周期和进程不一样,需要提前释放掉,就需要调用close

注意:先运行服务器,后运行客户端。服务器是被动方,要先准备好

在这里插入图片描述
在客户端的控制台中输入要发送的内容
在这里插入图片描述
服务器控制台会打印如下内容
在这里插入图片描述

  • 客户端ip是127.0.0.1
  • 客户端的端口号是52170(系统自动分配的结果)
  • 请求内容是hello
  • 响应内容也是hello

默认情况下,如果IDEA只写了一个客户端,那就只能启动一个客户端,要想启动多个需要对IDEA的配置进行修改
在这里插入图片描述
在这里插入图片描述
Allow multiple instances勾选上,点击OK,这样就允许多个实例了
在这里插入图片描述
再次运行客户端,这样就会多出一个客户端。运行几次多出几个客户端,这些客户端都可以和服务器进行通信,而且端口号不同
在这里插入图片描述

编写⼀个英译汉的服务器. 只需要继承UdpEchoServer以及重写 process方法即可

import java.io.IOException;
import java.net.SocketException;
import java.util.HashMap;
import java.util.Map;

public class UdpDictServer extends UdpEchoServer {
    private Map<String, String> dict = null;

    public UdpDictServer(int port) throws SocketException {
        super(port);

        dict = new HashMap<>();
        dict.put("hello", "你好");
        dict.put("cat", "小猫");
        // 可以在这⾥继续添加千千万万个单词
    }

    @Override
    public String process(String request) {
        return  dict.getOrDefault(request, "该词汇没有查询到");
    }

    public static void main(String[] args) throws IOException {
        UdpDictServer server = new UdpDictServer(9090);
        server.start();
    }
}

TCP流套接字编程

ServerSocket(专门给服务器用的)

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

构造方法:

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

方法:

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

Socket(客户端和服务器都要用)

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

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

构造方法:

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

方法:

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

TCP传输的是字节流,传输的基本单位就是字节。getInputStream和getOutputStream可以获取到socket内部持有的流对象

代码示例

服务端完整代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
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 {
    //ServerSocket不用手动关闭,因为生命周期是跟随整个服务器进程的
    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和客户端交互
            Socket clientSocket = serverSocket.accept();
            pool.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        procesConnection(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });
        }
    }

    //通过这个方法来处理一个连接的逻辑
    private void procesConnection(Socket clientSocket) throws IOException {
        //1.打印日志,告知当前有客户端连上了
        System.out.printf("[%s:%d] 客户端上线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
        //2.从socket中获取流对象
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            //针对每个连接,客户端都可能会发来多个请求,服务器也就需要返回多个响应了
            Scanner scanner = new Scanner(inputStream);
            while (true) {
                //读取请求并解析
                //情况1:TCP连接存在,这里就会阻塞等待请求到达
                //情况2:一旦TCP断开连接,Scanner就相当于读到socket文件的EOF,hasNextLine解除阻塞,并返回false
                //情况3:接收到数据,hasNextLine解除阻塞,并返回true
                if(!scanner.hasNextLine()) {
                    System.out.printf("[%s:%d] 客户端下线!\n", clientSocket.getInetAddress(), clientSocket.getPort());
                    break;
                }
                //如果直接用read方法来读,读出来的是字节数组还要转成String
                //如果使用Scanner的话,直接读出来的就是String。Scanner已经做好转换操作了
                String request = scanner.nextLine();
                //根据请求计算响应
                String response = process(request);
                //把响应返回客户端
                outputStream.write(response.getBytes());
                //服务器打印日志
                System.out.printf("[%s:%d] req=%s, resp=%s\n", clientSocket.getInetAddress(), clientSocket.getPort(), request, response);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            clientSocket.close();
        }
    }

    //由于是回显服务器,直接把请求作为响应返回
    private String process(String request) {
        //给响应后面这里加上一个换行符,使客户端Scanner读取响应的时候,也有明确的分隔符,不然会一直阻塞
        return request + "\n";
    }

    public static void main(String[] args) throws IOException {
        //服务器要先处理客户端发来的连接
        TcpEchoServer server = new TcpEchoServer(9090);
        server.start();
    }
}

客户端完整代码:

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;

public class TcpEchoClient {
    private Socket socket = null;

    public TcpEchoClient(String serverIp, int serverPort) throws IOException {
        //这样的构造过程,就会和服务器之间建立TCP连接
        //具体建立连接的流程,都是系统内核完成的
        socket = new Socket(serverIp, serverPort);
    }

    public void start() throws IOException {
        System.out.println("客户端启动!");
        Scanner scanner = new Scanner(System.in);
        try (InputStream in = socket.getInputStream();
             OutputStream out = socket.getOutputStream()) {
            Scanner scannerNetWork = new Scanner(in);
            while (true) {
                //1.从控制台读取数据
                System.out.println("请输入要发送的数据: ");
                String request = scanner.nextLine();
                //2.把请求发给服务器,发送的请求末尾要带有\n,这和服务器的nextLine是对应的
                request += "\n";
                out.write(request.getBytes());
                //3.从服务器读取到响应
                if(!scannerNetWork.hasNextLine()) break;
                String response = scannerNetWork.nextLine();
                //4.打印响应到控制台
                System.out.println(response);
            }
        }
    }

    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1", 9090);
        client.start();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2094995.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI安全前沿:模型攻击与防御策略

引言 随着chatGPT的横空出世&#xff0c;通用人工智能的时代正式开启。人工智能极大地影响了人类的生活方式和生产方式&#xff0c;例如以ChatGPT为代表的各类大模型&#xff0c;能够理解和生成人类语言&#xff0c;并以对话的方式同人类进行互动&#xff0c;能够执行撰写文本…

央视报道:国产时序数据库 IoTDB 刷新世界性能纪录!

IoTDB&#xff08;Internet of Things Database&#xff09;是一个专为物联网&#xff08;IoT&#xff09;场景设计的时间序列数据库管理系统&#xff08;TSDB&#xff09;。随着物联网技术的发展&#xff0c;大量的设备连接到互联网上&#xff0c;产生了海量的时间序列数据。这…

各位天命人!国自然评审意见出来了,那如何判断是否上会?

公众号&#xff1a;生信漫谈&#xff0c;获取最新科研信息&#xff01; 各位天命人&#xff01;国自然评审意见出来了&#xff0c;那如何判断是否上会&#xff1f;https://mp.weixin.qq.com/s?__bizMzkwNjQyNTUwMw&mid2247487055&idx1&sn1dc8b66e10323d37e477e88…

新版本 Redline 使用 Lua 字节码逃避检测

近日&#xff0c;研究人员观察到 Redline Stealer 木马的新变种&#xff0c;开始利用 Lua 字节码逃避检测。 遥测分布 根据遥测数据&#xff0c;Redline Stealer 木马已经日渐流行&#xff0c;覆盖北美洲、南美洲、欧洲和亚洲甚至大洋洲。 感染链 感染链 微软官方账户的 vcp…

基于Java的汽车推荐购买系统的设计与实现(论文+源码)_kaic

摘要 随着经济水平的不断提高&#xff0c;汽车销售行业存在激烈竞争&#xff0c;人们对于生活中汽车的需求也越来越多&#xff0c;而目前的汽车推荐购买管理由于存在管理不规范性等缺点&#xff0c;严重制约了汽车推荐购买和汽车公司的发展&#xff0c;因此需要设计一个汽车推荐…

一加8T安装 Kali NetHunter 高阶教程 KB2000刷机 param预载失败 高通9008驱动签名 小米刻晴主题

前言 本文包含一加8T手机刷入kaili nethunter 的详细版教程、资源、刷机知识思维导图、param预载失败问题解决、高通刷机驱动故障问题解决、小米刻晴主题等资源的分享 本机环境 手机&#xff1a;OnePlus 8T &#xff08;型号KB2000&#xff09; 系统&#xff1a;Android 13 …

公司招聘中,多个面试官对候选人评价不一致怎么办?

面试过程中&#xff0c;极易出现面试官评价标准不一的情况&#xff0c;为了有效解决这一问题&#xff0c;企业可以建立一套标准化的面试评分体系&#xff0c;在该体系中&#xff0c;应该详细包括统一的评分标准和评分细则&#xff0c;内容覆盖求职者的专业技能、沟通能力、团队…

【Threejs进阶教程-着色器篇】6. 2D SDF(三) 移动图形,限制图形,绘制多个图形

2D SDF 移动与合并图形 前五篇地址&#xff0c;建议按顺序学习本篇使用到的初始代码减小扩散范围clamp函数修改maxDistance来修改扩散范围 移动扩散中心添加第二个扩散点降低点的同步率调整参数来优化效果添加更多扩散点 完整源码如有不明白的&#xff0c;可以在下方留言或者加…

01:【stm32HAL】对GPIO的操作

对GPIO的操作 1、LED闪烁2、按键控制LED3、芯片调试接口被锁死导致无法下载程序 1、LED闪烁 使用的是STM32CubeMXKeilv5进行HAL库的开发。 开发的步骤&#xff1a; 第一步&#xff1a;新建工程 第二步&#xff1a;选择芯片 第三步&#xff1a;如下图哈哈 第四步&#xff1a;…

图像识别智能垃圾桶项目开发--语音命令识别垃圾

一、项目思维导图 二、语音模块配置信息 三、项目程序 main.c garbage.c garbage.h uartTool.c //串口发送数据 uartTool.h

IPv6配置实验(OSPFv3)

1.搭建拓扑图 2.配置接口IP地址

文件上传的学习

文件上传漏洞 文件上传漏洞是指由于程序员在对用户文件上传部分的控制不足或者处理缺陷&#xff0c;而导致的用户可以越过其本身权限向服务器上上传可执行的动态脚本文件。这里上传的文件可以是木马&#xff0c;病毒&#xff0c;恶意脚本或者WebShell等。“文件上传”本身没有…

计算机毕业设计推荐-基于python的公司员工考勤管理系统

&#x1f496;&#x1f525;作者主页&#xff1a;毕设木哥 精彩专栏推荐订阅&#xff1a;在 下方专栏&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; 实战项目 文章目录 实战项目 一、基于python的公司员工考勤管…

电池点焊机设计要点记录及个人分析

想要设计的由来 有些电路板或动力元件需要电池和镍片的连接&#xff0c;虽然临时使用焊锡焊接在了一起&#xff0c;但焊接过程中的热量和焊接后的厚度太大。最终想要设计一个用于点焊的板子 点焊的原理和操作上的误区 原理&#xff1a;两个点焊笔和镍片的接触点直径相比于导…

Local GAP - Financial Statement Version 【海外BS\PL报表】

业务场景&#xff1a; 基于海外IFRS等会计准则为客户定义一套BS\PL报表 BS - 从科目余额抓取 PL - 从利润中心报表抓取 会计报表版本的建立&#xff1a; 路径&#xff1a;IMG>财务会计&#xff08;新&#xff09;>总账会计核算&#xff08;新&#xff09;主数据>总…

【电子通识】失效分析中的电测试技术——电阻测试方法及注意事项

失效分析通常需要对测试数据进行仔细的分析&#xff0c;因此&#xff0c;测试设备的数据准确性和可靠性是至关重要的基本要求。为了确保数据的准确性&#xff0c;失效分析所使用的测试设备需要进行定期计量。 测试设备选择 在测试电阻、电容和电感的设备中&#xff0c;最常见的…

watchdog: BUG: soft lockup

故障现象&#xff1a; 故障原因&#xff1a; 不知道。 解决办法&#xff1a; 由12个改成2个&#xff1b;然后重新开机虚拟机&#xff0c; 临时解决了。

使用Golang的协程竟然变慢了|100万个协程的归并排序耗时分析

前言 这篇文章将用三个版本的归并排序&#xff0c;为大家分析使用协程排序的时间开销&#xff08;被排序的切片长度由128到1000w&#xff09; 本期demo地址&#xff1a;https://github.com/BaiZe1998/go-learning 往期视频讲解 &#x1f4fa;&#xff1a;B站&#xff1a;白泽…

145. 利用 Redis Bitmap实践: 用户签到统计

文章目录 一、Redis Bitmap简介二、Bitmap 的主要应用三、Go使用Redis实现签到统计用户签到查询用户签到状态统计今年累计签到天数统计当月的签到情况 总结 在现代应用程序中&#xff0c;用户签到是一个常见的功能。我们通常使用 MySQL 数据库来存储用户的签到记录。然而&#…

c++11新特性-智能指针

1. 智能指针的概念及原理 1.1 什么是智能指针 智能指针RAII(Resource Acquisition Is Initialization)&#xff0c;是一种利用对象的生命周期来管理资源的技术。如果我们采用传统的new/delete来申请和释放资源&#xff0c;如果忘记调用delete&#xff0c;或者在调用delete之前…