tftp协议(客户端和服务端)c语言实现

首先说结论, 看这个开源博客吧(linux下能运行):GitCode - 开发者的代码家园

网上搜索该资料,有很多知乎或者csdn相关博客,但是很多都是复制来的,代码不全,无法运行。这里给大家推荐这个我找到的开源代码,简单又完整(其它一些开源博客,要么代码量太大太复杂,要么拆成很多个c文件,不便于理解)。此外,该协议原理解释看这个博客: TFTP是什么,一文带你了解-CSDN博客

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#include <setjmp.h>

#define DATA_SIZE   	 512
#define MAX_FILENAME	 255
#define INITIAL_BLOCK 0
#define MAX_TIMEOUTS	 5
#define TIMEOUT_SECS	3

/* Opcodes */
#define RRQ    1
#define WRQ    2
#define DATA   3
#define ACK	   4
#define ERROR  5

static const char *TFTP_error_messages[] = {
	"Undefined error",                 // Error code 0
	"File not found",                  // 1
	"Access violation",                // 2
	"Disk full or allocation error",   // 3
	"Illegal TFTP operation",          // 4
	"Unknown transfer ID",             // 5
	"File already exists",             // 6
	"No such user"                     // 7
};
extern int errno;
typedef struct {
	unsigned short int opcode;
	char filename[MAX_FILENAME];
	char zero_0;
	char mode[MAX_FILENAME];
	char zero_1;
} TFTP_Request;
typedef struct {
	unsigned short int opcode;
	unsigned short int block;
	char data[DATA_SIZE];
} TFTP_Data;
typedef struct {
	unsigned short int opcode;
	unsigned short int block;
} TFTP_Ack;

/* Global vars */
static int is_debugging = 0, timeout;
jmp_buf timeoutbuf, endbuf;

int get_port(char* s) {
	 int retval = 0;
	 char *a = s;
	 while (*a != '\0') {
		  if (*a >= '0' && *a <= '9') {
				retval = retval * 10 + (*a - '0');
		  } else {
				return -1;
		  }
		  a++;
	 }
	 return retval;
}

/* Returns 0 for sucess, otherwise -1. */
int make_socket(struct sockaddr_in *s, char *host, int port) {
	s->sin_family = AF_INET;
	if (host != NULL) {
		struct hostent *he = gethostbyname(host);
		if (he == NULL) {
			perror("gethostbyname");
			return -1;
		}
		s->sin_addr = *((struct in_addr *)he->h_addr);
	} else {
		s->sin_addr.s_addr = htonl(INADDR_ANY);
	}
	s->sin_port = htons(port);
	memset(&(s->sin_zero), 0, 8);
	return 0;
}

/* Returns 0 a file that exists, other -1. */
int file_exists(char *filename) {
	struct stat filebuf;
	if ( stat(filename, &filebuf) == 0 ) {
		return 0;
	} else {
		return -1;
	}
}

/* Fill in the struct using data from buffer */
void packet_to_request(TFTP_Request *r, char *buf) {
	char filename[MAX_FILENAME];
	char mode[MAX_FILENAME];
	short signed int code;
	code = *(short signed int*)buf;
	buf += sizeof(r->opcode);
	strcpy(filename, buf);
	buf += strlen(filename) + 1;
	strcpy(mode, buf);
	r->opcode = ntohs(code);
	strcpy(r->filename, filename);
	r->zero_0 = '\0';
	strcpy(r->mode, mode);
	r->zero_1 = '\0';
}

/* Fill the given buffer using data from the given request */
void request_to_packet(TFTP_Request *r, char *buf) {
	char *pos = buf;
	*(short signed int*)pos = htons(r->opcode);
	pos += sizeof(r->opcode);
	strcpy(pos, r->filename);
	pos += strlen(r->filename) + 1;
	*pos = r->zero_0;
	strcpy(pos, r->mode);
	pos += strlen(r->mode) + 1;
	*pos = r->zero_1;
}

