Linux网络编程:多进程 多线程_并发服务器

文章目录:

一:wrap常用函数封装

wrap.h 

wrap.c

server.c封装实现

client.c封装实现

二:多进程process并发服务器

server.c服务器

实现思路

代码逻辑 

client.c客户端

三:多线程thread并发服务器

server.c服务器

实现思路

代码逻辑 

client.c客户端
​​​​


 

一:wrap常用函数封装

wrap.h 

//声明了一些网络编程中常用的函数//所有的函数都放在条件编译的代码块中,这样只有在编译时定义了 __WRAP_H_ 这个宏#ifndef __WRAP_H_#define __WRAP_H_//perr_exit:用来处理错误并退出程序void perr_exit(const char *s);//Accept:用于接受一个TCP连接请求//它接受一个文件描述符 fd,一个指向 struct sockaddr 结构的指针 sa,以及一个指向 socklen_t 类型的指针 salenptrint Accept(int fd, struct sockaddr *sa, socklen_t *salenptr);//Bind:用于将一个网络地址(包括IP地址和端口号)绑定到一个文件描述符上//它接受一个文件描述符 fd,一个指向 struct sockaddr 结构的指针 sa,以及 socklen_t 类型的 salenint Bind(int fd, const struct sockaddr *sa, socklen_t salen);//Connect:用于建立与远程主机的TCP连接//它接受一个文件描述符 fd,一个指向 struct sockaddr 结构的指针 sa,以及 socklen_t 类型的 salenint Connect(int fd, const struct sockaddr *sa, socklen_t salen);//Listen:用于在服务器端创建一个TCP监听队列//它接受一个文件描述符 fd 和一个指定的最大连接等待数 backlogint Listen(int fd, int backlog);//Socket:用于创建一个新的套接字//它接受一个地址族 family,一个套接字类型 type,以及一个协议编号 protocolint Socket(int family, int type, int protocol);//Read:用于从文件中读取数据//它接受一个文件描述符 fd,一个指向要读取数据的缓冲区的指针 ptr,以及要读取的最大字节数 nbytesssize_t Read(int fd, void *ptr, size_t nbytes);//Write:用于将数据写入文件//它接受一个文件描述符 fd,一个指向要写入数据的缓冲区的指针 ptr,以及要写入的字节数 nbytesssize_t Write(int fd, const void *ptr, size_t nbytes);//Close:用于关闭文件//它接受一个文件描述符 fdint Close(int fd);//Readn:用来读取指定数量的字节//它接受一个文件描述符 fd,一个指向要读取数据的缓冲区的指针 vptr,以及要读取的字节数 nssize_t Readn(int fd, void *vptr, size_t n);//Writen:用来写入指定数量的字节//它接受一个文件描述符 fd,一个指向要写入数据的缓冲区的指针 vptr,以及要写入的字节数 nssize_t Writen(int fd, const void *vptr, size_t n);//my_read:用来读取数据到一个字符数组中//它接受一个文件描述符 fd,一个指向要读取数据的缓冲区的指针 ptrssize_t my_read(int fd, char *ptr);//Readline:用来读取一行数据//它接受一个文件描述符 fd,一个指向要读取数据的缓冲区的指针 vptr,以及要读取的最大字节数 maxlenssize_t Readline(int fd, void *vptr, size_t maxlen);#endif

wrap.c

