服务器百万并发的原理与实现

news2024/9/23 19:22:18

什么是百万并发?

指的是服务器接收百万个连接或数据会在同一时刻接收到,也就是同时能看到

百万个连接或数据。

在了解服务器百万并发的同时,我们先来看看我们的百万并发服务器的结构图。

主体是以reactor为核心,链表方式存储事件以及事件对应的属性

服务端




#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>

#include <sys/types.h>
#include <sys/stat.h>


#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/time.h>               

#include <sys/sendfile.h>



#define BUFFER_LENGTH		1024
#define MAX_EPOLL_EVENTS	1024
#define RESOURCE_LENGTH	1024

#define SERVER_PORT			8888
#define PORT_COUNT			1

typedef int NCALLBACK(int ,int, void*);


#define HTTP_METHOD_GET		0
#define HTTP_METHOD_POST	1

struct ntyevent {
	int fd;
	int events;
	void *arg;
	int (*callback)(int fd, int events, void *arg);
	
	int status;
	char buffer[BUFFER_LENGTH];
	
	char wbuffer[BUFFER_LENGTH];
	
	int length;
	int wlength;
	//long last_active;

	// http reqeust
	int method;
	char resource[RESOURCE_LENGTH];

};

struct eventblock {
	
	struct eventblock *next;
	struct ntyevent *events;
};

struct ntyreactor {
	int epfd;
	int blkcnt;
	struct eventblock *evblks;
};


int recv_cb(int fd, int events, void *arg);
int send_cb(int fd, int events, void *arg);
struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd);



void nty_event_set(struct ntyevent *ev, int fd, NCALLBACK callback, void *arg) {

	ev->fd = fd;
	ev->callback = callback;
	ev->events = 0;
	ev->arg = arg;
	//ev->last_active = time(NULL);

	return ;
	
}


int nty_event_add(int epfd, int events, struct ntyevent *ev) {

	struct epoll_event ep_ev = {0, {0}};
	ep_ev.data.ptr = ev;
	ep_ev.events = ev->events = events;
	
	int op;
	if (ev->status == 1) {
		op = EPOLL_CTL_MOD;
	} else {
		op = EPOLL_CTL_ADD;
		ev->status = 1;
	}
	if (epoll_ctl(epfd, op, ev->fd, &ep_ev) < 0) {
		printf("event add failed [fd=%d], events[%d]\n", ev->fd, events);
		return -1;
	}
	
	return 0;
}

int nty_event_del(int epfd, struct ntyevent *ev) 
{
	struct epoll_event ep_ev = {0, {0}};
	
	if (ev->status != 1) {
		return -1;
	}
	
	ep_ev.data.ptr = ev;
	ev->status = 0;
	epoll_ctl(epfd, EPOLL_CTL_DEL, ev->fd, &ep_ev);
	return 0;
}

// request
// location  /0voice/king/index.html HTTP/1.1
// 

int readline(char* allbuf,int idx,char* linebuf) {    
	int len = strlen(allbuf);    

	for (;idx < len; ++idx)    {        
		if(allbuf[idx]=='\r' && allbuf[idx+1]=='\n')            
			return idx+2;        
		else            
			*(linebuf++) = allbuf[idx];    
	}    

	return -1;
}


int nty_http_request(struct ntyevent *ev) {

	char linebuffer[1024] = {0};
	
	int idx = readline(ev->buffer, 0, linebuffer);
	if (strstr(linebuffer, "GET")) {
		ev->method = HTTP_METHOD_GET; //

		int i = 0;
		while(linebuffer[sizeof("GET ") + i] != ' ') i ++;
		linebuffer[sizeof("GET ") + i] = '\0';

		sprintf(ev->resource, "%s/%s", HTTP_WEB_ROOT, linebuffer+sizeof("GET "));

		//printf("resource: %s\n", ev->resource);		 //
		
	} else if (strstr(linebuffer, "POST")) {
		ev->method = HTTP_METHOD_POST;
	}
	

}

