linux socket套接字

文章目录

    • socket
      • 流socket(TCP)
      • 数据报socket(UDP)
    • 讨论

socket

  • 所谓套接字,就是对网络中不同主机上的应用程序之间进行双向通信的端点的抽象。一个套接字就是网络上进程通信的一端,套接字提供了应用层进程利用网络协议交换数据的机制。
  • 从所处的位置来看,套接字上连应用进程,下连网络协议栈,是应用程序通过网络协议进程通信的接口,是引用程序与网络协议进行交互的接口。
  • 套接字是网络环境中进行通信的api,使用中每一个套接字都有一个与之相联的进程,通信时其中一个网络应用程序将要传输的一段信息写入他所在的主机socket中,该socket通过与网络接口卡NIC相连的传输介质将这段信息送到另一台主机的socket中,使得双方能够接收到这段信息。
  • socket是IP地址与端口的结合
  • socket是全双工的,同一时刻既可以输入数据也可以输出数据

在这里插入图片描述

流socket(TCP)

在这里插入图片描述

struct sockaddr{
	sa_family_t sa_family;		
	char        sa_data[14];	
}

struct sockaddr_in{			//IPv4 socket address
	sa_family_t  sin_family;	//Address family(AF_INET)
	in_port_t    sin_port;		//Port number
	struct in_addr sin_addr;	//IPv4 addreddr{				//IPv4 4-byte address
	in_addr_t s_addr;		//unsigned 32-bit integer
};
//server.c
#include<stdio.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>

#define PORT_ID 6666
#define SIZE 100

int main(){
	int sockfd,client_sockfd;
	struct sockaddr_in my_addr,client_addr;
	int addr_len;
	char welcome[SIZE]="welcome to connect to the server!";

	//初始化服务器的地址
	my_addr.sin_family=AF_INET;//协议族
	my_addr.sin_port=htons(PORT_ID);//端口
	my_addr.sin_addr.s_addr=INADDR_ANY;//可以接受任意客户端访问

	//创建socket
	sockfd=socket(AF_INET,SOCK_STREAM,0);
	
	//绑定socket---服务器用
	bind(sockfd,(struct sockaddr*)&my_addr,sizeof(struct sockaddr));
	
	//监听客户端访问,队列最大为10---TCP服务器用
	listen(sockfd,10);

	addr_len=sizeof(struct sockaddr);
	while(1){
		printf("server is waiting for client to connect:\n");
		//允许并接受客户端的访问
		client_sockfd=accept(sockfd,(struct sockaddr*)&client_addr,&addr_len);

		printf("client IP address id %s\n",inet_ntoa(client_addr.sin_addr));
		send(client_sockfd,welcome,SIZE,0);//TCP发送数据
		printf("disconnect the client request.\n");
		close(client_sockfd);
	}
	close(sockfd);
	return 0;

}

头文件:#include<sys/socket.h>

int socket(int domain,int type, int protocol):创建一个空的套接字描述符,如果成功,返回的是套接字描述符,如果失败返回-1。该函数有三个参数,第一个domain表示使用的协议族,AF_UNIX表示使用UNIX域套接字协议,AF_INET决定了要用ipv4地址(32位的)与端口号(16位的)的组合、AF_UNIX决定了要用一个绝对路径名作为地址;第二个参数type致命socket的类型,一般有三种:SOCK_STREAM表示使用TCP类型,保证数据顺序以及可靠性连接;SOCK_DGRAM表示使用UDP类型,不保证呢个数据接收的顺序,非可靠连接;SOCK_RAW表示原始类型,允许对底层协议如IP或者ICMP进行直接访问,不常用;最后一个参数通常赋值为0,由字体自动选择。
socket的返回值有两个用途,对于服务器,返回的套接字描述符作为调用accept的参数接收客户端的链接请求,它不是用来进行应用数据通信的;对于客户端而言,客户端对它的调用connect发起三次我搜,并且通过它进行后续的应用数据通信。