/* Computes length of request */
int request_length(TFTP_Request *r) {
	int len = sizeof(r->opcode) + sizeof(r->zero_0) + sizeof(r->zero_1);
	len += strlen(r->filename) + 1;
	len += strlen(r->mode) + 1;
	return len;
}

/* Returns 0 if request has the given mode, otherwise 0 */
int request_is_mode(TFTP_Request *r, char *mode) {
	if (strcmp(r->mode, mode) == 0) return 0;
	return -1;
}

void request_init(TFTP_Request *r, unsigned short int opcode, char *filename, char *mode) {
	memset(r, 0, sizeof(TFTP_Request));
	r->opcode = opcode;
	strcpy(r->filename, filename);
	r->zero_0 = '\0';
	strcpy(r->mode, "octet");
	r->zero_1 = '\0';
}

void timer(int sig) {
	switch(sig) {
		case SIGALRM: {
			timeout++;
			if (timeout >= MAX_TIMEOUTS) {
				if (is_debugging) printf("Retransmission timed out.\n");
				timeout = 0;
				alarm(0);
				longjmp(endbuf, sig);
			}
			if (is_debugging) printf("Retransmitting.\n");
			longjmp(timeoutbuf, sig);
		} break;
		case SIGINT: {
			if (is_debugging) printf("Transfer interrupted.\n");
			timeout = 0;
			alarm(0);
			longjmp(endbuf, sig);
		} break;
		default: break;
	}
}

void send_data(int sockfd, struct sockaddr *to_addr, socklen_t addr_len, char *filename) {
	int filesize, n, pos = 0, nextAck = -1;
	signed short int block = 0; 
	int fd = open(filename, O_RDONLY, 0006);
	
	if (fd == -1) {
		perror("open");
		exit(1);
	}
	filesize = lseek(fd, 0, SEEK_END);
	lseek(fd, 0, SEEK_SET);
	
	/* Allocate memory for DATA, ACK structs */
	TFTP_Data *dataPacket;
	TFTP_Ack *ack;
	dataPacket = (TFTP_Data *)malloc(sizeof(TFTP_Data));
	ack = (TFTP_Ack *)malloc(sizeof(TFTP_Ack));
	memset(dataPacket, 0, sizeof(TFTP_Ack));
	memset(ack, 0, sizeof(TFTP_Ack));
	
	/* Read from file and send data to server */
	while (pos < filesize) {
		char dataBuf[DATA_SIZE] = {0};
		n = read(fd, &dataBuf, DATA_SIZE);
		if (n == -1) {
			perror("read");
			exit(1);
		}
		pos += n;
		
		block++;
		dataPacket->opcode = htons(DATA);
		dataPacket->block = htons(block);
		if (is_debugging) printf("Block #%d, %d bytes\n", block, n);
		memset(dataPacket->data, 0, DATA_SIZE);
		memcpy(dataPacket->data, dataBuf, n);
		
		sigsetjmp(timeoutbuf, 1); // jump for retransmission
		if (is_debugging) printf("Sending DATA for block #%d\n", block);
		n = sendto(sockfd, dataPacket, 4 + n, 0, to_addr, addr_len);
		if (n < 0) {
			if (is_debugging) printf("Error sending DATA block #%d\n", block);
			break;
		}
		
		if (sigsetjmp(endbuf, 1) != 0) {
			// setup jump for retransmission timeout and interrupt
			break;
		}
		signal(SIGINT, timer);
		signal(SIGALRM, timer);
		
		while (nextAck < 0) {
			/* Receive ACK for the sent DATA */
			if (is_debugging) printf("Waiting for ACK...\n");
			alarm(TIMEOUT_SECS); // start new timer
			n = recvfrom(sockfd, ack, sizeof(TFTP_Ack), 0, to_addr, &addr_len);
			timeout = 0;
			alarm(0);
			if (n < 0) {
				if (is_debugging) printf("Error receiving ACK for block #%d\n", block);
				break;
			}
			
			if (ntohs(ack->opcode) == ERROR) {
				if (is_debugging) printf("Received ERROR: %s\n", TFTP_error_messages[ntohs(ack->block)]);
			}
			else if (ntohs(ack->opcode) == ACK) {
				/* Check block */
				if (ntohs(ack->block) == block) {
					nextAck = 1;
					if (pos == filesize) {
						if (is_debugging) printf("Received ACK for final block #%d\n", block);
						break;
					} else {
						if (is_debugging) printf("Received ACK for block #%d\n", block);
						continue;
					}
				} else if (ntohs(ack->block) < block) {
					nextAck = -1;
				}
			}
		}
		
		nextAck = -1;
	}
	
	free(dataPacket);
	free(ack);
	close(fd);
}