int nty_http_response_get_method(struct ntyevent *ev) {

	//int filed = open()
#if 0
	int len = sprintf(ev->wbuffer, 
	"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: 78\r\n"
"Content-Type: text/html\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n"
"<html><head><title>0voice.king</title></head><body><h1>King</h1><body/></html>");

	ev->wlength = len;
#else
	int len;
	int filefd = open(ev->resource, O_RDONLY);
	if (filefd == -1) {

		len = sprintf(ev->wbuffer, 
	"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: 78\r\n"
"Content-Type: text/html\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n"
"<html><head><title>0voice.king</title></head><body><h1>King</h1><body/></html>");

		ev->wlength = len;
	
	} else {

		struct stat stat_buf;
		fstat(filefd, &stat_buf);
		close(filefd);
#if 1
		len = sprintf(ev->wbuffer, 
	"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: %ld\r\n"
"Content-Type: text/html\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n", stat_buf.st_size);
#else
len = sprintf(ev->wbuffer, 
	"HTTP/1.1 200 OK\r\n"
"Accept-Ranges: bytes\r\n"
"Content-Length: %ld\r\n"
"Content-Type: image/png\r\n"
"Date: Sat, 06 Aug 2022 13:16:46 GMT\r\n\r\n", stat_buf.st_size);


#endif
		ev->wlength = len;

	}

#endif
	return len;
}


int nty_http_response(struct ntyevent *ev) {

	// ev->method, ev->resouces

	if (ev->method == HTTP_METHOD_GET) {
		return nty_http_response_get_method(ev);
	} else if (ev->method == HTTP_METHOD_POST) {

	}
	

}


// connection
// sock_item --> fd, rbuffer, wbuffer, clientaddr
int recv_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	struct ntyevent *ev = ntyreactor_idx(reactor, fd);

	if (ev == NULL) return -1;
	//
	int len = recv(fd, ev->buffer, BUFFER_LENGTH, 0);
	nty_event_del(reactor->epfd, ev);

	if (len > 0) {
		
		ev->length = len;
		ev->buffer[len] = '\0';

		//printf("recv [%d]:%s\n", fd, ev->buffer);

		nty_http_request(ev); // parser http hdr

		nty_event_set(ev, fd, send_cb, reactor);
		nty_event_add(reactor->epfd, EPOLLOUT, ev);
		
		
	} else if (len == 0) {

		nty_event_del(reactor->epfd, ev);
		//printf("recv_cb --> disconnect\n");
		close(ev->fd);
		 
	} else {

		if (errno == EAGAIN && errno == EWOULDBLOCK) { //
			
		} else if (errno == ECONNRESET){
			nty_event_del(reactor->epfd, ev);
			close(ev->fd);
		}
		//printf("recv[fd=%d] error[%d]:%s\n", fd, errno, strerror(errno));
		
	}

	return len;
}


int send_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	struct ntyevent *ev = ntyreactor_idx(reactor, fd);

	if (ev == NULL) return -1;

	nty_http_response(ev); //encode

	int len = send(fd, ev->wbuffer, ev->wlength, 0);
	if (len > 0) {
		//printf("resource: %s\n", ev->resource);

		int filefd = open(ev->resource, O_RDONLY);
		//if (filefd < 0) return -1;
		
		struct stat stat_buf;
		fstat(filefd, &stat_buf);
		
		int flag = fcntl(fd, F_GETFL, 0);
		flag &= ~O_NONBLOCK;
		fcntl(fd, F_SETFL, flag);
			
		int ret = sendfile(fd, filefd, NULL, stat_buf.st_size);
		if (ret == -1) {
			printf("sendfile: errno: %d\n", errno);
		}

		flag |= O_NONBLOCK;
		fcntl(fd, F_SETFL, flag);

		close(filefd);

		send(fd, "\r\n", 2, 0);

		nty_event_del(reactor->epfd, ev);
		nty_event_set(ev, fd, recv_cb, reactor);
		nty_event_add(reactor->epfd, EPOLLIN, ev);
		
	} else {

		nty_event_del(reactor->epfd, ev);
		close(ev->fd);

		//printf("send[fd=%d] error %s\n", fd, strerror(errno));

	}

	return len;
}

