网络套接字编程(一)

网络套接字编程(一)

文章目录

  • 网络套接字编程(一)
    • 预备知识
      • 源IP地址和目的IP地址
      • 端口号
      • TCP/UDP协议特点
      • 网络字节序
    • socket编程
      • socket常用API
      • sockaddr结构
    • 简易UDP网络程序
      • 服务端创建套接字
      • 服务端绑定IP地址和端口号
      • 字符型IP地址VS整型IP地址
      • 服务端运行
      • 客户端创建套接字
      • 客户端绑定问题
      • 启动客户端
      • 程序测试

预备知识

源IP地址和目的IP地址

在IP数据包头部中, 有两个IP地址, 分别叫做源IP地址, 和目的IP地址。

源IP地址的作用是让接收方能够将数据返回过来。

目的IP地址的作用进行路由选择和确认数据是否传输到指定位置。

端口号

端口号

在了解端口号前要明确一些概念,首先,网络通信使得网络中的一台主机可以将数据传输给另一台主机,其目的是为了让多台主机协同完成工作。其次,在网络协议栈中由应用层产生数据,交付给下层进行传输。而网络应用层中产生数据的其实是进程,进程为了完成一个工作通过网络将数据交付给其他主机的进程,从而完成多个进程协同工作,因此网络通信的本质是进程间通信

如下图,客户端进程通过网络将数据传输给服务端进程,让服务端进程对所得到的数据进行处理,从而完成任务:

image-20231021152108069

既然,网络通信的本质是进程间通信,因此在网络传输时,必须知道数据要定位接收方进程,因此使用端口号定位主机中的一个进程,又因为IP地址能够定位网络中的一台主机,因此IP地址+端口号可以定位网络中的唯一一个进程。完整的IP中包含IP地址和端口号。

端口号(port)作为传输层协议的内容,其内容如下:

  • 端口号是一个2字节16位的整数。
  • 端口号用来标识一个进程, 告诉操作系统, 当前的这个数据要交给哪一个进程来处理。
  • IP地址 + 端口号能够标识网络上的某一台主机的某一个进程。
  • 一个进程可以绑定多个端口号; 但是一个端口号不能被多个进程绑定。

不采用进程PID定位进程而采用端口号的原因

网络的管理在操作系统中属于文件管理的范畴,而进程PID是属于进程管理的范畴,并且网络在文件管理中属于一个单独的模块,如果使用进程PID就会将网络管理和进程管理关联起来,会使得二者耦合度变高,不利于维护。

网络将数据交付给进程的原理

网络的管理在操作系统中属于文件管理的范畴,进程的管理属于进程管理的范畴,网络要将数据交给进程需要将数据加载到文件的缓冲区中,然后让进程使用文件操作读取缓冲区的内容,最终得到网络传输过来的数据。

TCP/UDP协议特点

应用层进程主要是从传输层获取网络传输的数据,传输层中有两种协议:TCP协议、UDP协议。

TCP协议特点

TCP(Transmission Control Protocol 传输控制协议):

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

注: 可靠传输是指使用TCP协议传输数据时,如果数据丢失了,会采用重传数据等策略保证接收端接收到数据。

UDP协议特点

UDP(User Datagram Protocol 用户数据报协议):

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

注: 不可靠传输是指使用UCP协议传输数据时,即使数据丢失了,也不会采取任何措施。

说明一下: 可靠传输和不可靠传输是TCP协议和UDP协议的特点,而不是优缺点,因为执行可靠传输一定要付出协议复杂,传输时间长等的代价,不可靠传输由于协议简单,会有传输时间短等的优点。

网络字节序

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

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

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

#include <arpa/inet.h>uint32_t htonl(uint32_t hostlong);
uint16_t htons(uint16_t hostshort);
uint32_t ntohl(uint32_t netlong);
uint16_t ntohs(uint16_t netshort);
  • 这些函数名很好记,h表示host(主机),n表示network(网络),l表示32位长整数,s表示16位短整数。
  • 例如htonl表示将32位的长整数从主机字节序转换为网络字节序,例如将IP地址转换后准备发送。
  • 如果主机是小端字节序,这些函数将参数做相应的大小端转换然后返回;。
  • 如果主机是大端字节序,这些函数不做转换,将参数原封不动地返回。