void recv_data(int sockfd, char *filename) {
	struct sockaddr client_addr;
	int n;
	socklen_t clilen;
	short signed int block = 0, nextBlock = 1;

	/* Allocate memory for DATA, ACK and FILE structs */
	TFTP_Data *dataPacket = malloc(sizeof(TFTP_Data));
	TFTP_Ack *ack = malloc(sizeof(TFTP_Ack));
	memset(dataPacket, 0, sizeof(TFTP_Data));
	memset(ack, 0, sizeof(TFTP_Ack));
	FILE * file = fopen(filename, "ab");
	
	while (1) {
		clilen = sizeof(struct sockaddr);
		int length;
		
		if (sigsetjmp(endbuf, 1) != 0) {
			// setup jump for retransmission timeout and interrupt
			break;
		}
		signal(SIGINT, timer);
		signal(SIGALRM, timer);
		
		/* Receive the DATA */
		if (is_debugging) printf("Waiting for DATA...\n");
		alarm(TIMEOUT_SECS); // start new timer
		n = recvfrom(sockfd, dataPacket, sizeof(TFTP_Data), 0, (struct sockaddr *)&client_addr, &clilen);
		timeout = 0;
		alarm(0); // void timer
		if (n < 0) break;
		
		/* Received a duplicate DATA block */
		if (ntohs(dataPacket->block) < nextBlock) {
			if (is_debugging) printf("Received duplicate DATA for block #%d\n", ntohs(dataPacket->block));
		}
		else {
			length = strlen(dataPacket->data);
			if (length == 0) break;
			
			/* Fill the data buffer */
			char dataBuf[DATA_SIZE+1];
			strcpy(dataBuf, dataPacket->data);
			if (length > DATA_SIZE) {
				dataBuf[DATA_SIZE] = '\0';
				length = strlen(dataBuf);
			}
			if (is_debugging) printf("Received DATA for block #%d of size %d\n", ntohs(dataPacket->block), length);

			/* Write data to the file and check if disk is full */
			fwrite(dataBuf, sizeof(char), length, file);
			if (errno == ENOSPC) {
				if (is_debugging) printf("Sending error: %s\n", TFTP_error_messages[3]);
				ack->opcode = htons(ERROR);
				ack->block = htons(3);
				n = sendto(sockfd, ack, sizeof(TFTP_Ack), 0, &client_addr, clilen);
				break;
			}

			/* Fill ACK if correct block received */
			block = nextBlock;
			nextBlock++;
			ack->opcode = htons(ACK);
			ack->block = htons(block);
		}
		
		sigsetjmp(timeoutbuf, 1); // jump for retransmission
		if (is_debugging) printf("Sending ACK for block #%d\n", block);
		n = sendto(sockfd, ack, sizeof(TFTP_Ack), 0, &client_addr, clilen);
		if (n < 0) {
			printf("Error sending ACK.\n");
			break;
		}
		
		/* last block of DATA */
		if (length < DATA_SIZE) break;
	}

	free(dataPacket);
	free(ack);
	fclose(file);
}