int curfds = 0;

#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)

struct timeval tv_begin;

int accept_cb(int fd, int events, void *arg) {

	struct ntyreactor *reactor = (struct ntyreactor*)arg;
	if (reactor == NULL) return -1;

	struct sockaddr_in client_addr;
	socklen_t len = sizeof(client_addr);

	int clientfd;

	if ((clientfd = accept(fd, (struct sockaddr*)&client_addr, &len)) == -1) {
		if (errno != EAGAIN && errno != EINTR) {
			
		}
		printf("accept: %s\n", strerror(errno));
		return -1;
	}

	
	int flag = 0;
	if ((flag = fcntl(clientfd, F_SETFL, O_NONBLOCK)) < 0) {
		printf("%s: fcntl nonblocking failed, %d\n", __func__, MAX_EPOLL_EVENTS);
		return -1;
	}

	struct ntyevent *event = ntyreactor_idx(reactor, clientfd);

	if (event == NULL) return -1;
		
	nty_event_set(event, clientfd, recv_cb, reactor);
	nty_event_add(reactor->epfd, EPOLLIN, event);

	if (curfds++ % 1000 == 999) {
		struct timeval tv_cur;
		memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
		
		gettimeofday(&tv_begin, NULL);

		int time_used = TIME_SUB_MS(tv_begin, tv_cur);
		printf("connections: %d, sockfd:%d, time_used:%d\n", curfds, clientfd, time_used);
	}

	//printf("new connect [%s:%d], pos[%d]\n", 
	//	inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), clientfd);

	return 0;

}

int init_sock(short port) {

	int fd = socket(AF_INET, SOCK_STREAM, 0);
	fcntl(fd, F_SETFL, O_NONBLOCK);

	struct sockaddr_in server_addr;
	memset(&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(port);

	        if (bind(fd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
	            perror("bind");
	            return 2;
	        }

	if (listen(fd, 20) < 0) {
		printf("listen failed : %s\n", strerror(errno));
		return -1;
	}

	printf("listen server port : %d\n", port);
	gettimeofday(&tv_begin, NULL);

	return fd;
}


int ntyreactor_alloc(struct ntyreactor *reactor) {

	if (reactor == NULL) return -1;
	if (reactor->evblks == NULL) return -1;
	
	struct eventblock *blk = reactor->evblks;

	while (blk->next != NULL) {
		blk = blk->next;
	}

	struct ntyevent* evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
	if (evs == NULL) {
		printf("ntyreactor_alloc ntyevent failed\n");
		return -2;
	}
	memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));

	struct eventblock *block = malloc(sizeof(struct eventblock));
	if (block == NULL) {
		printf("ntyreactor_alloc eventblock failed\n");
		return -3;
	}
	block->events = evs;
	block->next = NULL;

	blk->next = block;
	reactor->blkcnt ++;

	return 0;
}

struct ntyevent *ntyreactor_idx(struct ntyreactor *reactor, int sockfd) {

	if (reactor == NULL) return NULL;
	if (reactor->evblks == NULL) return NULL;

	int blkidx = sockfd / MAX_EPOLL_EVENTS;
	while (blkidx >= reactor->blkcnt) {
		ntyreactor_alloc(reactor);
	}

	int i = 0;
	struct eventblock *blk = reactor->evblks;
	while (i++ != blkidx && blk != NULL) {
		blk = blk->next;
	}

	return &blk->events[sockfd % MAX_EPOLL_EVENTS];
}