int bind(int sockfd, const struct sockaddr* myaddr, socklen_t addrlen):将创建的socket绑定到指定的IP地址和端口上,通常是第二个调用的socket接口。返回值:0 – 成功,-1 – 出错。当socket函数返回一个描述符时,只是存在于其协议族的空间中,并没有分配一个具体的协议地址(这里指IPv4/IPv6和端口号的组合),bind函数可以将一组固定的地址绑定到sockfd上。该函数有三个参数:sockfd表示socket函数返回的描述符;myaddr致命要绑定的本地IP和端口号,使用大端模式;addrlen常被设置为sizeof(struct sockaddr)。
通常服务器在启动的时候都会绑定一个众所周知的协议地址,用于提供服务,客户就可以通过它来接连服务器;而客户端可以指定IP或端口也可以都不指定,未分配则系统自动分配。这就是为什么通常服务器端在listen之前会调用bind(),而客户端就不会调用,而是在connect()时由系统随机生成一个

int listen(int sockfd, int backlog):listen()函数仅被TCP类型的服务器程序调用,实现监听服务,它实现2件事情:①当socket()创建1个socket时,被假设为主动式套接字,也就是说它是一个将调用connect()发起连接请求的客户端套接字;函数listen()将套接口转换为被动式套接字,指示内核接受向此套接字的连接请求,调用此系统调用后tcp 状态机由close转换到listen②第2个参数指定内核为此套接字维护的最大连接个数,包括“未完成连接队列–未完成3次握手”、“已完成连接队列–已完成3次握手,建立连接”。大多数系统缺省值为20。
listen()成功时返回0,错误时返回-1。

int accept (int sockfd, struct sockaddr *addr, socklen_t *addrlen):accept()函数仅被TCP类型的服务器程序调用,从已完成连接队列返回下一个建立成功的连接,如果已完成连接队列为空,线程进入阻塞态睡眠状态。成功时返回套接字描述符,错误时返回-1。sockfdsocket()函数返回的描述符;addr输出一个的sockaddr_in变量地址,该变量用来存放发起连接请求的客户端的协议地址;addrten作为输入时指明缓冲器的长度,作为输出时指明addr的实际长度;
如果accpet()执行成功,返回由内核自动生成的一个全新socket描述符,用它引用与客户端的TCP连接。通常我们把accept()第一个参数成为监听套接字(listening socket),把accept()功能返回值成为已连接套接字(connected socket)。一个服务器通常只有1个监听套接字,监听客户端的连接请求;服务器内核为每一个客户端的TCP连接维护1个已连接套接字,用它实现数据双向通信。

//client.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>

#define PORT_ID 6666
#define SIZE    100

int main(int argc,char *argv[]){
	int sockfd;
	struct sockaddr_in server_addr;
	char buf[SIZE];

	if(argc<2){
		printf("Uage:./client [server IP address]\n");
		exit(1);
	}

	//创建
	sockfd=socket(AF_INET,SOCK_STREAM,0);

	server_addr.sin_family=AF_INET;
	server_addr.sin_port=htons(PORT_ID);//将整型变量从主机字节顺序转变成网络字节顺序,因为这里是大端模式
	server_addr.sin_addr.s_addr=inet_addr((argv[1]));//inet_addr是一个计算机函数,功能是将一个点分十进制的IP转换成一个长整型数(u_long类型)

	//TCP连接,三次握手
	connect(sockfd,(struct sockaddr*)&server_addr,sizeof(struct sockaddr));
	
	//接收数据
	recv(sockfd,buf,SIZE,0);
	printf("client receive from server:%s\n",buf);

	close(sockfd);
	return 0;

}

int connect(int sockfd, struct sockaddr *serv_addr, int addrlen):connect()通常由TCP类型客户端调用,用来与服务器建立一个TCP连接,实际是发起3次握手过程,连接成功返回0,连接失败返回1。sockfd :本地客户端的socket描述符;serv_addr: 服务器协议地址;addrlen :地址缓冲区的长度;
注意:
(1) 可以在UDP连接使用使用connect(),作用是在UDP套接字中记住目的地址和目的端口。
(2) UDP套接字使用connect后,如果数据报不是connect中指定的地址和端口,将被丢弃。没有调用connect的UDP套接字,将接收所有到达这个端口的UDP数据报,而不区分源端口和地址。

