首页 > 其他分享 >2.1.3-2 第二次Reactor代码(百万并发测试过程的报错信息)

2.1.3-2 第二次Reactor代码(百万并发测试过程的报错信息)

时间:2024-12-15 14:03:15浏览次数:6  
标签:Reactor int list fd 报错 2.1 event conn struct

零、概述

做服务器性能测试的时候,并发量QPS(每秒处理多少请求)时迟(延迟,每个请求多长时间返回)、测试用例(业务代码,发什么数据和回什么数据)这四组都是重要的参数。

并发 → 网络io的并发,是服务端最基础的技能。备注:研发和运营的数据不相同。

一、报错信息

server ip: 192.168.80.129

client  ip: 192.168.80.130

线程: 1

端口: 2000

(1)客户端出现Too many open files“”,而服务端出现“core dumped”

答:通过在“客户端”输入“ulimit -a”看到“open files (-n) 1024”。

对于客户端: 输入ulimit -n 1048576。也可直接修改文件“vim /etc/security/limits.conf”  

对于服务端,原因是脚本里没有在相应位置做返回值判断,在以下2个地方加判断:

(2)客户端出现报错信息“Cannot assign requested address”,服务端出现“Segmentation fault (core dumped)”

答:第1部分

出现不能分配address,这个说明“5元组”不够。每个TCP连接由“5元”组成,包括

源ip (sip)                 目的ip (dip)            源端口 (sport)           目的端口 (dport)             协议 (protocol)

local ip                    remote ip                 local port                 remote port                    TCP

192.168.80.130     192.168.80.129       1024-65535            1个(2000)

所以要在server端建立多个端口,从react.c文件里加sockfd的循环。

第2部分

输入命令“cat /proc/sys/net/ipv4/ip_local_port_range” 得到动态端口是从32768到60999共28232个。可通过root权限下的“sudo sysctl -w net.ipv4.ip_local_port_range="4000 65535"”命令临时修改动态端口数量。

(3)客户端fd不再增加

(4)在25万个并发请求后,客户端出现打开文件的上限,原因是什么?

答:这是系统级别的能够打开的文件的数量受限,这是对整个系统的限制。通过命令“sysctl -a | grep 'fs.file-max'”看到结果是“fs.file-max = 259827”的限制。有2种修改限制的方式,

方式1,临时生效,重启恢复默认

“echo 6553560 > /proc/sys/fs/file-max”或“sysctl -w "fs.file-max=655356"”

方式2,永久生效

“ulimit -HSn 6553560” 或
$ vim /etc/security/limits.conf  
* soft nofile 65535 
* hard nofile 65535

// 如果需要设置当前用户 session 立即生效,可以执行:
$ ulimit -n 65535

(5)客户端直接kill掉,原因是什么?

答:大概率是内存不足,客户端加内存。

(6)如何不让server端kill掉?

答:做一个信号注册函数,每次遇到信息做处理。

(7)出问题后,server端的CPU暴增原因?

答:此时客户端会有CPU里有大量的连接接收final信息,服务端会启用大量定时器,CPU在处理数据过程中出现雪崩的情况。

        我们只能把CPU暴增的时间减短,但无法完全消除。

sigaction
handler(int sig){
    printf("", 9, 11);
}

二、最终代码

#include <stdio.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>  
#include <arpa/inet.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <poll.h>
#include <sys/epoll.h>
#include <sys/time.h>


#define BUFFER_LENGTH  1024
#define CONNECTION_SIZE   1048576  // 1024

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


typedef int (*RCALLBACK)(int fd);


int accept_cb(int fd);
int recv_cb(int fd);
int send_cb(int fd);

int epfd = 0;

struct timeval begin;

struct conn{
	int fd;

	char rbuffer[BUFFER_LENGTH];
	int rlength;

	char wbuffer[BUFFER_LENGTH];
	int wlength;

	RCALLBACK send_callback;

	union{
		RCALLBACK recv_callback;	
		RCALLBACK accept_callback;
	} r_action;

};

struct conn conn_list[CONNECTION_SIZE] = {0};


int set_event(int fd, int event, int flag){ // fd的epoll注册

	if (flag){   // non-zero, than add
		struct epoll_event ev;
		ev.events = event;	//只监听是否可读这种时间,EPOLLOUT等不被检测
		ev.data.fd = fd; 
		epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

	}else {   // zero, then modify
		struct epoll_event ev;
		ev.events = event;	//只监听是否可读这种时间,EPOLLOUT等不被检测
		ev.data.fd = fd; 
		epoll_ctl(epfd, EPOLL_CTL_MOD, fd, &ev);

	}
}