int ntyreactor_init(struct ntyreactor *reactor) {

	if (reactor == NULL) return -1;
	memset(reactor, 0, sizeof(struct ntyreactor));

	reactor->epfd = epoll_create(1);
	if (reactor->epfd <= 0) {
		printf("create epfd in %s err %s\n", __func__, strerror(errno));
		return -2;
	}

	struct ntyevent* evs = (struct ntyevent*)malloc((MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));
	if (evs == NULL) {
		printf("create epfd in %s err %s\n", __func__, strerror(errno));
		close(reactor->epfd);
		return -3;
	}
	memset(evs, 0, (MAX_EPOLL_EVENTS) * sizeof(struct ntyevent));

	struct eventblock *block = malloc(sizeof(struct eventblock));
	if (block == NULL) {
		free(evs);
		close(reactor->epfd);
		return -3;
	}
	block->events = evs;
	block->next = NULL;

	reactor->evblks = block;
	reactor->blkcnt = 1;

	return 0;
}

int ntyreactor_destory(struct ntyreactor *reactor) {

	close(reactor->epfd);

	struct eventblock *blk = reactor->evblks;
	struct eventblock *blk_next;
	while (blk != NULL) {
		blk_next = blk->next;

		free(blk->events);
		free(blk);
		
		blk = blk_next;
	}

	return 0;
}



int ntyreactor_addlistener(struct ntyreactor *reactor, int sockfd, NCALLBACK *acceptor) {

	if (reactor == NULL) return -1;
	if (reactor->evblks == NULL) return -1;

	struct ntyevent *event = ntyreactor_idx(reactor, sockfd);
	if (event == NULL) return -1;

	nty_event_set(event, sockfd, acceptor, reactor);
	nty_event_add(reactor->epfd, EPOLLIN, event);

	return 0;
}



int ntyreactor_run(struct ntyreactor *reactor) {
	if (reactor == NULL) return -1;
	if (reactor->epfd < 0) return -1;
	if (reactor->evblks == NULL) return -1;
	
	struct epoll_event events[MAX_EPOLL_EVENTS+1];
	
	int checkpos = 0, i;

	while (1) {

		int nready = epoll_wait(reactor->epfd, events, MAX_EPOLL_EVENTS, 1000);
		if (nready < 0) {
			printf("epoll_wait error, exit\n");
			continue;
		}

		for (i = 0;i < nready;i ++) {

			struct ntyevent *ev = (struct ntyevent*)events[i].data.ptr;

			if ((events[i].events & EPOLLIN) && (ev->events & EPOLLIN)) {
				ev->callback(ev->fd, events[i].events, ev->arg);
			}
			if ((events[i].events & EPOLLOUT) && (ev->events & EPOLLOUT)) {
				ev->callback(ev->fd, events[i].events, ev->arg);
			}
			
		}

	}
}

int main(int argc, char *argv[]) {

	
	struct ntyreactor *reactor = (struct ntyreactor*)malloc(sizeof(struct ntyreactor));
	ntyreactor_init(reactor);

	unsigned short port = SERVER_PORT;
	if (argc == 2) {
		port = atoi(argv[1]);
	}

	int i = 0;
	int sockfds[PORT_COUNT] = {0};
	
	for (i = 0;i < PORT_COUNT;i ++) {
		sockfds[i] = init_sock(port+i);
		ntyreactor_addlistener(reactor, sockfds[i], accept_cb);
	}


	ntyreactor_run(reactor);

	ntyreactor_destory(reactor);
	
	for (i = 0;i < PORT_COUNT;i ++) {
		close(sockfds[i]);
	}
	free(reactor);
	

	return 0;
}

客户端(向服务器一直发请求)



#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <errno.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <fcntl.h>


#define MAX_BUFFER		128
#define MAX_EPOLLSIZE	(384*1024)
#define MAX_PORT		100

#define TIME_SUB_MS(tv1, tv2)  ((tv1.tv_sec - tv2.tv_sec) * 1000 + (tv1.tv_usec - tv2.tv_usec) / 1000)