void send_error(int sockfd, struct sockaddr *to_addr, socklen_t addrlen, TFTP_Ack *ack, char *msg) {
	int len = sizeof(TFTP_Ack)+strlen(msg)+1;
	char *buf = (char *)malloc(len);
	char *pbuf = buf;
	memset(buf, 0, len);
	*(short signed int*)pbuf = htons(ack->opcode);
	pbuf += sizeof(ack->opcode);
	*(short signed int*)pbuf = htons(ack->block);
	pbuf += sizeof(ack->block);
	strcpy(pbuf, msg);
	sendto(sockfd, buf, len, 0, to_addr, addrlen);
	free(buf);
}

int server_process(int oldsockfd, struct sockaddr *client_addr, TFTP_Request *request) {
	int pid = fork();
	if (pid < 0) {
		perror("fork");
		return -1;
	}
	if (pid == 0) {
		close(oldsockfd);
		
		int sockfd = 0;
		if ((sockfd=socket(AF_INET,SOCK_DGRAM,0)) == -1) {
			perror("socket");
			exit(1);
		}
		struct sockaddr_in serv_addr;
		make_socket(&serv_addr, NULL, 0);
		if (bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1) {
			perror("bind");
			exit(0);
		}
		unsigned int addr_len = sizeof(struct sockaddr);
		if (getsockname(sockfd, (struct sockaddr *)&serv_addr, &addr_len) == -1) {
			perror("getsockname");
			exit(1);
		}
		if (is_debugging) printf("Child process listening on port %i\n", ntohs(serv_addr.sin_port));
		
		/* Allocate memory for ACK struct */
		TFTP_Ack *ack = (TFTP_Ack *)malloc(sizeof(TFTP_Ack));
		memset(ack, 0, sizeof(TFTP_Ack));
		
		/* Octet mode only */
		if (request_is_mode(request, "octet") != 0) {
			ack->opcode = htons(ERROR);
			ack->block = htons(0);
			send_error(sockfd, client_addr, addr_len, ack, "mode not supported");
			free(ack);
			close(sockfd);
			free(request);
			exit(1);
		}
		
		if (request->opcode == WRQ) {
			/* file should not exist locally */
			if ( file_exists(request->filename) == 0 ) {
				exit(1);
			}
			
			/* Fill ACK struct and compute packet length */
			ack->opcode = htons(ACK);
			ack->block = htons(INITIAL_BLOCK);
			/* Send ACK and start receiving DATA */
			sendto(sockfd, ack, sizeof(TFTP_Ack), 0, client_addr, addr_len);
			recv_data(sockfd, request->filename);
		}
		else if (request->opcode == RRQ) {
			/* file must exist locally */
			if ( file_exists(request->filename) == -1 ) {
				exit(1);
			}
			/* Send data */
			send_data(sockfd, client_addr, addr_len, request->filename);
		}
		else {
			if (is_debugging) printf("Received request with unknown opcode: %i\n", request->opcode);
		}
		
		free(ack);
		close(sockfd);
		free(request);
		exit(0);
	}
	return pid;
}

void chld_trap(int s) {
	int pid = wait(NULL);
	if (pid < 0) {
		return; // wait went wrong, fly away
	} 
}