socket编程

socket常用API

#include <sys/types.h>         
#include <sys/socket.h>// 创建 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);

sockaddr结构

socket编程中用于定义网络地址的结构体种类分为struct sockaddr_instruct sockaddr_un,其中struct sockaddr_in用于IPv4网络,struct sockaddr_un用于Unix域(本地局域网),为了兼容两种结构体,采用struct sockaddr作为socket接口的参数,在接收参数时,会判断前16位地址类型是AF_INET还是AF_UNIX,区分使用的是那种结构体。

image-20231021165106439

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

sockaddr_in的结构:

struct sockaddr_in
{sa_family_t _sinfamily;//unsigned short int类型参数in_port_t sin_port;//端口号struct in_addr sin_addr;//IP地址//填充字段unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];
};typedef uint32_t in_addr_t;
struct in_addr
{in_addr_t s_addr;
};

简易UDP网络程序

为了更好的理解socket编程,编写一组简易的UDP网络程序,其包含客户端和服务端,客户端发送数据给服务端,服务端将接收的数据回传给客户端。

image-20231029184309956

服务端创建套接字

我们把服务器封装成一个类,当我们定义出一个服务器对象后需要马上初始化服务器,而初始化服务器需要做的第一件事就是创建套接字。创建套接字需要使用socket函数:

//socket函数所在的头文件和函数声明
#include <sys/types.h>
#include <sys/socket.h>int socket(int domain, int type, int protocol);
  • 该函数用于创建网络套接字。
  • domain参数: 指明数据传输域,传入AF_INET为网络通信,传入AF_UNIX为本地通信。
  • type函数: 指明套接字种类,传入SOCK_STREAM为流式套接,传入 SOCK_DGRAM 为数据报套接。
  • protocol参数: 指明所使用的协议,默认为0,该函数会自动识别所使用的协议。
  • 返回值: 调用成功返回一个文件描述符,调用失败返回-1,错误码被设置。

socket函数属于什么类型的接口?

在计算机软硬体系结构中,程序员编程形成程序都是在操作系统之上的用户层进行的,对应TCP/IP网络协议栈的应用层,因此,socket函数是操作系统提供属于应用层的系统接口。

socket函数底层做了什么?

socket函数是被引用层的进程所调用的,而每一个进程在系统层面上都有一个进程地址空间PCB(task_struct)、文件描述符表(files_struct)以及对应打开的各种文件。而文件描述符表里面包含了一个数组fd_array,其中数组中的0、1、2下标依次对应的就是标准输入、标准输出以及标准错误。
image-20231029171121435

在调用socket函数后,操作系统会为该进程创建该套接字对应的文件,将其记录在该进程的文件描述符表中:

image-20231029171516441

将数据写入该套接字对应的文件中,该文件刷新缓冲区的数据后,就会将数据写入网卡设备中,网卡会将数据传输出去。

image-20231029171611894

创建套接字