int isContinue = 0;

static int ntySetNonblock(int fd) {
	int flags;

	flags = fcntl(fd, F_GETFL, 0);
	if (flags < 0) return flags;
	flags |= O_NONBLOCK;
	if (fcntl(fd, F_SETFL, flags) < 0) return -1;
	return 0;
}

static int ntySetReUseAddr(int fd) {
	int reuse = 1;
	return setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse));
}



int main(int argc, char **argv) {
	if (argc <= 2) {
		printf("Usage: %s ip port\n", argv[0]);
		exit(0);
	}

	const char *ip = argv[1];
	int port = atoi(argv[2]);
	int connections = 0;
	char buffer[128] = {0};
	int i = 0, index = 0;

	struct epoll_event events[MAX_EPOLLSIZE];
	
	int epoll_fd = epoll_create(MAX_EPOLLSIZE);
	
	strcpy(buffer, " Data From MulClient\n");
		
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(struct sockaddr_in));
	
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(ip);

	struct timeval tv_begin;
	gettimeofday(&tv_begin, NULL);

	while (1) {
		if (++index >= MAX_PORT) index = 0;
		
		struct epoll_event ev;
		int sockfd = 0;

		if (connections < 340000 && !isContinue) {
			sockfd = socket(AF_INET, SOCK_STREAM, 0);
			if (sockfd == -1) {
				perror("socket");
				goto err;
			}

			//ntySetReUseAddr(sockfd);
			addr.sin_port = htons(port+index);

			if (connect(sockfd, (struct sockaddr*)&addr, sizeof(struct sockaddr_in)) < 0) {
				perror("connect");
				goto err;
			}
			ntySetNonblock(sockfd);
			ntySetReUseAddr(sockfd);

			sprintf(buffer, "Hello Server: client --> %d\n", connections);
			send(sockfd, buffer, strlen(buffer), 0);

			ev.data.fd = sockfd;
			ev.events = EPOLLIN | EPOLLOUT;
			epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sockfd, &ev);
		
			connections ++;
		}
		//connections ++;
		if (connections % 1000 == 999 || connections >= 340000) {
			struct timeval tv_cur;
			memcpy(&tv_cur, &tv_begin, sizeof(struct timeval));
			
			gettimeofday(&tv_begin, NULL);

			int time_used = TIME_SUB_MS(tv_begin, tv_cur);
			printf("connections: %d, sockfd:%d, time_used:%d\n", connections, sockfd, time_used);

			int nfds = epoll_wait(epoll_fd, events, connections, 100);
			for (i = 0;i < nfds;i ++) {
				int clientfd = events[i].data.fd;

				if (events[i].events & EPOLLOUT) {
					sprintf(buffer, "data from %d\n", clientfd);
					send(sockfd, buffer, strlen(buffer), 0);
				} else if (events[i].events & EPOLLIN) {
					char rBuffer[MAX_BUFFER] = {0};				
					ssize_t length = recv(sockfd, rBuffer, MAX_BUFFER, 0);
					if (length > 0) {
						printf(" RecvBuffer:%s\n", rBuffer);

						if (!strcmp(rBuffer, "quit")) {
							isContinue = 0;
						}
						
					} else if (length == 0) {
						printf(" Disconnect clientfd:%d\n", clientfd);
						connections --;
						close(clientfd);
					} else {
						if (errno == EINTR) continue;

						printf(" Error clientfd:%d, errno:%d\n", clientfd, errno);
						close(clientfd);
					}
				} else {
					printf(" clientfd:%d, errno:%d\n", clientfd, errno);
					close(clientfd);
				}
			}
		}

		usleep(500);
	}

	return 0;

err:
	printf("error : %s\n", strerror(errno));
	return 0;
	
}

实现效果跟服务器的性能和台数也有关系,我只有一台服务器并且内存很小只有1G,所以到不了百万并发,多几台服务器就可以实现百万并发了