int send(int sockfd, const void *msg, int len, int flags):TCP类型的数据发送。sockfd :发送端套接字描述符(非监听描述符)。msg :待发送数据的缓冲区。len : 待发送数据的字节长度。flags : 一般情况下置为0。
每个TCP套接口都有一个发送缓冲区,它的大小可以用SO_SNDBUF这个选项来改变。调用send函数的过程,实际是内核将用户数据拷贝至TCP套接口的发送缓冲区的过程:若len大于发送缓冲区大小,则返回-1;否则,查看缓冲区剩余空间是否容纳得下要发送的len长度,若不够,则拷贝一部分,并返回拷贝长度(指的是非阻塞send,若为阻塞send,则一定等待所有数据拷贝至缓冲区才返回,因此阻塞send返回值必定与len相等);若缓冲区满,则等待发送,有剩余空间后拷贝至缓冲区;若在拷贝过程出现错误,则返回-1。关于错误的原因,查看errno的值。
如果send在等待协议发送数据时出现网络断开的情况,则会返回-1。注意:send成功返回并不代表对方已接收到数据,如果后续的协议传输过程中出现网络错误,下一个send便会返回-1发送错误。TCP给对方的数据必须在对方给予确认时,方可删除发送缓冲区的数据。否则,会一直缓存在缓冲区直至发送成功(TCP可靠数据传输决定的)。

int recv(int sockfd, void *buf, int len, unsigned int flags):TCP类型的数据接收。sockefd :接收端套接字描述符(非监听描述符);buf : 接收缓冲区的基地址;len : 以字节计算的接收缓冲区长度;flags :一般情况下置为0。
recv()从接收缓冲区拷贝数据。成功时,返回拷贝的字节数,失败返回-1。阻塞模式下,recv/recvfrom将会阻塞到缓冲区里至少有一个字节(TCP)/至少有一个完整的UDP数据报才返回,没有数据时处于休眠状态。若非阻塞,则立即返回,有数据则返回拷贝的数据大小,否则返回错误-1。

运行结果:
[cch@aubin socket]$ ./server
server is waiting for client to connect:
client IP address id 192.168.100.120
disconnect the client request.
server is waiting for client to connect:
client IP address id 192.168.100.120
disconnect the client request.
server is waiting for client to connect:


[cch@aubin socket]$ ./client 192.168.100.120
client receive from server:welcome to connect to the server!
[cch@aubin socket]$ ./client 192.168.100.120
client receive from server:welcome to connect to the server!
[cch@aubin socket]$ 

数据报socket(UDP)

在这里插入图片描述

//server
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>

#define PORT_ID 6666
#define SIZE    100

int main(void)
{
	int sockfd, client_sockfd;
	struct sockaddr_in my_addr, client_addr;
	int addr_len;
	char buf[SIZE];
	char welcome[SIZE] = "Welcome to connect to the sever!";
	//init my_addr
	my_addr.sin_family = AF_INET;
	my_addr.sin_port = htons(PORT_ID);
	my_addr.sin_addr.s_addr = INADDR_ANY;	//any ip addr 
	//创建socket
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);//create a socket
	//绑定socket
	bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr));
	addr_len = sizeof(struct sockaddr);

	while(1)
	{
		printf("Server is waiting for client to connect:\n");
		//接收信息
		recvfrom(sockfd, buf, SIZE, 0, (struct sockaddr *)&client_addr, &addr_len);
		printf("Server receive ip is %s, receive data is %s\n", inet_ntoa(client_addr.sin_addr) ,buf);
	}
	//关闭socket
	close(sockfd);
	return 0;

}
//client
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#include <stdlib.h>
#define PORT_ID 6666
#define SIZE    100
int main(int argc, char *argv[])
{
	int sockfd;
	struct sockaddr_in server_addr;
	char buf[SIZE];
	int i;
	if(argc < 2)
	{
		printf("Usge:./client [server IP address]\n");
		exit(1);
	}
	//创建socket
	sockfd = socket(AF_INET, SOCK_DGRAM, 0);//create a socket
	//输入服务器地址
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT_ID);
	server_addr.sin_addr.s_addr =inet_addr((argv[1]));

	for(i = 0; i < 5; i++)
	{
		sprintf(buf, "%d\n", i);
		//发送数据
		sendto(sockfd, buf, SIZE, 0, (struct sockaddr *)&server_addr, sizeof(struct sockaddr));
		printf("Client sends to server %s: %s\n", argv[1], buf);
		sleep(1);
	}
	//关闭socket
	close(sockfd);
	return 0;
}