enum
{SOCKET_ERR=1
};
class UdpServer
{public:void InitServer(){//创建套接字_sock = socket(AF_INET, SOCK_DGRAM, 0);if (_sock < 0){std::cerr << "socket create error:" << strerror(errno) << std::endl;exit(SOCKET_ERR); }}private:int _sock; // 网络文件描述符
};

服务端绑定IP地址和端口号

现在套接字已经创建成功了,但作为一款服务器来讲,如果只是把套接字创建好了,那我们也只是在系统层面上打开了一个文件,操作系统将来并不知道是要将数据写入到磁盘还是刷到网卡,此时该文件还没有与网络关联起来。绑定IP地址和端口号需要使用bind函数:

//bind函数所在的头文件和函数声明
#include <sys/types.h>         
#include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
  • 该函数用于绑定套接字的IP地址和端口号。
  • sockfd参数: 要接收数据的套接字,即调用socket函数返回的文件描述符。
  • addr参数: 用于传入一个指向存有目标IP地址和端口号的sockaddr类型指针。
  • addlen参数: sockaddr类型变量的长度。
  • 返回值: 调用成功返回一个文件描述符,调用失败返回-1,错误码被设置。
  • 云服务不需要调用bind函数绑定指定IP地址,因为云服务可以存在多个网卡设备,需要让云服务自身制定IP地址。可以在将sockaddr类型中的IP地址字段赋值为INADDR_ANY让云服务绑定任意IP地址。

sockaddr_in的结构

前面提到了使用网络通信时,采用的sockaddr结构中的sockaddr_in结构,sockaddr_in具体的数据结构如下:

typedef unsigned short int sa_family_t;
typedef uint16_t in_port_t;typedef uint32_t in_addr_t;
struct in_addr
{in_addr_t s_addr;
};struct sockaddr_in
{sa_family_t _sinfamily;//unsigned short int类型参数in_port_t sin_port;//端口号struct in_addr sin_addr;//IP地址//填充字段unsigned char sin_zero[sizeof (struct sockaddr) -__SOCKADDR_COMMON_SIZE -sizeof (in_port_t) -sizeof (struct in_addr)];
};
  • _sinfamily: 标识该sockaddr结构要进行的是网络通信,还是本地通信.网络通信时赋值为AF_INET,本地通信时赋值为AF_UNIX.
  • sin_port: 16位无符号整型表示的端口号。
  • s_addr: 32位无符号正式表示的IP地址。

给进程绑定IP地址和端口号的原理

进程在应用层将要绑定的IP地址和端口号写入到对应的sockaddr结构中,然后调用操作系统提供的bind系统接口,让操作系统完成进程的IP地址和端口号的绑定工作。

本地端口号和网络字节序的转化

进程执行时定义一个无符号的16位整型port变量记录要绑定的端口号后,想要将其写入sockaddr结构前,需要调用系统提供的网络字节序接口htons接口,将port转换成符合网络字节序的16位端口号,完成网络字节序的转化后,才能将其写入sockaddr结构中,并使用其绑定端口号。

绑定IP地址和端口号

enum
{SOCKET_ERR = 1,BIND_ERROR
};
class UdpServer
{public:UdpServer(uint16_t port):_port(port) {}void InitServer(){// 创建套接字_sock = socket(AF_INET, SOCK_DGRAM, 0);if (_sock < 0){std::cerr << "socket create error:" << strerror(errno) << std::endl;exit(SOCKET_ERR);}// 绑定IP地址和端口号struct sockaddr_in local;//创建sockaddr结构写入IP地址和端口号memset(&local, 0, sizeof(local));local.sin_family = AF_INET;local.sin_addr.s_addr = INADDR_ANY;//云服务器IP地址赋值local.sin_port = htons(_port);socklen_t len = sizeof(local);int n = bind(_sock, (struct sockaddr*)&local, len);//端口号绑定if (n < 0){std::cerr << "bind error:" << strerror(errno) << std::endl;exit(BIND_ERROR);}}private:int _sock; // 网络文件描述符uint16_t _port;//端口号
};

字符型IP地址VS整型IP地址

IP地址是由 . 分割,由四个部分形成的,每个部分的取值范围位[0~255],如果使用字符型记录,至少需要12个字节(不记录.)也就是96个比特位,如果采用整型记录只需要4个字节,也就是32位,具体的记录方式是将一个4字节的无符号整形数据按照字节划分成4个部分,每个部分都占一个字节的空间,而一个字节的空间刚好能记录[0~255]的数据:

image-20231029182319364

操作系统提供了字符型IP地址和整形IP地址的转换函数,我们直接调用即可:

inet_addr函数

inet_addr函数的功能是将字符串IP转换成整数IP。

//inet_addr函数所在的头文件和函数声明
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
in_addr_t inet_addr(const char *cp);

该函数使用起来非常简单,我们只需传入待转换的字符串IP,该函数返回的就是转换后的整数IP。除此之外,inet_aton函数也可以将字符串IP转换成整数IP,不过该函数使用起来没有inet_addr简单。

inet_ntoa函数

inet_ntoa函数的功能是将整数IP转换成字符串IP。

//inet_ntoa函数所在的头文件和函数声明
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
char *inet_ntoa(struct in_addr in);

需要注意的是,传入inet_ntoa函数的参数类型是in_addr,因此我们在传参时不需要选中in_addr结构当中的32位的成员传入,直接传入in_addr结构体即可。

服务端运行

服务器运行起来后,需要完成从网络中接收数据和将数据回传给客户端的任务,接收数据需要用到recvfrom函数:

recvfrom函数

//recvfrom函数所在的头文件和函数声明
#include <sys/types.h>
#include <sys/socket.h>ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
  • 该函数的功能是从一个指定的套接字接收数据,并将数据存储到指定的缓冲区中。
  • sockfd参数: 要接收数据的套接字,即调用socket函数返回的文件描述符。
  • buf参数: 指向用来存储接收数据的缓冲区。
  • len参数: 缓冲区长度(即最多可以接收的字节数)。
  • flags参数: 用于控制recvfrom函数的行为,默认为0,阻塞读取。
  • src_addr参数: 存储发送方的地址信息(IP地址和端口号)的sockaddr类型变量的地址。
  • addrlen参数: 指向存放发送方地址信息的sockaddr类型变量的长度的变量的地址。
  • 返回值: 成功接收数据时,返回接收到的字节数。连接关闭时,返回0。发生错误时,返回-1,并设置errno变量以指示具体的错误原因。

服务端接受数据后要发送数据,发送数据需要使用sendto函数:

sendto函数

//sendto函数所在的头文件和函数声明
#include <sys/types.h>
#include <sys/socket.h>ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, 					   socklen_t addrlen);
  • 该函数的功能是将指定缓冲区中的数据发送到指定的套接字。
  • sockfd参数: 要发送数据的套接字,即调用socket函数返回的文件描述符。
  • buf参数: 指向要发送数据的缓冲区。
  • len参数: 要发送的数据长度(字节数)。
  • flags参数: 用于控制sendto函数的行为,默认为0。
  • dest_addr参数: 指定目标地址(即接收方的地址信息,包括IP地址和端口号)的sockaddr类型变量的指针。
  • addrlen参数: 指定目标地址信息的大小,即dest_addr的长度。
  • 返回值: 成功发送数据时,返回成功发送的字节数。发生错误时,返回-1,并设置errno变量以指示具体的错误原因。

启动服务器函数

启动服务器函数的功能让其从网络中接收数据,并将数据回传给客户端。

class UdpServer
{public:void StartServer()//服务端运行{char buffer[128];while (true){struct sockaddr_in peer;socklen_t len = sizeof(peer);//必须写明ssize_t n = recvfrom(_sock, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);if (n > 0){buffer[n] = 0;}elsecontinue;std::string clientip = inet_ntoa(peer.sin_addr);uint16_t clientport = ntohs(peer.sin_port);std::cout << clientip << "-" << clientport << "send#" << buffer << std::endl;sendto(_sock, buffer, strlen(buffer), 0, (struct sockaddr *)&peer, len);}}private:int _sock; // 网络文件描述符uint16_t _port;//端口号
};

recvfrom函数接收sockaddr结构

recvfrom函数使用sockaddr结构从网络中接收数据时,就是按照网络字节序接收的,因此再交给sendto函数发送数据时,无需进行网络字节序的转化。

缓冲区问题

使用buffer缓冲区从网络中接收数据时,按照C语言规定需要为缓冲区预留一个字节用于存储’\0’。

使用buffer缓冲区向网络中发送数据时,无需发送’\0’,因为那是C语言的规定不是网络的规定。

recvfrom函数接收数据时会将网络字节序转换为主机序列写入缓冲区,sendto函数向网络发送数据时会将缓冲区数据从主机序列转换成网络字节序发送。

运行服务端

调用服务端类内部的函数进行服务端的初始化,并启动服务端。为了给错误启动服务端纠错,引入了命令行参数,在启动服务端时做纠错提示:

void Usage(const char *proc)
{std::cout << "Usage:\n\t" << proc << "port\n" << std::endl;
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);}uint16_t port = atoi(argv[1]);std::unique_ptr<UdpServer> ustr(new UdpServer(port));ustr->InitServer();ustr->StartServer();return 0;
}