还有一个细节就是在测试百万并发的时候,尽量减少IO操作提升百万并发效率

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

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

相关文章

「北大社送书」学习MATLAB—从算法到实战

MATLAB科学计算从入门到精通 一句话推荐书籍特色内容简介书籍概览 从代码到函数&#xff0c;从算法到实战&#xff0c;从问题到应用&#xff0c;由浅入深掌握科学计算方法&#xff0c;高效解决实际问题。 一句话推荐 科学计算基础入门&#xff0c;高效解决实际问题。 书籍特色…

vue3中的provide 与 inject

一、概述 作用&#xff1a;实现祖先与后代组件的通信。一般为祖孙通信&#xff0c;因为子组件可以用props来通信。 语法&#xff1a;父组件中&#xff1a;provide(car, car) 子组件中&#xff1a;let car inject(car) 二、举例说明&#xff08;代码如下&#xff09; &…

逐鹿千亿市场:一碗中国面的魅力

【潮汐商业评论/原创】 根据世界方便面协会&#xff08;WINA&#xff09;发布的数据&#xff0c;2022年全球方便面总需求量同比增长4.0%至1212亿份&#xff0c;再创历史新高。从小门头商铺到大型商超&#xff0c;从线下到线上&#xff0c;方便面早就走进了千家万户&#xff0c…

C++ 左值、右值、左值引用以及右值引用

一、左值和右值 将亡值 1.左值 左值是一个表示数据的表达式&#xff0c;比如&#xff1a;变量名、解引用的指针变量。一般地&#xff0c;我们可以获取它的地址和对它赋值&#xff0c;但被 const 修饰后的左值&#xff08;常性&#xff09;&#xff0c;不能给它赋值&#xff0…

系统架构设计师之软件概要设计

系统架构设计师之软件概要设计

设计模式(15)组合模式

一、介绍&#xff1a; 1、定义&#xff1a;组合多个对象形成树形结构以表示“整体-部分”的关系的层次结构。组合模式对叶子节点和容器节点的处理具有一致性&#xff0c;又称为整体-部分模式。 2、优缺点&#xff1a; 优点&#xff1a; &#xff08;1&#xff09;高层模块调…

国外问卷调查赚钱靠谱吗?

大家好&#xff0c;我是橙河网络&#xff0c;这几年的国外问卷调查项目可真是火得一塌糊涂&#xff0c;不少人靠这个项目赚得是盆满钵满&#xff0c;让人直流口水。今天&#xff0c;我就来给大家详细扒一扒这个国外问卷调查赚钱靠谱吗&#xff1f; 首先&#xff0c;我得跟大家…

家长扫码查成绩

亲爱的老师&#xff0c;你是否曾为了如何让家长更方便地查询学生的成绩而烦恼&#xff1f;现在&#xff0c;我们为你介绍一款简单易用的成绩查询系统&#xff0c;让家长只需轻轻一扫&#xff0c;即可查看孩子的成绩。 一、什么是成绩查询系统&#xff1f; 成绩查询系统是一款专…

TTS | 一文总览语音合成系列基础知识及简要介绍

Text-to-Speech&#xff08;通常缩写为TTS&#xff09;是指一种将文本读成音频的技术。换句话说&#xff0c;它指的是一种模型&#xff0c;在该模型中&#xff0c;当文本或类似于字符的东西作为输入时&#xff0c;会生成波形音频作为输出。 但实际上&#xff0c;这个 TTS 的音…

iOS调试技巧——使用Python 自定义LLDB

一、类介绍 在使用Python 自定义LLDB之前,先了解一下LLDB的一些类型 SBTarget 正在被调试的程序SBProcess 和程序关联的具体的进程SBThread 执行的线程SBFrame 和线程关联的一个栈帧SBVariable 变量,寄存器或是一个表达式一般情况下,我们取到SBFrame就可以进行方法调用来打…

