【Linux系统化学习】网络套接字(编写简单的UDP服务端和客户端)

目录

理解源IP地址和目的IP地址

认识端口号

端口号和进程ID的区别

源端口号和目的端口号

认识TCP和UDP协议

TCP协议

UDP协议

网络字节序

socket编程接口

socket常见API

sockaddr结构

简单的UDP网络程序

UDP服务端

创建套接字

填充本地网络信息

绑定

收取消息

完整的服务端封装代码

UDP客户端

创建套接字

填充服务端信息

操作系统自动绑定

发送消息

 客户端完整代码

一些补充

本地回环测试

netstat指令


理解源IP地址和目的IP地址

  1. 源IP地址(Source IP Address):源IP地址是指发送数据包的设备或主机的IP地址。它是数据包的来源地址,标识了数据包从哪个设备发送出来。当你发送数据到网络上的其他设备时,你的设备会将数据包标记上源IP地址,以便接收设备知道数据来自哪里。

  2. 目的IP地址(Destination IP Address):目的IP地址是指接收数据包的设备或主机的IP地址。它是数据包的目标地址,标识了数据包应该被发送到哪个设备。当你发送数据到网络上的另一个设备时,你的设备会将数据包标记上目的IP地址,以便网络路由器和接收设备知道将数据包传送到哪里。


认识端口号

  • 端口号(port)是传输层协议的内容.
  • 端口号是一个2字节16位的整数;
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理;
  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程;
  • 一个端口号只能被一个进程占用.

注:上篇文章我们说了两台主机可以通过网络进行通信,在准确一点就是两台主机中的进程通过网络进行通信,就像我们可以在QQ给自己的基友发消息,通过网络你的基友机会在自己主机的QQ上收到你的消息;两台主机上的两个QQ进程就通过网络这同一份资源进行远距离通信。

今天我们是通过网络,对于双方而言:

  1. 数据首先要到达目标主机(IP)
  2. 找到指定的进程
  3. IP地址的是用来表示互联网中唯一的主机,端口号用来标识该指定的机器中进程的唯一性;因此IP加端口号可以用来表示互联网中唯一的一个进程。IP加端口就是套接字(socket)

端口号和进程ID的区别

端口号和进程ID是两个不同层次、不同领域的标识符。端口号用于网络通信中标识不同的应用程序或服务,而进程ID用于操作系统中标识不同的进程。在某些情况下,可以将端口号和进程ID关联起来,例如查看特定端口上运行的进程,但它们仍然是不同的概念。

注:一个进程可以有多个端口号,但是一个端口号只能代表一个进程

源端口号和目的端口号

  1. 源端口号(Source Port Number):源端口号是发送数据包的设备或主机上的应用程序或服务使用的端口号。在建立连接时,发送端的应用程序会随机选择一个空闲端口作为源端口号,并将其包含在发送的数据包中。源端口号帮助目标设备知道从哪个端口接收到了数据包,以便回复响应。

  2. 目的端口号(Destination Port Number):目的端口号是接收数据包的设备或主机上的应用程序或服务期望接收数据包的端口号。在发送数据包时,发送端会指定目标设备的IP地址和目标端口号。接收设备根据目的端口号确定将数据包传递给哪个应用程序或服务。

其实我们可以简单理解为:就是在描述 "数据是谁发的, 要发给谁"


认识TCP和UDP协议

我们先对TCP(Transmission Control Protocol 传输控制协议)、UDP(User Datagram Protocol 用户数据报协议)有一个直观的认识; 后面的文章我们再详细讨论TCP、UDP的一些细节问题.

TCP协议

  • 传输层协议
  • 有连接
  • 可靠传输
  • 面向字节流

UDP协议

  • 传输层协议
  • 无连接
  • 不可靠传输
  • 面向数据报 

网络字节序