启动服务端

启动服务端后,使用netstat -naup指令查看服务端进程信息:

image-20231030143051235

客户端创建套接字

同样的,将客户端封装成类,在使用客户端时,只需要创建类对象,然后调用对应的函数即可使用客户端。在创建客户端类对象后的第一步就是初始化客户端,在初始化客户端时,首先就需要创建套接字:

enum
{SOCKET_ERR = 1,BIND_ERROR
};
class Udp_Client
{public:void InitClient(){//创建套接字_sock = socket(AF_INET, SOCK_DGRAM, 0);if (_sock < 0){std::cerr << "socket create error:" << strerror(errno) << std::endl;exit(SOCKET_ERR);}}private:int _sock;
};

客户端绑定问题

使用socket进行网络通信,是需要通过IP地址和端口号确定唯一进程,然后再进行通信的,客户端如果不进行IP地址和端口号的绑定,服务端就无法将数据再回传给客户端,因此客户端是一定需要绑定IP地址和端口号的。

一台主机上会存在大量的客户端进程,如果每个客户端进程都要指定绑定端口号,可能会因为客户端端口号冲突造成客户端启动失败的问题,并且客户端只要能够实现和服务端进行网络通信的功能即可,端口号的具体值并不重要,因此客户端不能绑定指定的端口号,需要让操作系统来完成客户端端口号的绑定。

服务端是给众多客户端提供网络服务的,服务端的端口号如果随意改变,客户端就会因为服务端的端口号的改变导致无法找到服务端。因此服务端的端口号一定需要自主绑定。

客户端在首次调用发送数据的系统调用时,操作系统会自动选择端口号和自身的IP地址绑定到客户端。

启动客户端

运行客户端函数

运行客户端函数的功能是接受用户输入的数据将其发送给服务端,然后接受服务端回传的数据。

class Udp_Client
{public:Udp_Client(std::string serverip, uint16_t serverport):_serverip(serverip), _serverport(serverport){}void StartClient(){while(true){std::cout << "Please enter message#";std::string message;getline(std::cin, message);struct sockaddr_in peer;//指明服务端IP地址和端口号peer.sin_family = AF_INET;peer.sin_addr.s_addr = inet_addr(_serverip.c_str());peer.sin_port = htons(_serverport);sendto(_sock, message.c_str(), message.size(), 0, (struct sockaddr*)&peer, sizeof(peer));struct sockaddr_in temp;socklen_t tlen;char buffer[128];ssize_t n = recvfrom(_sock, buffer, sizeof(buffer)-1, 0, (struct sockaddr*)&temp, &tlen);if (n > 0){buffer[n] = 0;std::cout << "server echo:" << buffer << std::endl;}}}private:int _sock;std::string _serverip;uint16_t _serverport;
};

revfrom函数的注意事项

recvfrom函数最后两个参数src_addr,addrlen都是输出型参数,在函数中会进行赋值操作,因此不能传空指针。

启动客户端

和服务端相同,调用客户端类内部的函数进行客户端的初始化,并启动客户端。为了给错误启动客户端纠错,引入了命令行参数,在启动客户端时做纠错提示:

void Usage(const char *proc)
{std::cout << "Usage:\n\t" << proc << "port\n" << std::endl;
}int main(int argc, char *argv[])
{if (argc != 2){Usage(argv[0]);exit(USAGE_ERROR);}uint16_t port = atoi(argv[1]);std::unique_ptr<UdpServer> ustr(new UdpServer(port));ustr->InitServer();ustr->StartServer();return 0;
}

程序测试

本地测试

现在服务端和客户端的代码都已经编写完毕,我们可以先进行本地测试,此时服务器没有绑定外网,绑定的是本地环回。现在我们运行服务器时指明端口号为8080,再运行客户端,此时客户端要访问的服务器的IP地址就是本地环回127.0.0.1,服务端的端口号就是8080。

image-20231030160930214

客户端运行之后提示我们进行输入,当我们在客户端输入数据后,客户端将数据发送给服务端,此时服务端再将收到的数据打印输出,这时我们在服务端的窗口也看到我们输入的内容。

image-20231030160726907

此时我们再用netstat命令查看网络信息,可以看到服务端的端口是8080,客户端的端口是。这里客户端能被netstat命令查看到,说明客户端也已经动态绑定成功了,这就是我们所谓的网络通信。

image-20231030161029355

网络测试

网络测试和本地测试的方式类似,只是网络测试输入的IP地址得是服务端的IP地址:

image-20231030162533334

不同于本地测试的是,可以使用其他主机访问该服务端,只需要让其他主机获取该客户端程序,然后在其他主机运行客户端时输入服务端IP地址和端口号即可完成网络通信。

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

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

相关文章

mfc140u.dll丢失怎么修复,mfc140u.dll文件有什么作用

今天我想和大家分享的是关于mfc140u.dll文件丢失的解决方法。在我们使用电脑的过程中&#xff0c;有时候会遇到一些错误提示&#xff0c;其中比较常见的就是“无法找到mfc140u.dll文件”。那么&#xff0c;这个文件是什么呢&#xff1f;它有什么作用呢&#xff1f; 首先&#…

网络基础-2

IEEE制定了一个名为GARP的协议框架&#xff0c;该框架协议包含了两个具体协议&#xff0c;GMRP和GVRP。GVRP可以大大降低VLAN配置过程中的手工的工作量。 IP本身是一个协议文件的名称&#xff0c;该协议主要定义阐释了IP报文的格式。 类型网络号位数网络号个数主机号位数每个…

水溶性纳米银颗粒 纳米银颗粒 银纳米颗粒溶液

西&#xff09;产品名称&#xff1a;水溶性纳米银颗粒 安&#xff09;别名 &#xff1a;纳米银溶液 银纳米颗粒溶液 纳米银胶体等 瑞&#xff09;浓度&#xff1a;0.1mg/mL 其它均可定制 禧&#xff09;粒径&#xff1a;5nm 10nm 15nm 20nm 25nm 30nm 35nm 40nm 50nm 60nm 80…

1.6 基本安全设计准则

思维导图&#xff1a; 1.6 基本安全设计准则笔记 目标&#xff1a;理解和遵循一套广泛认可的安全设计准则&#xff0c;以指导保护机制的开发。 主要准则&#xff1a; 机制的经济性&#xff1a;安全机制应设计得简单、短小&#xff0c;便于测试和验证&#xff0c;减少漏洞和降…

【数据结构】顺序表实例探究

&#x1f497;个人主页&#x1f497; ⭐个人专栏——数据结构学习⭐ &#x1f4ab;点击关注&#x1f929;一起学习C语言&#x1f4af;&#x1f4ab; 目录 导读&#xff1a;1. 顺序表的基本内容1.1 概念及结构1.2 时间和空间复杂度1.3 基本操作1.4 顺序表的优缺点 2. 静态顺序表…

自动化测试注意事项

什么是自动化测&#xff1f; 做测试好几年了&#xff0c;真正学习和实践自动化测试一年&#xff0c;自我感觉这一个年中收获许多。一直想动笔写一篇文章分享自动化测试实践中的一些经验。终于决定花点时间来做这件事儿。 首先理清自动化测试的概念&#xff0c;广义上来讲&#…

华锐技术何志东:证券核心交易系统分布式改造将迎来规模化落地阶段

近年来&#xff0c;数字化转型成为证券业发展的下一战略高地&#xff0c;根据 2021 年证券业协会专项调查结果显示&#xff0c;71% 的券商将数字化转型列为公司战略任务。 在落地数字化转型战略过程中&#xff0c;证券业核心交易系统面临着不少挑战。构建新一代分布式核心交易…

06 MIT线性代数-线性无关,基和维数Independence, basis, and dimension

1. 线性无关 Independence Suppose A is m by n with m<n (more unknowns than equations) Then there are nonzero solutions to Ax0 Reason: there will be free variables! A中具有至少一个自由变量&#xff0c;那么Ax0一定具有非零解。A的列向量可以线性组合得到零向…

酷克数据出席永洪科技用户大会 携手驱动商业智能升级

10月27日&#xff0c;第7届永洪科技全国用户大会在北京召开。酷克数据作为国内云原生数仓代表企业&#xff0c;受邀出席本次大会&#xff0c;全面展示了云数仓领域最新前沿技术&#xff0c;并进行主题演讲。 携手合作 助力企业释放数据价值 数据仓库是商业智能&#xff08;BI…

Easy Javadoc插件的使用教程

目录 一、安装Easy Javadoc插件 二、配置注释模板 三、配置翻译 一、安装Easy Javadoc插件 在idea的File-Settings-Plugins中搜索Easy Javadoc插件&#xff0c;点击install进行安装&#xff0c;安装完成后需要restart IDE&#xff0c;重启后插件生效。 二、配置注释模板 …

openGauss学习笔记-111 openGauss 数据库管理-管理用户及权限-用户权限设置

文章目录 openGauss学习笔记-111 openGauss 数据库管理-管理用户及权限-用户权限设置111.1 给用户直接授予某对象的权限111.2 给用户指定角色111.3 回收用户权限 openGauss学习笔记-111 openGauss 数据库管理-管理用户及权限-用户权限设置 111.1 给用户直接授予某对象的权限 …

SIT3088E3.0V~5.5V 供电,ESD 15kV HBM,256 节点,14Mbps 半双工 RS485/RS422 收发器

SIT3088E 是一款 3.0V~5.5V 宽电源供电、总线端口 ESD 保护能力 HBM 达到 15kV 以上、总 线耐压范围达到 15V 、半双工、低功耗&#xff0c;功能完全满足 TIA/EIA-485 标准要求的 RS-485 收发器。 SIT3088E 包括一个驱动器和一个接收器&#xff0c;两者均可独立…

SpringCloud 微服务全栈体系(七)

第九章 Docker 一、什么是 Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署&#xff0c;环境不一定一致…

MySQL系列-架构体系、日志、事务

MySQL架构 server 层 &#xff1a;层包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&#xff08;如日期、时间、数学和加密函数等&#xff09;&#xff0c;所有跨存储引擎的功能都在这一层实现&am…

行情分析——加密货币市场大盘走势(10.31)

目前大饼依然在33000-36000这个位置震荡&#xff0c;需要等待指标修复&#xff0c;策略就是逢低做多&#xff0c;做短线。最近白天下跌&#xff0c;晚上涨回来&#xff0c;可以小仓位入场多单&#xff0c;晚上离场下车。 以太同样是震荡行情&#xff0c;看下来以太目前在补涨&a…

Mybatis—基础操作

mybatis入门后&#xff0c;继续学习mybatis基础操作。 目录 Mybatis基础操作准备工作删除操作日志输入预编译SQLSQL注入参数占位符 新增操作基本新增添加后返回主键 更新操作查询操作根据id查询数据封装条件查询条件查询 Mybatis基础操作 准备工作 根据下面页面原型及需求&am…

【云原生-K8s】Kubernetes安全组件CIS基准kube-beach安装及使用

基础介绍kube-beach介绍kube-beach 下载百度网盘下载wget下载 kube-beach安装kube-beach使用基础参数示例结果说明 基础介绍 为了保证集群以及容器应用的安全&#xff0c;Kubernetes 提供了多种安全机制&#xff0c;限制容器的行为&#xff0c;减少容器和集群的攻击面&#xf…

记录一次修改虚拟机静态ip的坑-与docker有关

修改虚拟机静态ip的坑&#xff08;与docker有关&#xff09; 由于我换了个移动wifi&#xff0c;我想把自己电脑上的虚拟机的静态ip也更改一下&#xff0c;但是改完静态ip之后我发现我可以ping得通我的虚拟机ip&#xff0c;但是用telnet命令访问我的3306端口却访问不通了&#x…

SpringBoot整合阿里云OSS对象存储

文章目录 1、OSS介绍及开通1.1、阿里云OSS简介1.2、开通OSS 2、创建存储空间bucket及密钥获取2.1、创建存储空间2.2、获取密钥 3、OSS快速入门案例4、在springboot项目中整合4.1、将oss配置放到yml文件中4.2、创建Oss属性类&#xff0c;接收yml文件中的属性4.3、封装文件上传功…

近期面试小结

作者&#xff1a;究极逮虾户 最近面试了不少的公司&#xff0c;行情整体来说还是非常差的&#xff0c;如果没有必要不建议大家裸辞&#xff0c;另外就不总结面试的题目了。这次打算着重从项目经验上来给大家讨论下&#xff0c;我觉得这部分可能才是面试中得分比重比较大的部分&…