int event_register(int fd, int event){

	if (fd < 0) return -1;

/// 把clientfd注册进回调函数 /
	conn_list[fd].fd = fd;                                                  //
	conn_list[fd].r_action.recv_callback = recv_cb;                               //
	conn_list[fd].send_callback = send_cb;                                        //
                                                                                        //
	memset(conn_list[fd].rbuffer, 0, BUFFER_LENGTH); //为了后面正常,这边要清空     //
	conn_list[fd].rlength = 0;                                                    //
                                                                                        //
	memset(conn_list[fd].wbuffer, 0, BUFFER_LENGTH); //为了后面正常,这边要清空     //
	conn_list[fd].wlength = 0;                                     

	set_event(fd, event, 1);
//
}


// accpept()函数
int accept_cb(int fd){

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

    int clientfd = accept(fd, (struct sockaddr*)&clientddr, &len); 
	//printf("accept finished: %d\n", clientfd);

	if(clientfd < 0){ 
		printf("accept errno: %d ---> %s\n", errno, strerror(errno));
		return -1;
	}

	event_register(clientfd, EPOLLIN);     


//每10000条打印一次信息
	if ((clientfd % 1000) == 0){

#if 0
		struct timeval current;
		gettimeofday(&current, NULL);   //gettimeofday
		int time_used = TIME_SUB_MS(current, begin);
		memcpy(&begin, &current, sizeof(struct timeval));
		
		printf("accept finished: %d, time_used is %d\n", clientfd, time_used);
#endif
		printf("accept finished: %d\n", clientfd);


	}



	return 0;
}

int recv_cb(int fd){
    	
    int count = recv(fd, conn_list[fd].rbuffer, BUFFER_LENGTH, 0); 
    if (count == 0){  // disconnect
    	printf("client disconnect, clientfd is: %d\n", fd); //
    	close(fd); //通知操作系统释放资源
		epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL); //unfinished
					
    	return 0;
    }
	conn_list[fd].rlength = count;
	
	//printf("RECV: %s\n", conn_list[fd].rbuffer);

#if 1 //echo  

	conn_list[fd].wlength = conn_list[fd].rlength;
	memcpy(conn_list[fd].wbuffer, conn_list[fd].rbuffer, conn_list[fd].wlength);
    //void *memcpy(void *dest, const void *src, size_t n)

#endif

	set_event(fd, EPOLLOUT, 0);	
	return count;
}


int send_cb(int fd){
	
	int count = send(fd, conn_list[fd].wbuffer, conn_list[fd].wlength, 0);

	set_event(fd, EPOLLIN, 0);		
	return count;
}



int init_server(unsigned short port){

	int sockfd = socket(AF_INET, SOCK_STREAM, 0);

	struct sockaddr_in servaddr;
	servaddr.sin_family = AF_INET;
	servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
	servaddr.sin_port = htons(port);

	if (-1 == bind(sockfd, (struct sockaddr*)&servaddr, sizeof(struct sockaddr))){
		printf("bind failed: %s\n", strerror(errno));
	}
	listen(sockfd, 10);
	//printf("Listen finished: %d\n", sockfd);

	return sockfd;

}




int main(){


/  01_初始化socket到listen
	unsigned short port = 2000;            ///

/  02_把sockfd注册到epoll
	epfd = epoll_create(1);                ///

	int i = 0;
	for (i = 0; i < MAX_PORTS; i ++){
		int sockfd = init_server(port + i); 	   
		conn_list[sockfd].fd = sockfd;
		conn_list[sockfd].r_action.recv_callback = accept_cb;
		set_event(sockfd, EPOLLIN, 1);    
		}
//

//	gettimeofday(&begin, NULL);

	while(1){

		struct epoll_event events[1024] = {0}; //定义口袋大小
		int nready = epoll_wait(epfd, events, 1024,-1); //返回值是

		int i = 0;
		for (i = 0; i < nready;i ++){
			int connfd = events[i].data.fd;

			if (events[i].events & EPOLLIN){
				conn_list[connfd].r_action.recv_callback(connfd);
			}
			if (events[i].events & EPOLLOUT){
				conn_list[connfd].send_callback(connfd);
			}

		}

	}

	return 0;
}