Spring Boot整合swagger2

在上一篇中我们围绕了Spring Boot 集成了RESTful API项目&#xff0c;但是我们在实际开发中&#xff0c;我们的一个RESTful API有可能就要服务多个不同的开发人员或者开发团队&#xff0c;包括不限于PC,安卓&#xff0c;IOS&#xff0c;甚至现在的鸿蒙OS&#xff0c;web开发等等…

buuctf_练[网鼎杯 2018]Fakebook

[网鼎杯 2018]Fakebook 文章目录 [网鼎杯 2018]Fakebook掌握知识解题思路关键paylaod 掌握知识 ​ SQL注入的联合注入&#xff1b;闭合类型的探查&#xff0c;本次是数字型闭合&#xff1b;SQL注入的读取文件的利用 解题思路 打开题目链接&#xff0c;发现主界面给了一些信息…

大数据-Storm流式框架(一)

一、storm介绍 Storm是个实时的、分布式以及具备高容错的计算系统 Storm进程常驻内存&#xff08;worker&#xff0c;supervisor&#xff0c;nimbus&#xff0c;ui&#xff0c;logviewer。。。&#xff09;Storm数据不经过磁盘&#xff0c;在内存中处理Twitter开源的分布式实时…

CSS基础框盒模型:打造炙手可热的网页布局!

&#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 ⭐ 专栏简介 &#x1f4d8; 文章引言 一、是…

老师们都在用的办公好物

现在还有老师不知道班级查询系统吗?各位老师们&#xff0c;向大家推荐一款超级实用的班级查询系统&#xff0c;帮你轻松管理学生信息&#xff0c;省去繁琐的手动操作&#xff0c;还能让学生们自主查询&#xff0c;简直是老师的福音&#xff01; 如果你在编程方面感到有些吃力&…

vscode推送gitee方法

有一套uni-app代码需要修改&#xff0c;版本控制使用vscode的git功能&#xff0c;远程库在gitee上。 1、设置vscode中git.exe路径 由于git使用了绿色便携版&#xff08;PortableGit-2.42.0.2-64-bit.7z.exe&#xff09;&#xff0c;vscode未识别到git安装路径&#xff0c;需要…

RTE2023大会来袭,声网宣布首创广播级4K超高清实时互动体验

10月24日&#xff0c;由声网和RTE开发者社区联合主办的RTE2023第九届实时互联网大会在北京举办&#xff0c;声网与众多RTE领域技术专家、产品精英、创业者、开发者一起&#xff0c;共同开启了以“智能高清”为主题的全新探讨。本届RTE大会将持续2天&#xff0c;开展1场主论坛及…

【路径规划】A*算法 Java实现

A*&#xff08;A-Star&#xff09;算法是一种广泛使用的寻路算法&#xff0c;尤其在计算机科学和人工智能领域。 算法思想 通过评估函数来引导搜索过程&#xff0c;从而找到从起始点到目标点的最短路径。评估函数通常包括两部分&#xff1a;一部分是已经走过的实际距离&#x…

「我在淘天做技术」双 11 背后的营销技术体系

作者&#xff1a;朱咏杰(小枫) 近期淘天集团秋季 2024 届校园招聘正式启动&#xff0c;预计将发放 2000 多个 offer&#xff0c;其中技术类岗位占比超过 50%。为了方便大家更真实地了解淘天技术的布局和现状&#xff0c;我们策划了「我在淘天做技术」系列&#xff0c;首次全面分…

科技资讯|苹果穿戴新专利,表带、服装等织物可变身柔性屏幕或扬声器

根据美国商标和专利局&#xff08;USPTO&#xff09;本周公示的清单&#xff0c;苹果公司获得了一项新的技术专利&#xff0c;可以在 Apple Watch 表带、服装等物品上&#xff0c;引入基于织物的柔性扬声器。 根据专利描述&#xff0c;通过在织物中嵌入声学组件&#xff08;例…