//这个头文件包含了标准库的函数和变量,包括用于内存分配、输入/输出、错误处理等功能的函数和变量#include <stdlib.h>		
//这个头文件包含了标准输入/输出库的函数和变量,包括用于文件操作、标准输入/输出等功能的函数和变量	#include <stdio.h>	
//这个头文件包含了用于Unix和类Unix系统中的函数和变量,包括与进程控制、系统调用等相关的函数和变量		#include <unistd.h>			
//这个头文件包含了用于错误处理的函数和变量,包括用于表示错误码的宏和全局变量#include <errno.h>			
//这个头文件包含了用于网络编程的函数和变量,包括用于创建、操作套接字等功能的函数和变量#include <sys/socket.h>		//perr_exit:用来处理错误并退出程序void perr_exit(const char *s){perror(s);exit(-1);}//Accept:用于接受一个TCP连接请求	 int Accept(int fd, struct sockaddr *sa, socklen_t *salenptr){int n;again:if ((n = accept(fd, sa, salenptr)) < 0) {if ((errno == ECONNABORTED) || (errno == EINTR))goto again;elseperr_exit("accept error");}return n;}//Bind:用于将一个网络地址(包括IP地址和端口号)绑定到一个文件描述符上	 int Bind(int fd, const struct sockaddr *sa, socklen_t salen){int n;if ((n = bind(fd, sa, salen)) < 0)perr_exit("bind error");return n;}//Connect:用于建立与远程主机的TCP连接	 int Connect(int fd, const struct sockaddr *sa, socklen_t salen){int n;n = connect(fd, sa, salen);if (n < 0) {perr_exit("connect error");}return n;}//Listen:用于在服务器端创建一个TCP监听队列	 int Listen(int fd, int backlog){int n;if ((n = listen(fd, backlog)) < 0)perr_exit("listen error");return n;}//Socket:用于创建一个新的套接字	 int Socket(int family, int type, int protocol){int n;if ((n = socket(family, type, protocol)) < 0)perr_exit("socket error");return n;}//Read:用于从文件中读取数据	 ssize_t Read(int fd, void *ptr, size_t nbytes){ssize_t n;again:if ( (n = read(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;}//Write:用于将数据写入文件	 ssize_t Write(int fd, const void *ptr, size_t nbytes){ssize_t n;again:if ((n = write(fd, ptr, nbytes)) == -1) {if (errno == EINTR)goto again;elsereturn -1;}return n;}//Close:用于关闭文件	 int Close(int fd){int n;if ((n = close(fd)) == -1)perr_exit("close error");return n;}//Readn:用来读取指定数量的字节	 /*参三: 应该读取的字节数  读 N 个字节*/                          //socket 4096  readn(cfd, buf, 4096)   nleft = 4096-1500ssize_t Readn(int fd, void *vptr, size_t n){size_t  nleft;              //usigned int 剩余未读取的字节数ssize_t nread;              //int 实际读到的字节数char   *ptr;ptr = vptr;nleft = n;                  //n 未读取字节数while (nleft > 0) {if ((nread = read(fd, ptr, nleft)) < 0) {if (errno == EINTR)nread = 0;elsereturn -1;} else if (nread == 0)break;nleft -= nread;   //nleft = nleft - nread ptr += nread;}return n - nleft;}//Writen:用来写入指定数量的字节	 ssize_t Writen(int fd, const void *vptr, size_t n){size_t nleft;ssize_t nwritten;const char *ptr;ptr = vptr;nleft = n;while (nleft > 0) {if ( (nwritten = write(fd, ptr, nleft)) <= 0) {if (nwritten < 0 && errno == EINTR)nwritten = 0;elsereturn -1;}nleft -= nwritten;ptr += nwritten;}return n;}//my_read:用来读取数据到一个字符数组中	 static ssize_t my_read(int fd, char *ptr){static int read_cnt;static char *read_ptr;static char read_buf[100];if (read_cnt <= 0) {again:if ( (read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {   //"hello\n"if (errno == EINTR)goto again;return -1;} else if (read_cnt == 0)return 0;read_ptr = read_buf;}read_cnt--;*ptr = *read_ptr++;return 1;}//Readline:用来读取一行数据	 /*readline读一行 --- fgets*/    //传出参数 vptrssize_t Readline(int fd, void *vptr, size_t maxlen){ssize_t n, rc;char    c, *ptr;ptr = vptr;for (n = 1; n < maxlen; n++) {if ((rc = my_read(fd, &c)) == 1) {   //ptr[] = hello\n*ptr++ = c;if (c == '\n')break;} else if (rc == 0) {*ptr = 0;return n-1;} elsereturn -1;}*ptr = 0;return n;
}

利用封装函数: 联合编译server.c 和 wrap.c 生成 server、 联合编译 client.c 和 wrap.c 生成 client