int sendto(int sockfd, const void *msg, int len, unsigned int flags, const struct sockaddr *dst_addr, int addrlen):用于非可靠连接(UDP)的数据发送,因为UDP方式未建立连接socket,因此需要制定目的协议地址。sockfd :发送端套接字描述符(非监听描述符);msg:待发送数据的缓冲区;len :待发送数据的字节长度;flags : 一般情况下置为0;dst_addr :数据发送的目的地址;addrlen : 地址长度。
当本地与不同目的地址通信时,只需指定目的地址,可使用同一个UDP套接口描述符sockfd,而TCP要预先建立连接,每个连接都会产生不同的套接口描述符,体现在:客户端要使用不同的fd进行connect,服务端每次accept产生不同的fd。
因为UDP没有真正的发送缓冲区,因为是不可靠连接,不必保存应用进程的数据拷贝,应用进程中的数据在沿协议栈向下传递时,以某种形式拷贝到内核缓冲区,当数据链路层把数据传出后就把内核缓冲区中数据拷贝删除。因此它不需要一个发送缓冲区。写UDP套接口的sendto/write返回表示应用程序的数据或数据分片已经进入链路层的输出队列,如果输出队列没有足够的空间存放数据,将返回错误ENOBUFS.

int recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, int*fromlen):用于非可靠连接(UDP)的数据接收。sockfd :接收端套接字描述;buf : 用于接收数据的应用缓冲区地址;len: 指名缓冲区大小;flags: 通常为0;src_addr : 数据来源端的地址;fromlen : 作为输入时,fromlen常置为sizeof(struct sockaddr);当输出时,fromlen包含实际存入buf中的数据字节数。

[cch@aubin socket]$ gcc udpserver.c -o udpserver
[cch@aubin socket]$ gcc udpclient.c -o udpclient
[cch@aubin socket]$ ./udpserver 
Server is waiting for client to connect:
Server receive ip is 192.168.100.120, receive data is 0

Server is waiting for client to connect:
Server receive ip is 192.168.100.120, receive data is 1

Server is waiting for client to connect:
Server receive ip is 192.168.100.120, receive data is 2

Server is waiting for client to connect:
Server receive ip is 192.168.100.120, receive data is 3

Server is waiting for client to connect:
Server receive ip is 192.168.100.120, receive data is 4

Server is waiting for client to connect:

#############################################################

[cch@aubin socket]$ ./udpclient 192.168.100.120
Client sends to server 192.168.100.120: 0

Client sends to server 192.168.100.120: 1

Client sends to server 192.168.100.120: 2

Client sends to server 192.168.100.120: 3

Client sends to server 192.168.100.120: 4

[cch@aubin socket]$ 

讨论

如何在典型的应用场景中创建TCP和UDP套接字。

TCP:sockfd = socket(AF_INET, SOCK_STREAM,0);
UDP:sockfd =socket(AF_INET, SOCK_DGRAM,0);

描述了TCP/UDP通信中客户端和服务器的框架。使用代码展示如何创建并发服务器。

TCP服务器端:
通过上图我们可以看到服务器端的流程是:
调用socket()创建一个新的socket。
调用bind()将创建的socket绑定在一个地址上,即分配ip和端口。
调用listen()监听客户端访问。
调用accept()接收客户端的访问
调用read()/write()或者send()/recv()传输数据。

TCP客户端的流程是:
调用socket()创建一个新的socket
调用connect()将客户端通过地址请求连接到服务器的socket上。
调用read()/write()或者send()/recv()传输数据。

UDP服务器端的流程是:
调用socket()创建一个socket,类似于创建一个邮箱。
调用bind()绑定服务器的地址(一个众所周知的地址,比如一个公司的邮箱地址,以便允许客户访问)。
调用recvfrom()/sendto()接收、发送数据报。
调用close()关闭socket

