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

news2025/1/16 8:17:49

目录

理解源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.coloradmin.cn/o/1644563.html

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

相关文章

打造亚马逊爆款秘诀:流量、排名与自养号测评的完美结合

亚马逊是一个产品为王的平台&#xff0c;只要我们的产品好&#xff0c;就会有更多的流量&#xff0c;有流量还怕我们的产品卖不出去&#xff1f;身为新手我们店无流量该怎么办&#xff0c;今天教给你们五个获取流量的方法。 1.自然检索 那是我们常说的自然流量&#xff0c;通…

spring中的bean是线程安全的嘛

在Spring框架中&#xff0c;bean默认情况下不是线程安全的。Spring容器在初始化bean时&#xff0c;会为其创建一个单例实例&#xff0c;这个实例在整个应用中是唯一的&#xff0c;并且只会被初始化一次。由于这个特性&#xff0c;bean在默认情况下不是线程安全的。 然而&#…

在Ubuntu上安装docker

一、安装docker 更新系统包列表&#xff1a; sudo apt-get update安装必要的依赖软件包&#xff0c;使apt可以通过HTTPS使用repository。 sudo apt-get install apt-transport-https ca-certificates curl software-properties-common添加Docker的阿里云GPG密钥&#xff1a;…

WP Rocket插件下载:加速您的WordPress网站,提升用户体验

在互联网速度决定用户体验的今天&#xff0c;一个快速加载的网站对于吸引和保留访问者至关重要。WP Rocket插件&#xff0c;作为一款专为WordPress设计的高性能缓存插件&#xff0c;提供了一套完整的解决方案&#xff0c;帮助您优化网站性能&#xff0c;提升用户体验。 [WP Ro…

Begin 版本:2023/01/11 知更鸟WordPress主题优化版

主题下载地址&#xff1a;Begin主题优化版.zip 适用于博客、新闻、公司、图片、小说、文档、商城、资源下载、网址导航等多种类型网站

Redis 实战之客户端属性

客户端属性 套接字描述符名字标志输入缓冲区命令与命令参数命令的实现函数输出缓冲区身份验证时间总结 客户端状态包含的属性可以分为两类&#xff1a; 一类是比较通用的属性&#xff0c; 这些属性很少与特定功能相关&#xff0c; 无论客户端执行的是什么工作&#xff0c; 它们…

(二十一)springboot实战——Spring AI劲爆来袭

前言 本节内容是关于Spring生态新发布的Spring AI的介绍&#xff0c;Spring AI 是一个面向人工智能工程的应用框架。其目标是将 Spring 生态系统的设计原则&#xff0c;如可移植性和模块化设计&#xff0c;应用到人工智能领域&#xff0c;并推广使用普通的Java对象&#xff08…

DSN Injection(CVE-2022-3023)

DSN DSN通常指数据源名称&#xff08;Data Source Name&#xff09;&#xff0c;它被用于存储数据库连接信息&#xff0c;如数据库服务器的地址、数据库名、用户名以及密码等&#xff0c;以便软件能够利用这些信息连接到数据库。 DSN Injection DSN注入&#xff08;DSN Injecti…

Web安全:SQL注入漏洞详解,SQL注入常见功能、危害、分类、判断注入点、注入方式

「作者简介」&#xff1a;2022年北京冬奥会网络安全中国代表队&#xff0c;CSDN Top100&#xff0c;就职奇安信多年&#xff0c;以实战工作为基础对安全知识体系进行总结与归纳&#xff0c;著作适用于快速入门的 《网络安全自学教程》&#xff0c;内容涵盖系统安全、信息收集等…

nginx--rewrite

功能 Nginx服务器利用ngx_http_rewrite_module 模块解析和处理理rewrite请求&#xff0c;此功能依靠PCRE(Perl Compatible Regular Expressions)&#xff0c;因此编译之前要安装PCRE库&#xff0c;rewrite是nginx服务器的重要功能之一&#xff0c;用于实现URL的重写&#xff0…

上位机图像处理和嵌入式模块部署(树莓派4b下ros安装方法)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 随着嵌入式开发板算力越来越强&#xff0c;很多的同学开始用树莓派做一些ros开发的工作。目前来说&#xff0c;ros有两个版本&#xff0c;分别是ro…

ChatGPT 4.0 直接用 !!!Code Copilot编程大模型、DALL-E AI绘图、绘制流程图、上传文件

嗨&#xff0c;你好呀&#xff0c;我是哪吒。 这一年最让人揪心的热点&#xff0c;就是各种层出不穷的AI技术。 原以为它只是短暂霸屏&#xff0c;但现实却赤裸裸展示了&#xff0c;什么叫AI抢走你的饭碗&#xff0c;连招呼都不打一声! 什么策划方案、公众号文案、营销卖点、…

电脑切换窗口快捷键,让你轻松驾驭多个任务

在使用电脑时&#xff0c;经常需要切换不同的窗口&#xff0c;以便快速地访问不同的应用程序或任务。为了提高效率&#xff0c;掌握一些电脑切换窗口快捷键是非常重要的。本文将介绍三种在电脑上切换窗口的方法&#xff0c;帮助您更加高效地进行多任务处理。 方法1&#xff1a;…

SAP PP学习笔记11 - PP中的MRP相关概念,参数,配置

上文讲了作业区的概念及配置。 SAP PP学习笔记08 - 作业区&#xff08;工作中心Work Center&#xff09;&#xff0c;作业区Customize-CSDN博客 SAP PP学习笔记09 - 作业区&#xff08;工作中心Work Center&#xff09;Customize2&#xff08;管理码&#xff0c;班次顺序&…

菜鸡学习netty源码(五)—— EventLoop

1.EventLoop的类关系图 2. EventExecutor /*** 返回自身的对象* Returns a reference to itself.*/OverrideEventExecutor next();/*** 获取所属的EventExecutorGroup* Return the {link EventExecutorGroup} which is the parent of this {link EventExecutor},*/EventExecuto…

EPICS DataBase详解

1、分布式EPICS设置 1&#xff09; 操作界面&#xff1a;包括shell命令行方式(caget, caput, camonitor等)和图形界面方式(medm, edm, css等)。 2&#xff09;输入输出控制器(IOC) 2、IOC 1) 数据库&#xff1a;数据流&#xff0c;基本上周期运行 2)sequencer&#xff1a;基…

ThingsBoard如何接受设备通过TCP发送的报文

1、概述 2、案例 2.1、阐述 2.2、导入依赖 2.3、构建Netty服务链接&#xff0c;接受的端口为8092 2.4、对数据进行相应的处理发送到ThingsBoard客户端 2.5、通过TCP链接工具 ​2.6、查看遥测数据 1、概述 TCP&#xff08;Transmission Control Protocol&#xff0c;传输…

关于 c++的模板库中的数组模板 is_array_v的测试

&#xff08;1&#xff09;该模板的源代码如下&#xff1a; template <class> // determine whether type argument is an array bool is_array_v false;template <class _Ty, size_t _Nx> bool is_array_v<_Ty[_Nx]> true;template <class _Ty>…

屏蔽罩材质和厚度对屏蔽效能的影响

​ 一&#xff0e;屏蔽效能的影响因素 屏蔽效能的影响因素主要有两个方面&#xff1a;屏蔽材料的特性和厚度&#xff1b;如下图所示&#xff0c;电磁波经过不同媒介时&#xff0c;会在分界面形成反射&#xff0c;穿过界面的电磁波一部分被反射回去&#xff0c;这部分能量损失…