我们已经知道,内存中的多字节数据相对于内存地址有大端和小端之分, 磁盘文件中的多字节数据相对于文件中的偏移地址也有大端小端之分, 网络数据流同样有大端小端之分. 那么如何定义网络数据流的地址呢?

  • 发送主机通常将发送缓冲区中的数据按内存地址从低到高的顺序发出;
  • 接收主机把从网络上接到的字节依次保存在接收缓冲区中,也是按内存地址从低到高的顺序保存;
  • 因此,网络数据流的地址应这样规定:先发出的数据是低地址,后发出的数据是高地址.
  • TCP/IP协议规定,网络数据流应采用大端字节序,即低地址高字节.
  • 不管这台主机是大端机还是小端机, 都会按照这个TCP/IP规定的网络字节序来发送/接收数据;
  • 如果当前发送主机是小端, 就需要先将数据转成大端; 否则就忽略, 直接发送即可;

为使网络程序具有可移植性,使同样的C代码在大端和小端计算机上编译后都能正常运行,可以调用以下库函数做网络字节序和主机字节序的转换。 

  • 这些函数名很好记,h表示host,n表示network,l表示32位长整数,s表示16位短整数。
  • 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;
  • 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。 

注:简单来说就是通过网络必须传送的是大端序,因此在传送之前不清楚自己主机是大端还是小端必须进行转换为大端序 


socket编程接口

socket常见API

// 创建 socket 文件描述符 (TCP/UDP, 客户端 + 服务器)
int socket(int domain, int type, int protocol);
// 绑定端口号 (TCP/UDP, 服务器)
int bind(int socket, const struct sockaddr *address,socklen_t address_len);
// 开始监听socket (TCP, 服务器)
int listen(int socket, int backlog);
// 接收请求 (TCP, 服务器)
int accept(int socket, struct sockaddr* address,socklen_t* address_len);
// 建立连接 (TCP, 客户端)
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);

网络编程的时候,socket是有很多分类的:

  • unix socket(域间套接字) :同一台机器上的文件路径,类似于命名管道,用于本主机内部进行通信
  • 网络socket:ip+port用于网络通信
  • 原始socket:跳过运输层,直接访问网络层;用于编写一些网络工具

sockaddr结构

网络编程的时候,有不同的应用场景,理论上而言我们应该给每一种场景都设计一套编程接口,但是设计者想使用一套接口,因此sockaddr是一个通用的接口;

sockaddr就相当与基类,当传入不同的类型是判断每个结构体的前两个字节进行类型的强转换。

IPv4和IPv6的地址格式定义在netinet/in.h中,IPv4地址用sockaddr_in结构体表示,包括16位地址类型, 16位端口号和32位IP地址.

IPv4、IPv6地址类型分别定义为常数AF_INET、AF_INET6. 这样,只要取得某种sockaddr结构体的首地址,不需要知道具体是哪种类型的sockaddr结构体,就可以根据地址类型字段确定结构体中的内容.
socket API可以都用struct sockaddr *类型表示, 在使用的时候需要强制转化成sockaddr_in; 这样的好处是程序的通用性, 可以接收IPv4, IPv6, 以及UNIX Domain Socket各种类型的sockaddr结构体指针做为参数; 

简单的UDP网络程序

UDP服务端

初始化服务器

创建套接字

int socket(int domain, int type, int protocol);

返回值

  • socket 函数的返回值代表了新创建的套接字的文件描述符,如果创建失败则返回 -1。
  • 在成功创建套接字后,socket 函数会返回一个非负整数,表示新创建的套接字的文件描述符。

参数

domain(地址族)

  • 类型:int
  • 意义:指定套接字的地址族,即通信所采用的协议族。
  • 常见取值:
    • AF_INET:IPv4 地址族。
    • AF_INET6:IPv6 地址族。
    • AF_UNIXAF_LOCAL:Unix 域(本地)套接字。

上面提到有三种套接字的分类,我们是网络套接字并且只介绍IPv4因此选择第一个取值

type(套接字类型)

  • 类型:int
  • 意义:指定套接字的类型,即套接字的通信模式。
  • 常见取值:
    • SOCK_STREAM:流套接字,提供可靠的、面向连接的、基于字节流的服务,使用 TCP 协议。
    • SOCK_DGRAM:数据报套接字,提供不可靠的、无连接的、基于数据报的服务,使用 UDP 协议。
    • SOCK_RAW:原始套接字,允许对底层协议进行直接访问,常用于网络监控和特殊应用。

 编写的是UDP服务器,因此选择第二个参数