UDP客户端的流程是:
调用socket()创建一个socket,类似于创建一个邮箱。
调用recvfrom()/sendto()接收、发送数据报。
调用close()关闭socket

使用代码显示select()、poll()函数的优点。

使用select和poll同时处理多个客户端连接请求

select代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAX_CLIENTS 5

int main() {
    int server_socket, client_sockets[MAX_CLIENTS];
    fd_set readfds;
    int max_sd, activity, new_socket, i;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Create server socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    // Initialize sockaddr_in structure
    // ...

    // Bind server socket
    // ...

    // Listen for incoming connections
    // ...

    while (1) {
        FD_ZERO(&readfds);
        FD_SET(server_socket, &readfds);
        max_sd = server_socket;

        for (i = 0; i < MAX_CLIENTS; i++) {
            int sd = client_sockets[i];
            if (sd > 0)
                FD_SET(sd, &readfds);
            if (sd > max_sd)
                max_sd = sd;
        }

        // Wait for an activity on any of the sockets
        activity = select(max_sd + 1, &readfds, NULL, NULL, NULL);

        // Handle activity on the server socket
        if (FD_ISSET(server_socket, &readfds)) {
            // Accept a new connection
            new_socket = accept(server_socket, (struct sockaddr*)&address, (socklen_t*)&addrlen);
            // Add the new socket to the array of client sockets
            // ...
        }

        // Handle activity on client sockets
        for (i = 0; i < MAX_CLIENTS; i++) {
            int sd = client_sockets[i];
            if (FD_ISSET(sd, &readfds)) {
                // Handle data from client
                // ...
            }
        }
    }

    return 0;
}

poll代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

#define MAX_CLIENTS 5

int main() {
    int server_socket, client_sockets[MAX_CLIENTS];
    struct pollfd fds[MAX_CLIENTS + 1];
    int nfds = 1; // including server socket
    int i, ret;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    // Create server socket
    server_socket = socket(AF_INET, SOCK_STREAM, 0);
    // Initialize sockaddr_in structure
    // ...

    // Bind server socket
    // ...

    // Listen for incoming connections
    // ...

    // Initialize pollfd structure for server socket
    fds[0].fd = server_socket;
    fds[0].events = POLLIN;

    for (i = 0; i < MAX_CLIENTS; i++) {
        fds[i + 1].fd = -1; // initialize client sockets to -1
    }

    while (1) {
        // Wait for an activity on any of the sockets
        ret = poll(fds, nfds, -1);

        // Handle activity on the server socket
        if (fds[0].revents & POLLIN) {
            // Accept a new connection
            client_sockets[nfds - 1] = accept(server_socket, (struct sockaddr*)&address, (socklen_t*)&addrlen);
            fds[nfds].fd = client_sockets[nfds - 1];
            fds[nfds].events = POLLIN;
            nfds++;
        }

        // Handle activity on client sockets
        for (i = 1; i < nfds; i++) {
            if (fds[i].revents & POLLIN) {
                // Handle data from client
                // ...
            }
        }
    }

    return 0;
}

(1)select ()优点:
1)select 的可移植性更好,在某些 Unix 系统上不支持 poll。
2)select 对于超时值提供了更好的精度:微秒,而 poll 是毫秒。
(2)poll() 函数的优点:
1)poll 不要求开发者计算最大文件描述符加一的大小。
2)poll 在应付大数目的文件描述符的时候相比于 select 速度更快。
3)它没有最大连接数的限制,原因是它是基于链表来存储的。

// 使用select()
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(socket1, &read_fds);
FD_SET(socket2, &read_fds);
select(max_socket + 1, &read_fds, NULL, NULL, NULL);
// 使用poll()
struct pollfd fds[2];
fds[0].fd = socket1;
fds[0].events = POLLIN;
fds[1].fd = socket2;
fds[1].events = POLLIN;

poll(fds, 2, timeout_in_milliseconds);

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

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

相关文章

AI - FlowField(流场寻路)