void run_server(int port) {
	/* install signal handlers */
	signal(SIGCHLD, chld_trap);
	
	int sockfd;
	struct sockaddr_in my_addr;
	struct sockaddr_in client_addr;
	unsigned int addr_len, numbytes;
	char *buf;
	
	/* Try to bind socket to the port */
	if ((sockfd=socket(AF_INET,SOCK_DGRAM,0)) == -1) {
		perror("socket");
		exit(1);
	}
	make_socket(&my_addr, NULL, port);
	if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
		perror("bind");
		exit(1);
	}
	
	/* Listen for incoming requests until program is teminated */
	if (is_debugging) printf("Listening on port %i\n", ntohs(my_addr.sin_port));
	while (1) {
		buf = (char *)malloc( sizeof(TFTP_Request) );
		memset(buf, 0, sizeof(TFTP_Request));
		addr_len = sizeof(struct sockaddr);
		
		numbytes = recvfrom(sockfd, buf, sizeof(TFTP_Request), 0, (struct sockaddr *)&client_addr, &addr_len);
		if (numbytes < 0) {
			free(buf);
			continue;
		}
		
		if (is_debugging) {
			printf("Got packet from %s:%d, %i bytes.\n",
						inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), numbytes
			);
		}
		
		TFTP_Request *request = (TFTP_Request *)malloc( sizeof(TFTP_Request) );
		packet_to_request(request, buf);
		free(buf);
		
		server_process(sockfd, (struct sockaddr *)&client_addr, request);
		free(request);
	}
	
	close(sockfd);
}