protocol(协议)

  • 类型:int
  • 意义:指定套接字所使用的协议,通常为 0,表示使用默认的协议。
  • 对于 SOCK_STREAMSOCK_DGRAM 类型的套接字,协议通常可以省略,因为它们分别与 TCP 和 UDP 相关联。
  • 对于 SOCK_RAW 类型的套接字,可以指定底层的协议,如 IP、ICMP 等。

一般为0; 

填充本地网络信息

因为我们是网络套接字,因此需要一个struct sockaddr_in的结构体;将我们的IP地址、端口号和套接字类型填充到结构体中;

注:

  • 创建好结构体后需要对结构体里的内容清零
  • 填充端口号时我们要将我们的主机序列转为网络序列
  • 填充IP地址时我我们要将原始的点分十进制的字符串转换为四字节的网络序列
  • 我们不可以使用我们的服务器的IP地址作为我们程序的IP地址,下一步绑死后只能收到该IP发送的报文。
  • 我更推荐使用任意IP地址,INADDR_ANY 是一个特殊的 IP 地址,在网络编程中经常用于绑定套接字到本地计算机的所有网络接口上。
  • 具体来说,INADDR_ANY 表示接受任何来自本地计算机所有网络接口(包括所有网卡)的数据包。这在服务器编程中非常有用,因为服务器通常需要监听来自所有网络接口的连接请求。

绑定

上篇文章我们提到传输层作用于内核中,我们上一步填充的各种信息只存在于栈中,因此我们需要告诉操作系统内核,某个特定的套接字对应于网络上的某个地址。这个过程就是绑定;

int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

返回值

bind 函数的返回值代表了函数执行的结果,它通常有以下两种可能:

  1. 如果绑定成功,bind 函数返回值为 0。这表示套接字已成功绑定到指定的地址和端口上。

  2. 如果绑定失败,bind 函数返回值为 -1,并且会设置相应的错误码以指示失败的原因。这种情况可能

参数 

套接字描述符

  • 类型:int(整数)
  • 意义:要绑定的套接字的文件描述符。
  • 在调用绑定函数时,需要传递已经创建好的套接字的文件描述符。

地址结构指针

  • 类型:const struct sockaddr *
  • 意义:指向存储目标地址信息的结构体的指针。
  • 绑定函数需要知道要绑定的目标地址和端口号。通常使用的是 sockaddr 结构体或其派生结构体,如 sockaddr_in(IPv4 地址)或 sockaddr_in6(IPv6 地址)等。
  • 使用 const 关键字修饰指针,表示绑定函数不会修改该地址结构。

地址结构的长度

  • 类型:socklen_t(整数)
  • 意义:地址结构的长度。
  • 用于指定地址结构的实际长度,以确保绑定函数能够正确地解析地址结构。

启动服务器

收取消息

启动服务器就是启动一个程序且程序没收到特定的指令不退出,即就是一个死循环。

ssize_t recvfrom(int sockfd, void *buf, size_t len, 
                    int flags,struct sockaddr *src_addr, socklen_t *addrlen);

 recvfrom 函数用于从指定的套接字接收数据,并将数据存储到指定的缓冲区中,同时还可以获取数据发送方的地址信息。这个函数通常在使用 UDP 协议进行通信时使用,因为 UDP 是面向数据报的,每个数据包都有自己的源地址和目标地址。

返回值

recvfrom 函数的返回值是接收到的数据的字节数,即实际读取到缓冲区中的数据量。如果发生错误,返回值为 -1。

参数 

套接字描述符

  • 类型:int(整数)
  • 意义:要接收数据的套接字的文件描述符。
  • 在调用 recvfrom 函数时,需要传递已经创建好的套接字的文件描述符。

缓冲区指针

  • 类型:void *
  • 意义:指向存储接收数据的缓冲区的指针。
  • 接收到的数据将被存储到这个缓冲区中。

缓冲区大小

  • 类型:size_t(无符号整数)
  • 意义:缓冲区的大小,即接收数据的最大长度。
  • 在调用 recvfrom 函数之前,应该确保缓冲区足够大,以容纳接收到的数据。

标志

  • 类型:int(整数)
  • 意义:用于指定接收数据的选项。
  • 可以设置为 0,表示没有特殊的选项。

