Linux系统编程_网络编程:字节序、socket、serverclient、ftp 云盘

1. 网络编程概述(444.1)

TCP/UDP对比

  1. TCP 面向连接(如打电话要先拨号建立连接);UDP 是无连接的,即发送数据之前不需要建立连接
  2. TCP 提供可靠的服务。也就是说,通过 TCP 连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP 尽最大努力交付,即不保证可靠交付
  3. TCP 面向字节流,实际上是 TCP 把数据看成一连串无结构的字节流;UDP 是面向报文的 UDP 没有拥塞控制,因此网络出现拥塞不会使源主机的发送速率降低(对实时应用很有用,如 IP 电话,实时视频会议等)
  4. 每一条 TCP 连接只能是点到点的;UDP 支持一对一,一对多,多对一和多对多的交互通信
  5. TCP 首部开销 20 字节;UDP 的首部开销小,只有 8 个字节
  6. TCP 的逻辑通信信道是全双工的可靠信道,UDP 则是不可靠信道

端口号作用

  • 一台拥有 IP 地址的主机可以提供许多服务,比如 Web 服务、FTP 服务、SMTP 服务等
  • 这些服务完全可以通过 1 个 IP 地址来实现。那么,主机是怎样区分不同的网络服务呢?显然不能只靠 IP 地址,因为 IP 地址与网络服务的关系是一对多的关系。
  • 实际上是通过 “IP 地址 + 端口号” 来区分不同的服务的。端口提供了一种访问通道,服务器一般都是通过知名端口号来识别的。例如,对于每个 TCP/IP 实现来说,FTP 服务器的 TCP 端口号都是 21,每个 Telnet 服务器的 TCP 端口号都是 23,每个 TFTP (简单文件传送协议)服务器的 UDP 端口号都是 69。

在这里插入图片描述

2. 字节序(445.2)

  • 字节序,即字节在电脑中存放时的序列与输入(输出)时的序列是先到的在前还是后到的在前。
  • 字节序是指多字节数据在计算机内存中存储或者网络传输时各字节的存储顺序。
  1. Little endian:将低序字节存储在起始地址
  2. Big endian:将高序字节存储在起始地址
  • LE little-endian 小端字节序
  • BE big-endian 大端字节序
  • 网络字节序 = 大端字节序
    在这里插入图片描述

字节序转换api

#include <arpa/inet.h>

uint16_t htons(uint16_t host16bitvalue);    //返回网络字节序的值
uint32_t htonl(uint32_t host32bitvalue);    //返回网络字节序的值
uint16_t ntohs(uint16_t net16bitvalue);     //返回主机字节序的值
uint32_t ntohl(uint32_t net32bitvalue);     //返回主机字节序的值
  • h代表host主机,n代表net,s代表short(两个字节),l代表long(4个字节),通过上面的4个函数可以实现主机字节序和网络字节序之间的转换。有时可以用INADDR_ANY,INADDR_ANY指定地址让操作系统自己获取

3. socket编程步骤(446.3)

在这里插入图片描述

Sockt服务器和客户端的开发步骤

在这里插入图片描述

  • TCP Server
  1. 创建套接字(socket)
  2. 为套接字添加信息(IP地址和端口号)(bind)
  3. 监听网络连接(listen)
  4. 监听到有客户端接入,接受一个连接(accept)
  5. 数据交互(read、write、read)
  6. 关闭套接字,断开连接(close)

4. Linux提供的API简析(447.4)

  1. 指定讲“汉语”(连接协议)
    在这里插入图片描述
  • int socket(int domain, int type, int protocol);
    在这里插入图片描述
  1. 地址准备好
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 地址转换API
    • int inet_aton(const char* straddr,struct in_addr *addrp);
      把字符串形式的“192.168.1.123”转为网络能识别的格式
    • char* inet_ntoa(struct in_addr inaddr);
      把网络格式的ip地址转为字符串形式
  1. 监听
    在这里插入图片描述
    在这里插入图片描述
  2. 连接
    在这里插入图片描述
  3. 数据收发

5.1 数据收发常用第一套API

在这里插入图片描述
5.2 数据收发常用第二套API
在这里插入图片描述

  1. 客户端的connect函数
    在这里插入图片描述