void send_request_read(char *host, int port, char *filename) {
	int n, len;
	int mysockfd;
	struct sockaddr_in serv_addr;
	struct sockaddr_in my_addr;
	unsigned int addr_len;
	
	/* Prepare the sockets */
	make_socket(&serv_addr, host, port);
	if ((mysockfd=socket(AF_INET,SOCK_DGRAM,0)) == -1) {
		perror("socket");
		exit(1);
	}
	make_socket(&my_addr, NULL, 0);
	if (bind(mysockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
		perror("bind");
		exit(1);
	}
	addr_len = sizeof(struct sockaddr);
	
	/* Allocate the Ack struct */
	TFTP_Ack *ack =  (TFTP_Ack *)malloc(sizeof(TFTP_Ack));
	memset(ack, 0, sizeof(TFTP_Ack));
	
	/* Create the request */
	TFTP_Request *request = (TFTP_Request *)malloc(sizeof(TFTP_Request));
	request_init(request, RRQ, filename, "octet");
	len = request_length(request);
	char *req_buffer = (char*)malloc(len);
	memset(req_buffer, 0, len);
	request_to_packet(request, req_buffer);
	
	/* Send the request */
	sigsetjmp(timeoutbuf, 1);
	if (is_debugging) printf("Sending read request to server, %i bytes.\n", len);
	n = sendto(mysockfd, req_buffer, len, 0, (struct sockaddr *)&serv_addr, addr_len);
	if (n < 0) {
		if (is_debugging) printf("Error sending read request!\n");
		free(ack);
		free(request);
		free(req_buffer);
		close(mysockfd);
		exit(1);
	}
	
	/* Just receive data */
	recv_data(mysockfd, filename);
	
	free(ack);
	free(request);
	free(req_buffer);
	close(mysockfd);
}

void send_request_write(char *host, int port, char *filename) {
	int mysockfd, n, len;
	struct sockaddr_in serv_addr, my_addr;
	unsigned int addr_len;
	
	/* Prepare the sockets */
	make_socket(&serv_addr, host, port);
	if ((mysockfd=socket(AF_INET,SOCK_DGRAM,0)) == -1) {
		perror("socket");
		exit(1);
	}
	make_socket(&my_addr, NULL, 0);
	if (bind(mysockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1) {
		perror("bind");
		exit(1);
	}
	addr_len = sizeof(struct sockaddr);
	
	/* Allocate the Ack struct */
	TFTP_Ack *ack =  (TFTP_Ack *)malloc(sizeof(TFTP_Ack));
	memset(ack, 0, sizeof(TFTP_Ack));
	
	/* Create the request */
	TFTP_Request *request = (TFTP_Request *)malloc(sizeof(TFTP_Request));
	request_init(request, WRQ, filename, "octet");
	len = request_length(request);
	char *req_buffer = (char*)malloc(len);
	memset(req_buffer, 0, len);
	request_to_packet(request, req_buffer);
	
	/* Send the request */
	sigsetjmp(timeoutbuf, 1); // jump for retransmission
	if (is_debugging) printf("Sending write request to server, %i bytes.\n", len);
	n = sendto(mysockfd, req_buffer, len, 0, (struct sockaddr *)&serv_addr, addr_len);
	if (n < 0) {
		if (is_debugging) printf("Error sending write request!\n");
		exit(1);
	}
	
	if (sigsetjmp(endbuf, 1) != 0) {
		// jump for retransmission failure or interrupt
		free(ack);
		free(request);
		free(req_buffer);
		close(mysockfd);
		exit(1);
	}
	
	/* Wait for the Ack */
	if (getsockname(mysockfd, (struct sockaddr *)&my_addr, &addr_len) == -1) {
		if (is_debugging) perror("getsockname");
		exit(1);
	}
	if (is_debugging) printf("Waiting for ACK on port %d...\n", ntohs( my_addr.sin_port ));
	signal(SIGINT, timer);
	signal(SIGALRM, timer);
	alarm(TIMEOUT_SECS);
	n = recvfrom(mysockfd, ack, sizeof(TFTP_Ack), 0, (struct sockaddr *)&serv_addr, &addr_len);
	alarm(0);
	timeout = 0;
	if (n < 0) {
		if (is_debugging) printf("Error receiving ACK from server!\n");
		exit(1);
	}
	
	/* Check the Opcode */
	if (ntohs(ack->opcode) == ERROR) {
		if (is_debugging) printf("Received ERROR: %s\n", TFTP_error_messages[ntohs(ack->block)]);
	}
	else if ( ntohs(ack->opcode) == ACK && ntohs(ack->block) == INITIAL_BLOCK ) {
		if (is_debugging) printf("Received ACK for block #%d\n", ntohs(ack->block));
		send_data(mysockfd, (struct sockaddr *)&serv_addr, addr_len, filename);
	} else {
		if (is_debugging) printf("Received packet other than expected ACK\n");
	}
	
	free(ack);
	free(request);
	free(req_buffer);
	close(mysockfd);
}

void run_client(char *host, int port, char mode, char *filename) {
	void (* sender)(char *, int , char *) = NULL;
	int exist = (mode == 'r') ? 0 : -1;
	if (file_exists(filename) == exist) {
		/* Nothing to do here */
		exit(1);
	}
	sender = (mode == 'r') ? &send_request_read : &send_request_write;
	if (sender != NULL) sender(host, port, filename);
}

/*
 * Server: mytftp -l [-p port] [-v]
 * Client: mytftp [-p port] [-v] [-r|w file] host
 */
int main(int argc, char** argv) {
	int server = 0;
	int port = 3335;
	char mode = 0;
	char *filename = NULL;
	char *host = NULL;
	
	/* Parse the arguments */
	while (--argc > 0) {
		char *str = *++argv;
		if (*str != '-') {
			host = (char *)malloc( sizeof(char)*(strlen(str)+1) );
			strcpy(host, str);
			continue;
		}
		str++;
		if (*str == 'l') {
			server = 1;
		}
		else if (*str == 'p') {
			if (--argc > 0) {
				port = get_port(*++argv);
				if (port < 0) {
					printf("Invalid port number: %s\n", *argv);
					exit(0);
				}
			}
		}
		else if (*str == 'v') {
			is_debugging = 1;
			printf("Verbose mode on.\n");
		}
		else if (*str == 'r' || *str == 'w') {
			mode = *str;
			--argc;
			filename = (char *)malloc( sizeof(char)*(strlen(*++argv)+1) );
			strcpy(filename, *argv);
		}
	}
	
	if (server == 1) {
		run_server(port);
	} else {
		if (host != NULL && mode > 0 && filename != NULL) {
			run_client(host, port, mode, filename);
			free(host);
			free(filename);
		} else {
			printf("Usage:\nServer: mytftp -l [-p port] [-v]\nClient: mytftp [-p port] [-v] [-r|w file] host\n");
		}
	}

	return 0;
}

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

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

相关文章

C# wpf 运行时替换方法实现mvvm自动触发刷新

文章目录 前言一、如何实现&#xff1f;1、反射获取属性2、定义替换方法3、交换属性的setter方法 二、完整代码1、接口2、项目 三、使用示例1、倒计时&#xff08;1&#xff09;、继承ViewModelBase&#xff08;2&#xff09;、定义属性&#xff08;3&#xff09;、属性赋值&am…

小程序地理位置接口怎么开通?

小程序地理位置接口有什么功能&#xff1f; 如果我们提审后驳回理由写了“当前提审小程序代码包中地理位置相关接口( chooseAddress、getLocation )暂未开通&#xff0c;建议完成接口开通后或移除接口相关内容后再进行后续版本提审”&#xff0c;如果你也碰到类似问题&#xf…

C#基础之冒泡排序

排序初探 文章目录 冒泡排序1、概念2、冒泡排序的基本原理3、代码实现思考1 随机数冒泡排序思考2 函数实现排序 冒泡排序 1、概念 将一组无序的记录序列调整为有序的记录序列&#xff08;升、降序&#xff09; 2、冒泡排序的基本原理 两两相邻&#xff0c;不停比较&#x…

mySQL商城项目实战 (终)(全部表)(1-88张)

本章无sql语句&#xff0c;直接放转出的sql文件。 88张表结果如图! 资源在已经与文章绑定&#xff0c; 在navicat工具中&#xff0c;执行以下步骤 在新建的数据库中右键,点击【运行sql文件】&#xff0c;运行绑定的资源&#xff0c;之后您就可以在您的navicat中看到我建好的8…

OpenLayers入门①(引入的是一个高德地图)

OpenLayers入门&#xff08;一&#xff09; - 知乎 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport&qu…

使用 LooperPrinter 监控 Android 应用的卡顿

在 Android 开发中&#xff0c;主线程&#xff08;UI线程&#xff09;的卡顿直接影响用户体验。LooperPrinter 是一种有效的工具&#xff0c;可以帮助我们监测和识别这些卡顿。下面是如何实现 LooperPrinter 监控的详细步骤和相应的 Kotlin 代码示例。 步骤 1: 创建自定义的 P…

【java超方便的导入导出工具类】SpringBoot操作Excel导入和导出

Excel导入和导出 一、前期准备 1、首先导入主要的依赖 <dependencies><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.7.0</version></dependency><depende…

Stable Diffusion 模型分享:Counterfeit-V3.0(动漫)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里&#xff0c;订阅后可阅读专栏内所有文章。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 高质量动漫风格模型。 条目内容类型大模型基础模…

关于使用SpringSecurity框架发起JSON请求,但因登陆失效导致响应403的问题。

这里记录一个生产中遇到的一个问题。 现有环境是基于SpringBoot 2.6.8&#xff0c;然后是前后台一体化的项目。 安全框架使用的是内置版本的SpringSecurity。 在实际使用过程中遇到一个问题。 就是当用户登陆失效后&#xff0c;前端操作JSON请求获取列表数据&#xff0c;但…

【知识学习/复习】损失函数篇,包含理解应用与分类:回归、分类、排序、生成等任务

损失函数总结 一、损失函数理解二、不同任务的损失函数的应用1.图像分类2.目标检测3.语义分割4.自然语言处理&#xff08;NLP&#xff09;5.图神经网络&#xff08;GNN&#xff09;6.生成式网络 三、损失函数1. 回归任务损失函数常见损失函数IoU系列损失函数1. IoU损失函数&…

微信开发api、微信视频号开发

接口地址&#xff1a; http://api.videostui.com/finder/v2/api/login/checkLogin 接口说明 获取到登录二维码后需每间隔5s调用本接口来判断是否登录成功新设备登录平台&#xff0c;次日凌晨会掉线一次&#xff0c;重新登录时需调用获取二维码且传appId取码&#xff0c;登录成…

Outlook邮箱如何撤回一封已发送邮件?~网页版上

点【已发送邮件】 双击要撤回的已发送的那个邮件 点【…】 点击【撤回消息】 点【确定】 结束&#xff01;

使用LocalGPT+cpolar打造可远程访问的本地私有类chatgpt服务

文章目录 前言环境准备1. localGPT部署2. 启动和使用3. 安装cpolar 内网穿透4. 创建公网地址5. 公网地址访问6. 固定公网地址 前言 本文主要介绍如何本地部署LocalGPT并实现远程访问&#xff0c;由于localGPT只能通过本地局域网IP地址端口号的形式访问&#xff0c;实现远程访问…

【源代码】使用Vision Pro远程操控机器人

1、OpenTeleVision 是一个开源项目&#xff0c;提供远程操作功能 2、可以从 VisionPro 或 Meta Quest 3 中流式传输头部、手部和腕部数据 3、可以将实时立体视频从摄像头流式传输到 VR 设备 4、需要在 Ubuntu 机器上安装 Zed SDK 和 mkcert&#xff0c;以便在本地进行测试 …

全新突破:「Paraverse平行云」实现3D/XR企业级应用全面接入Apple Vision Pro

在前不久举行的GTC开发者大会上&#xff0c;英伟达引领行业风向&#xff0c;宣布其Omniverse平台能够助力企业将3D/XR应用流畅传输至Apple Vision Pro混合现实头显。在英伟达与苹果这两大科技巨头的合作下,此举标志着3D/XR技术迈向新纪元的关键一步。「Paraverse平行云」实时云…

基于STM32单片机的汽车胎压、速度及状态监测系统设计与实现

基于STM32单片机的汽车胎压、速度及状态监测系统设计与实现 摘要&#xff1a; 随着汽车电子技术的快速发展&#xff0c;车辆状态实时监控系统的需求日益增长。本文设计并实现了一种基于STM32单片机的汽车胎压、速度及状态监测系统。该系统能够实时监测汽车的胎压、速度以及其他…

算法设计与分析4.1 迷宫问题 栈与队列解法、打印矩阵、三壶问题、蛮力匹配

1.ROSE矩阵 实现&#xff1a; 使用算法2 分析&#xff1a; 每半圈元素值的增长规律变换一次 设增量为t&#xff0c;每半圈变换一次t <— -t . 设矩阵边长为i&#xff0c;每半圈的元素个数是2*(i-1)个&#xff0c;hc为记数变量&#xff0c;则1≤hc<2i-1&#xff0c;前1/…

ChatGLM2-6B的部署步骤_A3

ChatGLM2-6B 下载地址 一、VisualGLM-6B环境安装 1、硬件配置 操作系统&#xff1a;Ubuntu_64&#xff08;ubuntu22.04.3&#xff09; GPU&#xff1a;4050 显存&#xff1a;16G 2、配置环境 建议最好自己新建一个conda环境 conda create -n chatglm2 python3.8pip …

【go项目01_学习记录day01】

博客系统 1 vscode开发go项目插件推荐1.1 CtrlShiftP&#xff08;俗称万能键&#xff09; &#xff1a;打开命令面板。在打开的输入框内&#xff0c;可以输入任何命令。1.2 开发时&#xff0c;我们需要经常查阅 Go 语言官方文档&#xff0c;可惜因国内访问外网不稳定&#xff0…

STM32开启停止模式,用外部中断唤醒程序运行

今天学习了一下STM32的停止模式&#xff0c;停止模式下&#xff0c;所有外设的时钟和CPU的电源都会被关闭&#xff0c;所以会很省电&#xff0c;打破这种停止模式的方式就是外部中断可以唤醒停止模式。要想实现这个功能&#xff0c;其实设置很简单的&#xff0c;总共就需要两步…
最新文章