发送方地址结构指针

  • 类型:struct sockaddr *
  • 意义:用于存储发送方的地址信息的结构体指针。
  • 如果不需要获取发送方的地址信息,可以将这个参数设置为 NULL

发送方地址结构的长度指针

  • 类型:socklen_t *
  • 意义:发送方地址结构的长度。
  • 在调用 recvfrom 函数之前,需要将这个参数设置为一个指向长度变量的指针,用于接收实际的地址结构长度。

完整的服务端封装代码

Udpserver.hpp

#pragma once 
#include<iostream>
#include<string>
#include<sys/types.h>
#include<sys/socket.h>
#include<cerrno>
#include<unistd.h>
#include<cstring>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<strings.h>
using namespace std;
static const uint16_t defaultport = 8888;
static const int sockfd=-1;
static const int size=1024;
class UdpServer
{
public:
    UdpServer(uint16_t port=defaultport)
    :_port(port),_sockfd(sockfd)
    {
    }
    //初始化服务器
    void Init()
    {
        //创建套接字
        _sockfd = socket(AF_INET,SOCK_DGRAM,0);
        if(_sockfd<0)
        {
            //表示创建失败
            cout<<"Fatal Error"<<errno<<strerror(errno)<<endl;
            exit(2);
        }
        else{
            cout<<"socket success "<<"sockfd : "<<_sockfd<<endl;
        }
        //绑定套接字


        struct sockaddr_in local;
        //初始化local 
        //指定的一块内存清零
        bzero(&local,sizeof(local));
        //填充
        //进行网络通信
        local.sin_family = AF_INET;
        //端口号
        //转为网络序列
        local.sin_port = htons(_port);
        //1.4字节点分十进制字符串 2. 转为网络序列
        //local.sin_addr.s_addr = inet_addr(_ip.c_str());
        //使用地址任意
        //实现IP动态绑定
        local.sin_addr.s_addr = INADDR_ANY;
        //到此还没有设置到内核中,只存在于栈

        //绑定
        //强制类型转换
        int n = ::bind(_sockfd,(struct sockaddr*)&local,sizeof(local));
        if(n!=0)
        {
            cout<<"Fatal Error , bind error "<<errno<<" "<<strerror(errno)<<endl;
            exit(3);
        }
    }
    //启动服务器
    //服务器永远不退出
    //是一个死循环
    void Start()
    {
        //收发消息
        //返回值实际收到的消息
        //第一个参数为文件描述符
        //第二个
        //第三个为期望
        //第四个参数为收数据的模式通常设置为0 阻塞式
        //最后两个参数为输出型参数
        //保存我们客户端的信息 ip port
        char buffer[size];
        while(1)
        {
            //预留一个\0
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            
            ssize_t n = recvfrom(_sockfd,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&peer,&len);
            if(n>0)
            {
                //拿到客户端的信息
                //网络序列转主机序列
                uint16_t clientport = ntohs(peer.sin_port);
                string clientip = inet_ntoa(peer.sin_addr);

                string info = clientip;
                info+=":";
                info+=std::to_string(clientport);
                buffer[n]=0;
                cout<<"["<<info<<"]"<<buffer<<endl;
                //返回消息
                sendto(_sockfd,buffer,n,0,(struct sockaddr*)&peer,len);
            }
        }
    }
    ~UdpServer()
    {
        if(_sockfd!=-1)
        {
            close(_sockfd);
        }
    }
private:
    uint16_t _port;//端口号
    int _sockfd;
};

 Main.cc

#include<iostream>
#include<memory>
#include<string>
#include"Udpserver.hpp"
using namespace std;
enum comm
{
    Usage_Err=1
};
void Usage(string proc)
{
    cout<<"usage: \n\t"<<proc<<"locak_port"<<endl;
}
int main(int argc , char * argv[])
{
    //告诉如何使用
    if(argc!=2)
    {
        Usage(argv[0]);
        return Usage_Err;
    }
    // string ip = argv[1];
    uint16_t port= stoi(argv[1]);

    UdpServer* usvr  = new UdpServer(port);
    usvr->Init();
    usvr->Start();
    delete usvr;
    return 0;
}

UDP客户端

作为客户端我们一定知道服务端的IP和端口号,作为服务端IP和端口号是不可能随便改变的;

创建套接字

和服务端类似

填充服务端信息