5. socket服务端代码实现一(448.5)

man 2 socketman 2 bindman htonsman inet_aton

查找某段源码在哪个头文件之下的方法

  • cd /usr/include
  • ls
  • grep "struct sockaddr_in {" * -nir
    • 搜索其在哪个头文件下被定义/声明
    • ※ (星号) 在当前目录底下
    • n 找出时显示其所在行号
    • i 不区分大小写
    • r 递归的方式
  • vi linux/in.h +261
    在这里插入图片描述
    在这里插入图片描述
  • grep "struct in_addr {" * -nir
  • vi linux/in.h +89
    在这里插入图片描述
    在这里插入图片描述

代码相关

  • SOCKET/server.c
#include <stdio.h>//printf
#include <sys/types.h>//socket bind          /* See NOTES */
#include <sys/socket.h>//socket bind
//#include <linux/in.h>//struct sockaddr_in//和<netinet/in.h>冲突
#include <arpa/inet.h>//htons
#include <netinet/in.h>//inet_aton
#include <stdlib.h>//exit
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct sockaddr_in {//也可在<linux/in.h>中找到
  __kernel_sa_family_t  sin_family;     /* Address family               */
//__be16                sin_port;       /* Port number                  */
//struct in_addr        sin_addr;       /* Internet address             */

  /* Pad to size of `struct sockaddr'. */
//unsigned char         __pad[__SOCK_SIZE__ - sizeof(short int) -
//                      sizeof(unsigned short int) - sizeof(struct in_addr)];
//};*/
/*struct in_addr {
        __be32  s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度地址,返回新的建立的socket的通道
int main(int argc, char **argv)
{
	int s_fd;
	
	//1. socket 获取/创建套接字
	s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
	if(s_fd == -1){//判断建立socket通道是否成功
		perror("socket");//把错误的问题打出来
		exit(-1);//退出这个程序
	}
	//2. bind 绑定
	struct sockaddr_in s_addr;
	s_addr.sin_family = AF_INET;//协议族,跟domain一致
	s_addr.sin_port = htons(8989);//端口号一般3000以下为操作系统来用,建议用户5000以上  端口号由主机to网络 返回网络字节序的值
	inet_aton("192.168.2.13",&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig

	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来//fd,强转为struct sockaddr型,结构体的长度

	//3. listen
	listen(s_fd,10);//监听10个连接,不阻塞
	
	//4. accept 接受
	int c_fd = accept(s_fd,NULL,NULL);//先不关心客户端是谁//如果没连接到,会卡在这//后续的操作用新的c_fd
	
	//5. read
	//6. write
	
	printf("connected!\n");
	while(1)//有客户端连上,不让其退出

	return 0;
}

在这里插入图片描述
在这里插入图片描述

  • ifconfig 本机网络地址和本机回环地址:
    在这里插入图片描述

win10 telnet不是内部或外部命令(已解决)

  • telnet 在win10下默认是不开启的,所以需要我们自己手动开启。
  1. win+s 搜索:控制面板,点击进入;
    在这里插入图片描述
  2. 在控制面板中,选择程序——启动或关闭 windows 功能,勾选 Telnet 客户端选项,确定进行安装。
    在这里插入图片描述
    勾选 “Telnet 客户端”
    在这里插入图片描述
    更改 windows 设置需要一分钟左右的时间,不要关闭。安装完成后重启计算机生效。(实测可不重启)
    在这里插入图片描述
  3. windows功能的telnet功能已经开启,我们测试下是否可以正常使用,输入telnet+ip地址。
    在这里插入图片描述

6. socket服务端代码实现二(449.6)

  • SOCKET/server2.c(建立服务器并等待客户端连接 后收发)
#include <stdio.h>//printf
#include <sys/types.h>//socket bind          /* See NOTES */
#include <sys/socket.h>//socket bind
//#include <linux/in.h>//struct sockaddr_in//和<netinet/in.h>冲突
#include <arpa/inet.h>//htons
#include <netinet/in.h>//inet_aton
#include <stdlib.h>//exit
#include <string.h>//memset
#include <unistd.h>//read write
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct in_addr {
        __be32  s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度,返回新的建立的socket的通道
int main()
{
	int s_fd;//1. socket
	int c_fd;//4. accept
	int n_read;//5. read
	char readBuf[128];//5. read//定义一个数组就不用像指针还要开辟空间
	char *msg = "I get your connection\n";//6. write
	struct sockaddr_in s_addr;//2. bind
	struct sockaddr_in c_addr;//2. bind
	memset(&s_addr,0,sizeof(struct sockaddr_in));//清空
	memset(&c_addr,0,sizeof(struct sockaddr_in));//清空
	//1. socket 获取/创建套接字
	s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
	if(s_fd == -1){//判断建立socket通道是否成功
		perror("socket");//把错误的问题打出来
		exit(-1);//退出这个程序
	}
	//2. bind 绑定
	s_addr.sin_family = AF_INET;//协议族,跟domain一致
	s_addr.sin_port = htons(8989);//端口号一般3000以下为操作系统来用,建议用户5000以上  端口号由主机to网络 返回网络字节序的值
	inet_aton("192.168.2.13",&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来
	//3. listen
	listen(s_fd,10);//监听10个连接
	//4. accept 接受
	int clen = sizeof(struct sockaddr_in);
	c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//如果没连接到,会卡在这
	if(c_fd == -1){
		perror("accept");
	}
	printf("get connected: %s\n",inet_ntoa(c_addr.sin_addr));//连上后打印 “已连接” 和客户端的 ip地址
	//5. read
	n_read = read(c_fd, readBuf, 128);
	if(n_read == -1){
		perror("read");
	}else{
		printf("get message:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
	}
	//6. write
	write(c_fd,msg,strlen(msg));//用提前定义的字符串,如直接写入字符串,字节大小也随意写如128,会造成乱码因有无用的字节
	return 0;
}

在这里插入图片描述

7. socket客户端代码实现(450.7)

  • man 2 connect
  • SOCKET/client.c(连接服务器后 客户端发收)
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>//read write
//int socket(int domain, int type, int protocol);
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int main(int argc, char **argv)
{
	int c_fd;//1. socket
	int n_read;//4. read
	char readBuf[128];//4. read
	char *msg = "I'm a msg from Client";//3. write
	//1. socket 获取/创建套接字
	c_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(c_fd == -1){
		perror("socket");
		exit(-1);
	}
	//2.connect//连接服务器	
	struct sockaddr_in c_addr;
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(8989);
	inet_aton("192.168.2.13",&c_addr.sin_addr);//服务器的ip地址
	if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){//连接时会阻塞,直到出结果为之
		perror("connect");
		exit(-1);
	}
	//3. write//写
	write(c_fd,msg,strlen(msg));
	//4. read//读		
	n_read = read(c_fd, readBuf, 128);
	if(n_read == -1){
		perror("read");
	}else{
		printf("get message from server:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
	}

	return 0;
}

在这里插入图片描述

8. 实现双方聊天(451.8)

在这里插入图片描述

  • SOCKET/server3.c(服务器可以一直接收多个客户端的连接,并和某个客户端互发消息)
#include <stdio.h>//printf
#include <sys/types.h>//socket bind          /* See NOTES */
#include <sys/socket.h>//socket bind
//#include <linux/in.h>//struct sockaddr_in//冲突
#include <arpa/inet.h>//htons
#include <netinet/in.h>//inet_aton
#include <stdlib.h>//exit
#include <string.h>//memset
#include <unistd.h>//read write
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct in_addr {
        __be32  s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度,返回新的建立的socket的通道
int main(int argc, char **argv)
{
	int s_fd;//1. socket
	int c_fd;//4. accept
	int n_read;//5. read
	char readBuf[128];//5. read
	//	char *msg = "I get your connection";
	char msg[128] = {0};//6. write
	struct sockaddr_in s_addr;//2. bind
	struct sockaddr_in c_addr;//2. bind
	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	
	if(argc != 3){//如果没有输入参数 会提示
		printf("param is not good\n");
		exit(-1);
	}
	//1. socket 获取套接字
	s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
	if(s_fd == -1){//判断建立socket通道是否成功
		perror("socket");//把错误的问题打出来
		exit(-1);//退出这个程序
	}

	//2. bind 绑定
	s_addr.sin_family = AF_INET;//协议族,跟domain一致
	s_addr.sin_port = htons(atoi(argv[2]));//字符串转换为整形数
	inet_aton(argv[1],&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来

	//3. listen
	listen(s_fd,10);//监听10个连接
	
	//4. accept 接受连接
	int clen = sizeof(struct sockaddr_in);
	while(1){//不让程序退出 一直循环进行//不要在while(1)里定义变量
	//同时收和发
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//如果没连接到,会卡在这
		if(c_fd == -1){
			perror("accept");
		}
		printf("get connected: %s\n",inet_ntoa(c_addr.sin_addr));//连上后打印 “已连接” 和客户端的 ip地址
		if(fork() == 0){//在网络服务进程中父进程等待客户端的服务请求 当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达
			//6. write
			if(fork()==0){//如果要用两个while(1),要么用多线程,要么用fork创建子进程
				while(1){
					memset(msg,0,sizeof(msg));
					printf("input: ");
					//gets(msg);//gets不安全,已经被废弃
					fgets(msg,sizeof(msg),stdin);//阻塞
					msg[strcspn(msg, "\n")] = '\0';//移除输入中的换行符
					write(c_fd,msg,strlen(msg));//6. write
				}	
			}	
			//5. read
			while(1){
				memset(readBuf,0,sizeof(readBuf));//每次写之前清空
				n_read = read(c_fd, readBuf, 128);//阻塞
				if(n_read == -1){
					perror("read");
				}else{
					printf("get message from client:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
				}
			}
		}
	}
	return 0;
}
  • SOCKET/client2.c(多个客户端分别连接服务器,并和服务器互发消息)
#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
//#include <linux/in.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>//read write
//int socket(int domain, int type, int protocol);
//int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
int main(int argc, char **argv)
{
	int c_fd;//1. socket
	int n_read;//4. read
	char readBuf[128];//4. read
	//char *msg = "I'm a msg from Client";//3. write	
	char msg[128] = {0};
	if(argc != 3){//如果没有输入参数 会提示
		printf("param is not good\n");
		exit(-1);
	}
	//1. socket 获取/创建套接字
	c_fd = socket(AF_INET, SOCK_STREAM, 0);
	if(c_fd == -1){
		perror("socket");
		exit(-1);
	}
	//2.connect 连接服务器	
	struct sockaddr_in c_addr;
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	c_addr.sin_family = AF_INET;
	c_addr.sin_port = htons(atoi(argv[2]));
	inet_aton(argv[1],&c_addr.sin_addr);//服务器的ip地址
	if(connect(c_fd, (struct sockaddr *)&c_addr,sizeof(struct sockaddr)) == -1){//连接时阻塞 成功后往下
		perror("connect");
		exit(-1);
	}
		
	while(1){//不让程序退出 一直循环进行
	//同时发和收
		//3. write 写
		if(fork()==0){//如果要用两个while(1),要么用多线程,要么用fork创建子进程
			while(1){
				memset(msg,0,sizeof(msg));//每次写之前清空
				printf("input: ");
				//gets(msg);//gets不安全,已经被废弃
				fgets(msg,sizeof(msg),stdin);//阻塞
				msg[strcspn(msg, "\n")] = '\0';//移除输入中的换行符
				write(c_fd,msg,strlen(msg));
			}
		}
		//4. read 读
		while(1){
			memset(readBuf,0,sizeof(readBuf));
			n_read = read(c_fd, readBuf, 128);//阻塞
			if(n_read == -1){
				perror("read");
			}else{
				printf("get message from server:%d,%s\n",n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
			}
		}
	}

	return 0;
}

在这里插入图片描述

9. 多方消息收发(452.9)

  • 上节课的逻辑:shell终端获得输入,并不知道是哪个子进程的输入,所以返回给客户端也并不知道是哪个(子进程之间存在资源竞争)
    在这里插入图片描述
  • SOCKET/server4.c(自动主动回复给客户端消息,类似心跳包)
#include <stdio.h>//printf
#include <sys/types.h>//socket bind          /* See NOTES */
#include <sys/socket.h>//socket bind
//#include <linux/in.h>//struct sockaddr_in//冲突
#include <arpa/inet.h>//htons
#include <netinet/in.h>//inet_aton
#include <stdlib.h>//exit
#include <string.h>//memset
#include <unistd.h>//read write
//int socket(int domain, int type, int protocol);
//int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
/*struct in_addr {
        __be32  s_addr;
};*/
//int listen(int sockfd, int backlog);
//int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);//fd,客户端地址,客户端地址长度,返回新的建立的socket的通道
int main(int argc, char **argv)
{
	int s_fd;//1. socket
	int c_fd;//4. accept
	int n_read;//5. read
	int mark = 0;//第几个客户端
	char readBuf[128];//5. read
	//	char *msg = "I get your connection";
	char msg[128] = {0};//6. write
	struct sockaddr_in s_addr;//2. bind
	struct sockaddr_in c_addr;//2. bind
	memset(&s_addr,0,sizeof(struct sockaddr_in));
	memset(&c_addr,0,sizeof(struct sockaddr_in));
	
	if(argc != 3){//如果没有输入参数 会提示
		printf("param is not good\n");
		exit(-1);
	}
	//1. socket 获取套接字
	s_fd = socket(AF_INET, SOCK_STREAM, 0);//IPv4 因特网域,TCP协议,自动选择type类型对应的默认协议(也可用宏:IPPROTO_TCP TCP)
	if(s_fd == -1){//判断建立socket通道是否成功
		perror("socket");//把错误的问题打出来
		exit(-1);//退出这个程序
	}

	//2. bind 绑定
	s_addr.sin_family = AF_INET;//协议族,跟domain一致
	s_addr.sin_port = htons(atoi(argv[2]));//字符串转换为整形数
	inet_aton(argv[1],&s_addr.sin_addr);//本机ip地址由字符串形式to网络格式//ifconfig
	bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));//把ip地址端口号和s_fd绑定起来

	//3. listen
	listen(s_fd,10);//监听10个连接
	
	//4. accept 接受连接
	int clen = sizeof(struct sockaddr_in);
	while(1){//不让程序退出 一直循环进行//不要在while(1)里定义变量
	//同时收和发
		c_fd = accept(s_fd,(struct sockaddr *)&c_addr,&clen);//如果没连接到,会卡在这
		if(c_fd == -1){
			perror("accept");
		}
		mark++;
		printf("get connected: %s\n",inet_ntoa(c_addr.sin_addr));//连上后打印 “已连接” 和客户端的 ip地址
		if(fork() == 0){//在网络服务进程中父进程等待客户端的服务请求 当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达//一有客户端接入就调用子进程
			//6. write
			if(fork()==0){//如果要用两个while(1),要么用多线程,要么用fork创建子进程
				while(1){
					sprintf(msg,"welcome NO.%d Client",mark);//每个客户端都能知道其连接有无丢失
					write(c_fd,msg,strlen(msg));//6. write//对于服务端都能收到客户端的请求
					sleep(3);//类似心跳包,每隔3s发一串话
				}	
			}	
			//5. read
			while(1){//接收每一个客户端发来的消息
				memset(readBuf,0,sizeof(readBuf));//每次写之前清空
				n_read = read(c_fd, readBuf, 128);//阻塞
				if(n_read == -1){
					perror("read");
				}else{
					printf("get message from NO.%d Client :%d,%s\n",mark,n_read,readBuf);//打印收到了多少个字节的消息,和消息的内容
				}
			}
		}
	}
	return 0;
}

在这里插入图片描述

10. 项目运行结果(453.1)

在这里插入图片描述

11. 项目研发思路(454.2)

客户端要实现的指令:

  • get a.c:获取服务器的文件 a.c
  • put a.c:上传文件 a.c 到服务器
  • cd a:进入服务器某文件夹 a
  • ls:展示服务器有哪些文件和文件夹
  • pwd:显示当前文件夹所在路径
  • lcd aa:进入客户端本地的某文件夹 aa
  • lls:展示客户端本地有哪些文件和文件夹
  • quit:退出连接

服务端去解析这些指令,执行这些指令,返回这些指令的结果

  • 自行搜索 “Linux 判断文件是否存在” 的函数,写 demo 测试,再整合进项目中
    在这里插入图片描述
  • recv 和 read 区别:
    • recv 第四个参数 MSG_PEEK 就可以多次读,其返回值等0时表示客户端连接断开,小于0读数据失败
    • read 只能读一次套接字中的数据就
      在这里插入图片描述
      在这里插入图片描述

12. 项目指导(455.3)

  • 服务端
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
  • 客户端
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

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

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

相关文章

C#使用mysql-connector-net驱动连接mariadb报错

给树莓派用最新的官方OS重刷了一下&#xff0c;并且用apt install mariadb-server装上“mysql”作为我的测试服务器。然后神奇的事情发生了&#xff0c;之前用得好好的程序突然就报错了&#xff0c;经过排查&#xff0c;发现在连接数据库的Open阶段就报错了。写了个最单纯的Con…

Wpf 使用 Prism 实战开发Day01

一.开发环境准备 1. VisualStudio 2022 2. .NET SDK 7.0 3. Prism 版本 8.1.97 以上环境&#xff0c;如有新的版本&#xff0c;可自行选择安装新的版本为主 二.创建Wpf项目 1.项目的名称:MyToDo 项目名称:这里只是记录学习&#xff0c;所以随便命名都无所谓,只要觉得合理就…

水声功率放大器的应用场景是什么

水声功率放大器是一种专门用于水声信号处理和传输的设备&#xff0c;通过放大水声信号的功率&#xff0c;以实现远距离传播和提高信号的清晰度和可辨识度。下面是关于水声功率放大器应用场景的详细解释&#xff1a; 水声通信&#xff1a;水声通信是一种在水下进行声波传输的技术…

sharepoint2016-2019升级到sharepoint订阅版

一、升级前准备&#xff1a; 要建立新的sharepoint订阅版环境&#xff0c;需求如下&#xff1a; 1.单服务器硬件需求CPU 4核&#xff0c;内存24G以上&#xff0c;硬盘300G&#xff08;根据要迁移的数量来扩容大小等&#xff09;&#xff1b; 2.操作系统需要windows server 20…

接口自动化测试工具,Postman使用详解

一、概念 1、Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件&#xff0c;Postman分为Postman native app和Postman Chrome app两个版本。目前Chrome app已经停止维护&#xff0c;官方也不推荐使用该版本。 2、官网下载地址&#xff1a;http://www.getpostman…

云计算与ai人工智能对高防cdn的发展

高防CDN&#xff08;Content Delivery Network&#xff09;作为网络安全领域的一项关键技术&#xff0c;致力于保护在线内容免受各种网络攻击&#xff0c;包括分布式拒绝服务攻击&#xff08;DDoS&#xff09;等。然而&#xff0c;随着人工智能&#xff08;AI&#xff09;和大数…

jquery中定义的动态生成的标签元素,点击事件该方法未定义Uncaught ReferenceError: goHere is not defined

如下图&#xff1a; 在点击动态生成的弹窗里的html中的企业列表标签时&#xff08;该标签绑定了点击事件-goHere&#xff09;&#xff0c; 会提示&#xff1a;Uncaught ReferenceError: goHere is not defined 生成的html代码&#xff1a; // 自定义content function showCo…

Postman如何做接口自动化测试?

前言 什么是自动化测试 把人对软件的测试行为转化为由机器执行测试行为的一种实践。 例如GUI自动化测试&#xff0c;模拟人去操作软件界面&#xff0c;把人从简单重复的劳动中解放出来。 本质是用代码去测试另一段代码&#xff0c;属于一种软件开发工作&#xff0c;已经开发完…

C# 图解教程 第5版 —— 第10章 语句

文章目录 10.1 什么是语句&#xff08;*&#xff09;10.2 表达式语句10.3 控制流语句10.4 if 语句&#xff08;*&#xff09;10.5 if ... else 语句&#xff08;*&#xff09;10.6 while 循环&#xff08;*&#xff09;10.7 do 循环&#xff08;*&#xff09;10.8 for 循环10.8…

视觉SLAM数据集(三):KITTI 数据集

教程目录 一、官网二、注册登录三、下载数据集四、测试数据集 一、官网 官网地址&#xff1a;https://www.cvlibs.net/datasets/kitti/eval_odometry.php Kitti数据集很庞大&#xff0c;包含了双目、光流、场景流、深度、里程计、目标、跟踪、马路、语义、原始数据等大类别&…

HarmonyOS原生分析能力,即开即用助力精细化运营

数据分析产品对开发者的价值呈现在两个层面&#xff0c;第一个是产品的层面&#xff0c;可以通过数据去洞察用户的行为&#xff0c;从而找到产品的优化点。另外一个就是运营层面&#xff0c;可以基于数据去驱动&#xff0c;来实现私域和公域的精细化运营。 在鸿蒙生态上&#…

云服务器搭建Zookeeper集群

文章目录 1.集群配置2.zookeeper的群起脚本3. Zookeeper节点的创建和删除相关4. Zookeeper的选举机制 1.集群配置 Zookeeper的集群个数最好保证是奇数个数&#xff0c;因为Zookeeper的选举过程有一个“半数机制”。 5台服务器&#xff0c;可以设置Zookeeper的集群为3或者5&…

矩阵特征值与特征向量的理解

各位朋友大家好&#xff0c;我是小C哈哈哈&#xff0c;很高兴认识大家&#xff0c;在这里&#xff0c;我会将一些枯燥难懂的数学和算法知识以图片或动画的形式通俗易懂的展现给大家&#xff0c;希望大家喜欢。 线性代数中的矩阵特征值与特征向量这两个基本概念总是让很多人摸不…

10款轻量型的嵌入式GUI库分享

LVGL LittlevGL是一个免费的开源图形库&#xff0c;提供了创建嵌入式GUI所需的一切&#xff0c;具有易于使用的图形元素、漂亮的视觉效果和低内存占用。 特点&#xff1a; 强大的构建模组 按钮、图表、列表、滑块、图像等 ​先进的图形 动画、反锯齿、半透明、平滑滚动 多样…

嵌入式系统中C++ 类的设计和实现分析

C代码提供了足够的灵活性&#xff0c;因此对于大部分工程师来说都很难把握。 本文介绍了写好C代码需要遵循的10个最佳实践&#xff0c;并在最后提供了一个工具可以帮助我们分析C代码的健壮度。 原文&#xff1a;10 Best practices to design and implement a C class。 1. 尽…

Vue-dvadmin-d2-crud-plus-自定义后台菜单-添加页面

文章目录 1.新建数据模型2.新建数据序列类3.新建数据视图4.配置路由5.前端新建View组件6.配置后台7.总结 django-vue-admin是一套全部开源的快速开发平台&#xff0c;毫无保留给个人及企业免费使用。 &#x1f9d1;‍&#x1f91d;‍&#x1f9d1;前端采用D2Admin 、Vue、Eleme…

calcite 校验层总结

1、校验的作用 1&#xff09;完善语义信息 例如在SQL语句中&#xff0c;如果碰到select * 这样的指令&#xff0c;在SQL的语义当中&#xff0c;“*” 指的是取出对应数据源中所有字段的信息&#xff0c;因此就需要根据元数据信息来展开。 2&#xff09;结合元数据信息来纠偏…

分享一下怎么做陪诊小程序

在当今快节奏的社会中&#xff0c;人们的生活压力越来越大&#xff0c;尤其是在大城市中&#xff0c;由于工作繁忙&#xff0c;生活节奏快&#xff0c;很多人都感到看病难、看病贵的问题。为了解决这一问题&#xff0c;陪诊小程序应运而生。陪诊小程序是一种可以提供线上预约、…

世界前沿技术发展报告2023《世界航空技术发展报告》(四)无人机技术

&#xff08;四&#xff09;无人机技术 1.无人作战飞机1.1 美国空军披露可与下一代战斗机编组作战的协同式无人作战飞机项目1.2 俄罗斯无人作战飞机取得重要进展 2.支援保障无人机2.1 欧洲无人机项目通过首个里程碑2.2 美国海军继续开展MQ-25无人加油机测试工作 3.微小型无人机…

shell脚本的编写(输入、输出、变量、数组等的使用规范及实例)

1.shell中变量的定义 使用变量的值&#xff1a; 例子&#xff1a; 2.外部传参/位置变量 例子&#xff1a; 3.输出---echo 4.输入---read 5.命令置换符 作用:把指令的运行结果赋值给变量 6.数组--shell支持稀疏数组