server.c封装实现

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <strings.h>
#include <string.h>
#include <ctype.h>
#include <arpa/inet.h>#include "wrap.h"#define SERV_PORT 6666int main(void)
{int sfd, cfd;int len, i;char buf[BUFSIZ], clie_IP[BUFSIZ];struct sockaddr_in serv_addr, clie_addr;socklen_t clie_addr_len;/*1.socket函数:创建用于建立连接的socket,返回的文件描述符存入link_fd*/sfd = Socket(AF_INET, SOCK_STREAM, 0);int opt = 1;//设置套接字选项:文件描述符,要设置的选项是套接字的选项,要设置的选项是“重用地址”选项,包含了要设置的选项的值,选项值的长度setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&serv_addr, sizeof(serv_addr));           	 //将指定内存区域的内容初始化为0	serv_addr.sin_family = AF_INET;        				 //IPv4         serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);  	 //获取本机任意有效IPserv_addr.sin_port = htons(SERV_PORT);          	 //转为网络字节序的 端口号/*2.bind函数:绑定服务器端的socket绑定地址结构(IP+port)*/Bind(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));/*3.listen函数:设定监听(连接)上线*/Listen(sfd, 2);                                printf("wait for client connect ...\n");clie_addr_len = sizeof(clie_addr_len);/*4.accept函数:阻塞等待客户端建立连接*/cfd = Accept(sfd, (struct sockaddr *)&clie_addr, &clie_addr_len);/*建立连接后打印客户端的IP和端口号    获取客户端地址结构*/printf("cfd = ----%d\n", cfd);printf("client IP: %s  port:%d\n", inet_ntop(AF_INET, &clie_addr.sin_addr.s_addr, clie_IP, sizeof(clie_IP)), ntohs(clie_addr.sin_port));while (1) {//5. read(fd)	读socket获取客户端数据len = Read(cfd, buf, sizeof(buf));Write(STDOUT_FILENO, buf, len);//6. 小--大写	toupper()for (i = 0; i < len; i++)buf[i] = toupper(buf[i]);//7. write(fd)Write(cfd, buf, len); }//8. close()Close(sfd);Close(cfd);return 0;
}

client.c封装实现

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>#include "wrap.h"#define SERV_IP "127.0.0.1"
#define SERV_PORT 6666int main(void)
{int sfd, len;struct sockaddr_in serv_addr;char buf[BUFSIZ]; //1. socket()	创建socketsfd = Socket(AF_INET, SOCK_STREAM, 0);                    bzero(&serv_addr, sizeof(serv_addr));           	 		 //将指定内存区域的内容初始化为0	serv_addr.sin_family = AF_INET;        				 		 //IPv4         inet_pton(AF_INET, SERV_IP, &serv_addr.sin_addr.s_addr);  	 //本地字节序(string IP) ---> 网络字节序serv_addr.sin_port = htons(SERV_PORT);          	 		 //转为网络字节序的 端口号//2. connect();	与服务器建立连接Connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));while (1) {fgets(buf, sizeof(buf), stdin);//3. write()	写数据到 socketint r = Write(sfd, buf, strlen(buf));       printf("Write r ======== %d\n", r);//4. read()	读转换后的数据len = Read(sfd, buf, sizeof(buf));printf("Read len ========= %d\n", len);//5. 显示读取结果Write(STDOUT_FILENO, buf, len);}//6. close()Close(sfd);return 0;
}

 read 函数的返回值

read 函数的返回值:1. > 0 实际读到的字节数2. = 0 已经读到结尾(对端已经关闭)【 !重 !点 !】3. -1 应进一步判断errno的值:errno = EAGAIN or EWOULDBLOCK: 设置了非阻塞方式 读。 没有数据到达。 errno = EINTR 慢速系统调用被 中断。errno = “其他情况” 异常。

二:多进程process并发服务器

server.c服务器

实现思路

使用多进程并发服务器时要考虑以下几点:1.父进程最大文件描述个数(父进程中需要close关闭accept返回的新文件描述符)2.系统内创建进程个数(与内存大小相关)3.进程创建过多是否降低整体服务性能(进程调度)
1. Socket();		        创建 监听套接字 lfd2. Bind()	                绑定地址结构 Strcut scokaddr_in addr;3. Listen();	4. while (1) {cfd = Accpet();			接收客户端连接请求。pid = fork();if (pid == 0){			子进程 read(cfd) --- 小-》大 --- write(cfd)close(lfd)		    关闭用于建立连接的套接字 lfdread()小--大write()} else if (pid > 0) {	close(cfd);		    关闭用于与客户端通信的套接字 cfd	contiue;}}5. 子进程:close(lfd)read()小--大write()	父进程:close(cfd);注册信号捕捉函数:	SIGCHLD在回调函数中, 完成子进程回收while (waitpid());

代码逻辑 