和服务端类似

操作系统自动绑定

客户端不需要显示使用bind函数进行绑定,而是操作系统自动隐式绑定;因为如果客户端能够绑定特定的端口号,那么可能会导致端口冲突的问题。假设多个客户端应用都试图绑定到相同的固定端口号上,那么在同一台计算机上运行这些应用时就会发生冲突。为了避免这种情况,操作系统会自动为客户端分配一个可用的临时端口。

发送消息

ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

返回值

  • 如果成功,sendto 函数返回发送的字节数。这通常与 len 参数相同,但也可能更少(例如,如果套接字是非阻塞的,并且没有足够的缓冲区空间来容纳整个消息)。
  • 如果发生错误,sendto 函数返回 -1,并设置全局变量 errno 以指示错误类型。可能的错误包括 ECONNREFUSED(连接被拒绝)、EHOSTUNREACH(主机不可达)、EMSGSIZE(消息太大)、ENOBUFS(没有可用的缓冲区空间)等。

参数

sockfd这是一个打开的 socket 文件描述符,用于标识一个打开的 socket。

buf这是一个指向要发送数据的缓冲区的指针。

len这是要发送的数据的字节数。

flags这是可选的标志参数,可以用来指定不同的操作行为。常见的标志包括:

  • MSG_CONFIRM:告知底层传输层协议确认数据。
  • MSG_DONTROUTE:告知底层传输层协议不要路由数据。
  • MSG_EOR:表示发送的数据是一个消息的末尾。
  • 等等。具体的标志因操作系统和网络协议栈的不同而有所不同。

dest_addr这是一个指向目标地址信息的结构体的指针。它是一个 sockaddr 结构体,可以是 sockaddr_insockaddr_in6 结构体,具体取决于使用的网络协议版本。

addrlen这是目标地址结构体的大小,以字节为单位。通常情况下,它可以通过 sizeof(struct sockaddr) 来获取。

 客户端完整代码

Client.cc

#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <cerrno>
#include <string.h>
#include <string>
#include <unistd.h>
#include<arpa/inet.h>
#include<netinet/in.h>

using namespace std;
void Usage(const string &process) 
{
    cout<<"Usage : "<<process<<" server_ip server_port"<<endl;
}
int main(int argc, char*argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        return 1;
    }
    string serverip = argv[1];
    uint16_t serverport = stoi(argv[2]);
    int sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        cout << "socket error : " << strerror(errno) << endl;
        return 1;
    }
    cout << "socket success!" << endl;
    // 作为客户端必须知道服务器的ip和端口号

    // 作为客户端一定要进行绑定,但是不是显示绑定,客户端会在首次发送数据的时候进行自动绑定
    // 服务端端口号,一定是总所周知的不可改变的,
    // 客户端需要prot,绑定随机端口
    // why?
    // 因为客户端非常的多
    // 绑定确定的端口号,可能会在某一时刻启动失败
    // 让本地操作系统自动随机绑定,随机选择端口
    struct  sockaddr_in server;
    memset(&server,0,sizeof(server));
    server.sin_family =AF_INET;
    server.sin_port = htons(serverport);
    server.sin_addr.s_addr = inet_addr(serverip.c_str());
    // 发消息
    while (1)
    {
        //我们要发的数据
        string inbuffer;
        cout << "plase Entre#: ";
       std::getline(std::cin, inbuffer);
        //发给谁
        ssize_t n = sendto(sock,inbuffer.c_str(),inbuffer.size(),0,(struct sockaddr*)&server,sizeof(server));
        if(n>0) 
        {
            //收消息
            //UDP支持全双工通信
            char buffer[1024];
            struct sockaddr_in temp;
            socklen_t len = sizeof(temp);
            ssize_t m = recvfrom(sock,buffer,sizeof(buffer)-1,0,(struct sockaddr*)&temp,&len);
            if(m>0)
            {
                buffer[m]='\0';
                cout<<"server echo# "<<buffer<<endl;

            }
            else
            {
                break;
            }
        }
        else 
        {
            break;
        }
    }
    //套接字类型为文件描述符
    //使用结束后需要关闭
    close(sock);
    return 0;
}

一些补充

本地回环测试