FlowField流场寻路&#xff0c;利用网格存储每个点对目标点的推力&#xff0c;网格上的单位根据对于推力进行移动。用于大量单位进行寻路对于同一目的地的寻路&#xff0c;常用于rts游戏等。 对应一张网格地图(图中黑块是不可行走区域) 生成热度图 计算所有网格对于目标点(…

【Flutter】graphic图表实现tooltip一段时间后自动隐藏

概述 graphic图表中提供了自定义tooltip的事件&#xff0c;可通过selections中on和clear配置手势选项和可识别设备&#xff0c;默认情况下tooltip需要双击隐藏&#xff0c;但这并不符合我们的需求。通过调研发现&#xff0c;若想实现tooltip隔几秒后隐藏&#xff0c;可通过Str…

西工大网络空间安全学院计算机系统基础实验一(9, 10, 11, 12, 13)

还是那句话&#xff0c;专心做好你自己的&#xff0c;老老实实把基础打好&#xff0c;不要被其他人带跑节奏&#xff0c;不要跟他打&#xff0c;跟着这系列博客&#xff0c;稳扎稳打一步一步来。即使你VMware workstation没下载好&#xff0c;即使你Ubuntu虚拟机没配好&#xf…

【数据挖掘】国科大刘莹老师数据挖掘课程作业 —— 第三次作业

Written Part 1. 基于表 1 1 1 回答下列问题&#xff08;min_sup40%, min_conf75%&#xff09;&#xff1a; Transaction IDItems Bought0001{a, d, e}0024{a, b, c, e}0012{a, b, d, e}0031{a, c, d, e}0015{b, c, e}0022{b, d, e}0029{c, d}0040{a, b, c}0033{a, d, e}0038…

【计算机网络笔记】交换机

系列文章目录 什么是计算机网络&#xff1f; 什么是网络协议&#xff1f; 计算机网络的结构 数据交换之电路交换 数据交换之报文交换和分组交换 分组交换 vs 电路交换 计算机网络性能&#xff08;1&#xff09;——速率、带宽、延迟 计算机网络性能&#xff08;2&#xff09;…

Vue3依赖注入

适用场景 尤其针对一个变量需要从顶层组件开始透传&#xff0c;途径很多个子组件最后在第n代子组件使用的时候。对于这些途经的子组件而言&#xff0c;它们不但不使用而且完全不关心该变量具体是什么&#xff0c;只是作为一个传递工具罢了。这种情况下&#xff0c;使用依赖注入…

asla四大开源组件应用示例(alsa-lib、alsa-utils、alsa-tools、alsa-plugins)

文章目录 alsa设备文件/dev/snd//sys/class/sound/proc/asoundalsa-lib示例1alsa-utilsalsa-toolsalsa-plugins参考alsa设备文件 /dev/snd/ alsa设备文件目录位于,/dev/snd,如下所示 root@xboard:~#ls /dev/snd -l total 0 drwxr-xr-x 2 root root 60 Nov 6 2023 …

vuepress-----7、发布在GitHub

# 7、发布在GitHub 在你的项目中&#xff0c;创建一个如下的 deploy.sh 文件&#xff08;请自行判断去掉高亮行的注释&#xff09;: #!/usr/bin/env sh# 确保脚本抛出遇到的错误 set -e# 生成静态文件 npm run docs:build# 进入生成的文件夹 cd docs/.vuepress/dist# 如果是发…

PTA_2023年软件设计综合实践_10(回溯法与分治限界法)

7-1 桥本分数 将1-9九个数不重复地赋给不同的9个元素 &#xff0c;实现形如a/bcd/eff/hi 的形式。例&#xff1a;1/265/784/39 1/325/967/84 &#xff08;注意&#xff1a;1/265/784/39 和5/781/264/39 只能算一种解&#xff09;&#xff0c;共有多少种不同的解。 语言选C #…

36 - 电商系统表设计优化案例分析

如果在业务架构设计初期&#xff0c;表结构没有设计好&#xff0c;那么后期随着业务以及数据量的增多&#xff0c;系统就很容易出现瓶颈。如果表结构扩展性差&#xff0c;业务耦合度将会越来越高&#xff0c;系统的复杂度也将随之增加。这一讲我将以电商系统中的表结构设计为例…