#include <stdio.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <sys/wait.h>
#include <ctype.h>
#include <unistd.h>#include "wrap.h"#define MAXLINE 8192
#define SERV_PORT 8000//在回调函数中, 完成子进程回收void do_sigchild(int num){while (waitpid(0, NULL, WNOHANG) > 0);}int main(void)
{struct sockaddr_in servaddr, cliaddr;socklen_t cliaddr_len;int listenfd, connfd;char buf[MAXLINE];char str[INET_ADDRSTRLEN];int i, n;pid_t pid;struct sigaction newact;//5.父进程newact.sa_handler = do_sigchild;sigemptyset(&newact.sa_mask);newact.sa_flags = 0;//注册信号捕捉函数:	SIGCHLDsigaction(SIGCHLD, &newact, NULL);//1. Socket();		        创建 监听套接字 lfdlistenfd = Socket(AF_INET, SOCK_STREAM, 0);int opt = 1;setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(SERV_PORT);//2. Bind()	                绑定地址结构 Strcut scokaddr_in addr;Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));//3. Listen();Listen(listenfd, 20);printf("Accepting connections ...\n");while (1) {cliaddr_len = sizeof(cliaddr);//accept()	阻塞监听客户端连接,接收客户端连接请求connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);printf("-------------------------%d\n", connfd);pid = fork();		//4.子进程 read(connfd) --- 小-》大 --- write(connfd)if (pid == 0) {//关闭用于建立连接的套接字 lfdClose(listenfd);while (1) {//read()n = Read(connfd, buf, MAXLINE);if (n == 0) {printf("the other side has been closed.\n");break;}printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));//小--大for (i = 0; i < n; i++)buf[i] = toupper(buf[i]);//write()Write(STDOUT_FILENO, buf, n);Write(connfd, buf, n);}Close(connfd);return 0;} else if (pid > 0) {Close(connfd);		//关闭用于与客户端通信的套接字 connfd} elseperr_exit("fork");}return 0;
}

client.c客户端

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>#include "wrap.h"#define MAXLINE 8192
#define SERV_PORT 8000int main(int argc, char *argv[])
{struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {Write(sockfd, buf, strlen(buf));n = Read(sockfd, buf, MAXLINE);if (n == 0) {printf("the other side has been closed.\n");break;}elseWrite(STDOUT_FILENO, buf, n);}Close(sockfd);return 0;
}

三:多线程thread并发服务器

server.c服务器

实现思路

在使用线程模型开发服务器时需考虑以下问题:1.调整进程内最大文件描述符上限2.线程如有共享数据,考虑线程同步3.服务于客户端线程退出时,退出处理。(退出值,分离态)4.系统负载,随着链接客户端增加,导致其它线程不能及时得到CPU
	1. Socket();		            创建 监听套接字 lfd2. Bind()		                绑定地址结构 Strcut scokaddr_in addr;3. Listen();		4. while (1) {		cfd = Accept(lfd, );pthread_create(&tid, NULL, tfn, (void *)cfd);pthread_detach(tid);  		// pthead_join(tid, void **);  新线程---专用于回收子线程}5. 子线程:void *tfn(void *arg) {// close(lfd)			不能关闭。 主线程要使用lfdread(cfd)小--大write(cfd)pthread_exit((void *)10);	}

代码逻辑 

#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>#include "wrap.h"#define MAXLINE 8192
#define SERV_PORT 8000//定义一个结构体, 将地址结构跟cfd捆绑 struct s_info {                     struct sockaddr_in cliaddr;int connfd;};//子线程void *do_work(void *arg){int n,i;struct s_info *ts = (struct s_info*)arg;char buf[MAXLINE];char str[INET_ADDRSTRLEN];      //#define INET_ADDRSTRLEN 16  可用"[+d"查看while (1) {		//读客户端//read(cfd)n = Read(ts->connfd, buf, MAXLINE);            //跳出循环,关闭cfdif (n == 0) {printf("the client %d closed...\n", ts->connfd);break;                                              }//打印客户端信息(IP/PORT)printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &(*ts).cliaddr.sin_addr, str, sizeof(str)),ntohs((*ts).cliaddr.sin_port));                //小写-->大写for (i = 0; i < n; i++) buf[i] = toupper(buf[i]);                       //写出至屏幕Write(STDOUT_FILENO, buf, n);   //回写给客户端Write(ts->connfd, buf, n);                              }Close(ts->connfd);return (void *)0;
}int main(void)
{struct sockaddr_in servaddr, cliaddr;socklen_t cliaddr_len;int listenfd, connfd;pthread_t tid;struct s_info ts[256];     								   //创建结构体数组.int i = 0;//1. Socket();		            创建 监听套接字 lfdlistenfd = Socket(AF_INET, SOCK_STREAM, 0);                     			//创建一个socket, 得到lfdbzero(&servaddr, sizeof(servaddr));                             			//地址结构清零servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);                  				//指定本地任意IPservaddr.sin_port = htons(SERV_PORT);                                   	//指定端口号 //2. Bind()		                绑定地址结构 Strcut scokaddr_in addr;Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));         	//绑定//3. Listen();Listen(listenfd, 128);                                                  	//设置同一时刻链接服务器上限数printf("Accepting client connect ...\n");while (1) {cliaddr_len = sizeof(cliaddr);//accept()	阻塞监听客户端连接connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len); 	//阻塞监听客户端链接请求ts[i].cliaddr = cliaddr;ts[i].connfd = connfd;pthread_create(&tid, NULL, do_work, (void*)&ts[i]);pthread_detach(tid);                                                    	//子线程分离,防止僵线程产生.i++;}return 0;
}