我们可以让封装的服务端带上IP地址,使用127.0.0.1这个IP地址在本地的一台服务器上开上两个窗口启动服务端和客户端进行本地回环测试,检查代码和程序;上面的代码可以做到一些简单的交互联动。

netstat指令

netstat 命令,你可以查看本地计算机上的网络连接、路由表、网络接口统计信息等

常用选项

  • -a:显示所有连接和监听端口。
  • -t:显示 TCP 协议的连接。
  • -u:显示 UDP 协议的连接。
  • -l:显示监听状态的连接。
  • -n:以数字形式显示地址和端口。
  • -p:显示与连接相关的进程 ID。
  • -r:显示路由表。
  • -i:显示网络接口的统计信息。
  • -s:显示网络协议的统计信息。

今天对网络套接字的分享到这就结束了,希望大家读完后有很大的收获,也可以在评论区点评文章中的内容和分享自己的看法;个人主页还有很多精彩的内容。您三连的支持就是我前进的动力,感谢大家的支持!!! 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

selenium 4.x 之验证码处理(python)

验证码处理 一般情况公司如果涉及web自动化测试需要对验证码进行处理的方式一般有一下几种&#xff1a; 关闭验证码功能&#xff08;开发处理&#xff09;设置万能验证码&#xff08;开发处理&#xff09;使用智能识别库进行验证 通过第三方打码平台识别验证码 1. 跳过验证功…

Activity工作流基本知识点

1.概念 工作流(Workflow)&#xff0c;就是“业务过程的部分或整体在计算机应用环境下的自动化”&#xff0c;它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行&#xff0c;从而实现某个预期的业务目标&#xff0c;或者促使此目标的…

MySql#MySql数据库基础

目录 一、什么是数据库 二、主流数据库 三、基本使用 1.连接服务器 2.使用 1.查看你数据库 2.创建数据库 ​编辑 ​编辑 ​编辑​编辑 3.使用数据库 ​编辑 4.创建数据库表 5.表中插入数据 6.服务器&#xff0c;数据库&#xff0c;表之间的关系 四、MySQL架构…

AI图书推荐:AI在语言学习教育领域的应用和挑战

这本书《AI在语言学习教育领域的应用和挑战》&#xff08;AI in Language Teaching, Learning, and Assessment&#xff09;由Fang Pan编辑&#xff0c;出版于IGI Global&#xff0c;主要探讨了人工智能&#xff08;AI&#xff09;在语言教育领域的应用、挑战以及潜在的益处。 …

Vue踩坑,less与less-loader安装,版本不一致

无脑通过npm i less -D安装less之后&#xff0c;继续无脑通过npm i less-loader -D安装less-loader出现如下错误&#xff1a; 解决方法&#xff1a; 1) npm uninstall less与 npm uninstall less-loader 2) 直接对其版本&#xff1a; npm i less3.0.4 -D npm i less-loader…

Jackson 中使用 Optional

介绍 在本文中&#xff0c;我们会对 Optional 类进行一些说明&#xff0c;并且会解释下如果在使用 Optional 类的时候可能在 Jackson 中进行序列化和反序列化的过程中出现的问题。 针对上面的问题&#xff0c;本文会将会介绍在 Jackson 中如何处理 Optional 对象&#xff0c;…

vue2项目升级到vue3经历分享3

当初花了1个半月将十几个微服务从mybatis升级为mybatis-plus&#xff0c;就很自信的认为前端vue2升级到vue3也不过so so&#xff0c;世界过程中却是折腾&#xff0c;写法乱七八糟&#xff0c;不兼容的问题一大堆。 1 操作dom元素 this.$refs.subject[index].$children[0].$chil…

「 网络安全常用术语解读 」通用配置枚举CCE详解

1. 背景介绍 NIST提供了安全内容自动化协议&#xff08;Security Content Automation Protocol&#xff0c;SCAP&#xff09;为漏洞描述和评估提供一种通用语言。SCAP组件包括&#xff1a; 通用漏洞披露(Common Vulnerabilities and Exposures, CVE)&#xff1a;提供一个描述…

wordpress子比主题给文章内容加上密码查看

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、pandas是什么?二、使用步骤1.引入库2.读入数据第三步:文章内添加代码前言 提示:这里可以添加本文要记录的大概内容: 例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,…