标签:Reactor,int,list,fd,报错,2.1,event,conn,struct
From: https://blog.csdn.net/qsq_Ai/article/details/144459932

相关文章

  • PbootCMS模板报错提示“PHP Warning: Unknown: open_basedir restriction in effect.
    在使用PbootCMS时,遇到“PHPWarning:Unknown:open_basedirrestrictionineffect.File”错误通常是由于PHP的open_basedir配置限制了脚本可以访问的目录范围。以下是解决这个问题的详细步骤和注意事项:了解open_basedir配置:open_basedir是一个PHP配置选项,用于限制脚本只能......
  • PbootCMS网站迁移后无法打开,报错“No input file specified”,如何解决?
    当PbootCMS网站迁移后遇到“Noinputfilespecified”的错误提示时,通常是由于服务器配置或文件权限的问题导致的。以下是详细的解决步骤和注意事项:检查.user.ini文件:进入网站的根目录,查找是否存在.user.ini文件。如果存在.user.ini文件,尝试删除它。这个文件有时会干扰服务......
  • Z-BlogPHP 报错“error-7 用户名格式不正确,可能过长或为空”,如何解决?
    当您在使用Z-BlogPHP时遇到“error-7用户名格式不正确,可能过长或为空”的错误,通常是因为您输入的用户名不符合Z-BlogPHP的格式要求。Z-BlogPHP要求用户名长度不超过20位字符,并且不能为空。以下是一些解决此问题的方法:检查用户名长度:确认您输入的用户名长度是否超过了......
  • Z-BlogPHP 报错“启用该应用,需要先停用冲突应用”,如何解决?
    当您在使用Z-BlogPHP时遇到“启用该应用,需要先停用冲突应用”的错误,通常是因为您试图启用的应用与已经安装的某个应用存在冲突,导致无法同时启用。以下是一些解决此问题的方法:识别冲突应用:首先,确定您试图启用的应用与哪个已安装的应用存在冲突。通常,应用的文档或安装说明中......
  • 2024.12.14 周六
    2024.12.14周六Q1.1000Youaregiventwostrings$a$and$b$ofequallength,consistingofonlycharacters0and/or1;bothstringsstartwithcharacter0andendwithcharacter1.Youcanperformthefollowingoperationanynumberoftimes(possiblyze......
  • Git之git push报错protocol error: bad line length 8192怎么处理
    故障现象gitpull报错$gitpushCountingobjects:40,done.Deltacompressionusingupto32threads.Compressingobjects:100%(38/38),done.fatal:protocolerror:badlinelength819247.18MiB/sfatal:sha1file'<stdout>'writeerror:Bro......
  • 12.13
    在对银行账户等重要权限设置密码的时候,我们常常遇到这样的烦恼:如果为了好记用生日吧,容易被破解,不安全;如果设置不好记的密码,又担心自己也会忘记;如果写在纸上,担心纸张被别人发现或弄丢了...   这个程序的任务就是把一串拼音字母转换为6位数字(密码)。我们可以使用任何好记的拼......
  • 关于在虚拟环境中装tensorflow框架跑模型安装了一些库报错问题
    一、问题描述:我用conda安装创建了虚拟环境,然后在环境里安装了numpy、pandas、scikit-learn和tensorflow,但在运行程序是报错如下:ModuleNotFoundErrorTraceback(mostrecentcalllast)CellIn[3],line75fromtensorflow.keras.modelsimportSequential6fromten......
  • win10 docker wsl 报错:管理员用策略规则 %2 限制了对 %1 的访问
    Window10使用Docker的时候,需要使用wsl,在本地启用了Hyper-V后,执行wsl报错:程序“wsl.exe”无法运行:管理员用策略规则%2限制了对%1的访问。所在位置行:1字符:1+wsl--status+~~~~~~~~~~~~。所在位置行:1字符:1+wsl--status+~~~~~~~~~~~~+Ca......
  • 达梦DM.Microsoft.EntityFreameworkCore查询报错invalid cast from DateTime to DateT
    1.问题达梦dotnetefcore的驱动DM.Microsoft.EntityFreameworkCore。如果实体中存在DateTimeOffset类型字段时,查询报错:invalidcastfromDateTimetoDateTimeOffset。Invalidcastfrom'System.DateTime'to'System.DateTimeOffset'System.Convert.DefaultToType(Sy......