client.c客户端

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 8000int main(int argc, char *argv[])
{struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr.s_addr);servaddr.sin_port = htons(SERV_PORT);Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {Write(sockfd, buf, strlen(buf));n = Read(sockfd, buf, MAXLINE);if (n == 0)printf("the other side has been closed.\n");elseWrite(STDOUT_FILENO, buf, n);}Close(sockfd);return 0;
}

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

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

相关文章

途乐证券|定增募资是什么意思?

作为融资手法之一&#xff0c;定增募资在企业中被广泛运用。但一般投资者对此或许不太了解&#xff0c;只知道它是一种融资手法。那么&#xff0c;定增募资到底是什么意思呢&#xff1f; 一、什么是定增募资&#xff1f; 定增募资即定向增发股票募集资金&#xff0c;是新股票发…

C++入门知识点——解决C语言不足

&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️ &#x1f4a5;个人主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王&#x1f525;&#x1f525;&#x1f525; &#x1f4a5;代码仓库&#xff1a;&#x1f525;&#x1f525;魔…

leetcode-动态规划-42-接雨水

题目 给定 n 个非负整数表示每个宽度为 1 的柱子的高度图&#xff0c;计算按此排列的柱子&#xff0c;下雨之后能接多少雨水。 示例 1&#xff1a; 输入&#xff1a;height [0,1,0,2,1,0,1,3,2,1,2,1] 输出&#xff1a;6 解释&#xff1a;上面是由数组 [0,1,0,2,1,0,1,3,2,1…

【C# 基础精讲】LINQ to Objects查询

LINQ to Objects是LINQ技术在C#中的一种应用&#xff0c;它专门用于对内存中的对象集合进行查询和操作。通过使用LINQ to Objects&#xff0c;您可以使用统一的语法来查询、过滤、排序、分组等操作各种.NET对象。本文将详细介绍LINQ to Objects的基本概念、常见的操作和示例&am…

Android Studio实现读取本地相册文件并展示

目录 原文链接效果 代码activity_main.xmlMainActivity 原文链接 效果 代码 activity_main.xml 需要有一个按钮和image来展示图片 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas.android.com/apk…

Error creating bean with name ‘esUtils‘ defined in file

报错异常&#xff1a; 背景&#xff1a; esUtils在common服务中、启动media服务时候、报这个异常、后排查esUtils在启动时候发生异常引起的、在相关bean中加入try{}catch{}即可解决问题 String[] split url.split(","); HttpHost[] httpHosts new HttpHost[split.…

Java中使用@Component时再使用@Resource或@Autowired时注入失败问题解决方法

问题 在Component注解的类下&#xff0c;再使用了Resource或Autowired注解。如此操作会导致依赖注入失败。 这是因为spring加载它们的顺序不同&#xff0c;在使用Component注解将bean实例化到spring容器内的时候&#xff0c;因为Autowired是在这个bean之中的&#xff0c;此时A…

CentOS 7.8 Docker安装、卸载与Docker-Compose的安装

一、CentOS 7.8 安装Docker 1.1、安装需要的软件包 yum install -y yum-utils device-mapper-persistent-data lvm21.12、设置yum源 yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo1.13、查看仓库中的docker版本 yum lis…

FirmAE 工具安装(解决克隆失败 网络问题解决)

FirmAE官方推荐使用Ubuntu 18.04系统进行安装部署&#xff0c;FirmAE工具的安装部署十分简单&#xff0c;只需要拉取工具仓库后执行安装脚本即可。 首先运行git clone --recursive https://kgithub.com/pr0v3rbs/FirmAE命令 拉取FirmAE工具仓库&#xff0c;因为网络的问题&…