服务器数据恢复—V7000存储raid5崩溃导致上层卷无法使用的数据恢复案例

服务器数据恢复环境&#xff1a; 某品牌V7000存储中有一组由几十块硬盘组建的raid5阵列。上层操作系统为windows server&#xff0c;NTFS分区。 服务器故障&#xff1a; 有一块硬盘出现故障离线&#xff0c;热备盘自动上线替换离线硬盘。在热备盘上线同步数据的过程&#xff0c…

【springboot】idea项目启动端口被占用

问题 idea本地启动springboot项目端口老是被占用 解决 关闭被占用的端口进程 步骤: 1. winR打开程序框 2. 查出被占用端口的进程id netstat -ano | finderstr 端口号 例如 netstat -ano | finderstr 81013.杀死进程 taskkill /pid 进程id -t -f 例如 taskkill /pid 2…

TZOJ 1369 求绝对值

答案&#xff1a; #include<stdio.h> int main() {double a0.0; 要求输入实数&#xff0c;实数包括小数&#xff0c;所以不能用int&#xff0c;只能用浮点型doublewhile (scanf("%lf", &a) ! EOF) //多组数据输入{if (a < 0.0) //如果是负数a -a…

用IDEA创建Java类时,自动生成作者、时间和版本号、注释等信息

1.File->settings… 2、Editor->File and Code Templates->Includes->File Header(双击)&#xff0c;然后在右边输入框内输入代码即可 代码可以直接复制 /*** Author 作者名* Date ${DATE} ${TIME}* version 1.0* 注释*/上边你也可以自定义生成的内容。

Spring 日志

日志的作用: 1.定位和发现问题 2.系统监控 3.数据采集 观察日志 先写一段打印日志的代码 日志内容 日志级别分类 默认日志级别是Info,级别一下的就不打印了 Spring 帮我们集成了日志框架,我们直接使用即可 我们测试一下用日志框架打印日志是如何 我们就会发现打印的结果跟…

内测分发平台应用的异地容灾和负载均衡处理和实现思路

内测分发平台应用的异地容灾和负载均衡处理和实现思路 ​ 内测分发平台在软件开发过程中起着至关重要的作用&#xff0c;它不仅可以帮助开发者将应用程序传播给内部测试人员&#xff0c;还可以收集反馈、跟踪错误并改进产品。然而&#xff0c;为了确保一个平稳、连贯的内测过…

血的教训--kail系统免密centos7的坑【高版本ssh免密低版本ssh的坑】

血的教训–kail系统免密centos7的坑【高版本ssh免密低版本ssh的坑】 最近下载了一个2023版本的kail系统&#xff0c;但是经过几次设置免密后&#xff0c;ssh过去一直让提供密码&#xff0c;所以就仔细的分析了一下&#xff0c;果然还是发现了点猫腻 接上一个博客&#xff0c;大…

运算放大器

一、运算放大器的概念 1&#xff09;运算放大器具有两个输入端和一个输出端还有两个电源端&#xff0c;其中标有“”号的输入端为“同相输入端”&#xff0c;另一只标有“一”号的输入端为“反相输入端” 2&#xff09;运放的供电一般有两种方式&#xff1a;单电源和双电源 单…

谱方法学习笔记-上(超详细)

谱方法学习笔记&#x1f4d2; 谱方法学习笔记-下(超详细) 声明&#xff1a;鉴于CSDN使用 K a T e X KaTeX KaTeX 渲染公式&#xff0c; KaTeX \KaTeX KATE​X 与 L a T e X LaTeX LaTeX 不同&#xff0c;不支持直接的交叉引用命令&#xff0c;如\label和\eqref。 KaTeX \KaT…

SpringBoot+网易邮箱登录注册

文章目录 SpringBoot网易邮箱登录注册pom.xmlapplication.ymlsqlUserEmail.javaUserEmailMapper.javaUserEmailMapper.xmlEmailService.javaUserEmailService.javaUserEmailServiceImpl.javaUserEmailController.javaregister1.html 编写前参考 SpringBoot网易邮箱登录注册 po…
最新文章