乳制品粘性测试:操作流程详解

乳制品粘性测试&#xff1a;操作流程详解 在乳制品生产中&#xff0c;粘性测试是确保产品质量和口感的重要步骤。通过详细的操作流程&#xff0c;我们可以准确评估乳制品的粘性&#xff0c;为产品优化和品质控制提供有力支持。本文将详细介绍乳制品粘性测试的操作流程。 一、准…

应用层协议——http协议和https协议

目录 一、HTTP协议 1、概念 2、URL 二、HTTP协议格式 1、请求协议格式 2、响应协议格式 三、HTTP的请求方法 四、HTTP的状态码 五、HTTP常见的报头 六、HTTP和HTTPS 1、HTTPS协议 2、HTTPS的加密原理 1、基本概念 2、加密原理 通常我们程序员在网络编程的时候&am…

CSDN如何转载他人文章(超简单)

经常遇到一篇很好的文章&#xff0c;但是CSDN没有转载功能&#xff0c;所以需要我们自己处理一下。以谷歌浏览器打开某篇文章为例 一、按F12打开开发者工具 二、复制转载文章内容 按Ctrlf查找content_views&#xff0c;找到这一行<div id"content_views" class&…

2024项目拆解日均引流100+精准创业粉,全程干货

详情介绍 2024年项目拆解引流高质量创业粉&#xff0c;全程干货单日轻松引流100&#xff0c;项目拆解类视频本身引流效果就非常不错&#xff0c;视频内容针对性强直击创业粉内心&#xff0c;获客非常有效。做好视频钩子&#xff0c;和后端承接&#xff0c;赚钱没那么难。 课程…

没有精益管理内容的数字化,会是成功的数字化吗?

精益管理与数字化的结合被认为是制造业和企业管理中的一种重要转型策略。精益管理注重消除浪费、提升效率和质量&#xff0c;而数字化则通过技术手段来实现这一目标&#xff0c;两者的结合能够带来更高效、更智能的生产和管理方式。 首先&#xff0c;精益管理的核心理念是价值…

什么是HTTPS证书?怎么免费申请?——值得收藏

SSL证书的核心功能在于保障互联网数据传输的安全性和网站身份的可靠性。它通过加密通信防止信息被窃取或篡改&#xff0c;同时验证网站的真实身份&#xff0c;有效抵御钓鱼攻击&#xff0c;增强用户信任。此外&#xff0c;使用SSL证书还有助于提升网站在搜索引擎中的排名&#…

Docker 入门篇(六)-- idea 打包 docker 镜像流程

环境准备&#xff1a; idea 环境&#xff1a;IntelliJ IDEA 2021.3.1 (Ultimate Edition)docker 版本&#xff1a;v. 26.1.0准备 springboot jar 文件 &#xff1a;target/DockerDemo-0.0.1-SNAPSHOT.jardocker 可视化管理工具 portainer &#xff1a;v2.6.0 一. 配置docker远…

前端面试题大合集3----网络篇

一、Http协议详解&#xff0c;http请求方式&#xff0c;http状态码 Http协议详解&#xff1a; 全称Hyper Text Transfer Protocol&#xff0c;即超文本传输协议&#xff0c;是互联网上应用最为广泛的一种网络传输协议。 是一个无状态的应用层协议&#xff0c;即不会保存客户…

【管理咨询宝藏92】国际咨询公司为大型药企数字化转型项目规划方案

本报告首发于公号“管理咨询宝藏”&#xff0c;如需阅读完整版报告内容&#xff0c;请查阅公号“管理咨询宝藏”。 【管理咨询宝藏92】国际咨询公司为大型药企数字化转型项目规划方案 【格式】PDF版本 【关键词】国际咨询公司、药企转型、数字化转型 【核心观点】 - 企业业务…

51-48 CVPR 2024 | Vlogger: make your dream a vlog 自编剧制作视频博客

24年1月&#xff0c;上海交大、上海人工智能实验室、中科院联合发布Vlogger&#xff1a;make your dream a vlog。该论文主要工作是生成超过5分钟的视频博客vlog。鉴于现有文本到视频T2V生成方法很难处理复杂的故事情节和多样化的场景&#xff0c;本文提出了一个名为Vlogger的通…
最新文章