【SA8295P 源码分析】41 - SA8295所有镜像位置、拷贝脚本、生成QFIL包

【SA8295P 源码分析】41 - SA8295所有镜像位置、拷贝脚本、生成QFIL包 一、SA8295 各镜像位置二、SA8295 QNX 侧镜像拷贝脚本三、SA8295 Android 侧镜像拷贝脚本四、使用QFIL 下载整包五、Fastboot 下载命令整理系列文章汇总见:《【SA8295P 源码分析】00 - 系列文章链接汇总》…

c语言每日一练(10)

前言&#xff1a;每日一练系列&#xff0c;每一期都包含5道选择题&#xff0c;2道编程题&#xff0c;博主会尽可能详细地进行讲解&#xff0c;令初学者也能听的清晰。每日一练系列会持续更新&#xff0c;暑假时三天之内必有一更&#xff0c;到了开学之后&#xff0c;将看学业情…

WinPlan经营大脑:预测先机,决策未来

目录 一、引言 二、WinPlan的市场预测功能 三、WinPlan的决策制定功能 四、WinPlan的应用价值

验证评估守护关基安全 赛宁数字孪生靶场创新实践

​​近日&#xff0c;由赛宁网安主办&#xff0c;ISC互联网安全大会组委会协办的第十一届互联网安全大会&#xff08;ISC 2023&#xff09;安全运营实践论坛圆满结束。赛宁网安产品总监史崯出席并作出主题演讲&#xff1a;《基于数字孪生靶场如何开展验证评估》&#xff0c;同时…

Linux工具【2】(调试器gdb、项目自动化构建工具make/Makefile)

gdb、make/Makefile 引言调试器gdb介绍常用指令 自动化构建工具make/Makefile介绍使用依赖关系与依赖方法编辑Makefile伪目标 总结 引言 在上一篇文章中介绍了Linux中的编辑器vim与编译器gcc与g&#xff1a; 戳我看vim与gcc详解哦 在本篇文章中将继续来介绍Linux中的工具&…

【Apollo学习笔记】——规划模块TASK之LANE_CHANGE_DECIDER

文章目录 前言LANE_CHANGE_DECIDER功能简介LANE_CHANGE_DECIDER相关配置LANE_CHANGE_DECIDER总体流程LANE_CHANGE_DECIDER相关子函数PrioritizeChangeLaneUpdateStatusIsClearToChangeLaneHysteresisFilter 参考 前言 在Apollo星火计划学习笔记——Apollo路径规划算法原理与实…

TCP定制协议,序列化和反序列化

目录 前言 1.理解协议 2.网络版本计算器 2.1设计思路 2.2接口设计 2.3代码实现&#xff1a; 2.4编译测试 总结 前言 在之前的文章中&#xff0c;我们说TCP是面向字节流的&#xff0c;但是可能对于面向字节流这个概念&#xff0c;其实并不理解的&#xff0c;今天我们要介…

nginx反向代理后实现nginx和apache两种web服务器能够记录客户端的真实IP地址

一.构建环境 二.配置反向代理 1.基于源码安装的nginx环境下修改nginx.conf&#xff08;设备1&#xff09; 2.通过windows powershell进行修改hosts文件并测试 3.设备2和设备3上查看日志&#xff0c;可以看到访问来源都是代理服务器&#xff08;2.190&#xff09;而不是真实…

WebSocket服务端数据推送及心跳机制(Spring Boot + VUE)

一、WebSocket简介 HTML5规范在传统的web交互基础上为我们带来了众多的新特性&#xff0c;随着web技术被广泛用于web APP的开发&#xff0c;这些新特性得以推广和使用&#xff0c;而websocket作为一种新的web通信技术具有巨大意义。WebSocket是HTML5新增的协议&#xff0c;它的…

Python Web开发 Django 简介

今天来为大家介绍 Python 另一个 Web 开发框架 Django&#xff0c;它是一个基于 Python 定制的开源 Web 应用框架&#xff0c;最早源于一个在线新闻 Web 网站&#xff0c;后于2005年开源。Django 的功能大而全&#xff0c;它提供的一站式解决的思路&#xff0c;能让开发者不用在…

__slots__和__doc__

目录 一、什么是__slots__ 二、为什么用__slots__ 三、刨根问底 四、__doc__ python从小白到总裁完整教程目录:https://blog.csdn.net/weixin_67859959/article/details/129328397?spm1001.2014.3001.5502 一、什么是__slots__ __slots__是一个类变量&#xff0c;变量值…