linux网络编程-高并发服务器

linux网络编程-高并发服务器

1.多进程\多线程版高并发服务器(使用与客服端数量不多的情况,不适用与大型开发,该方法需要自己监听\处理对系统资源消耗太大.应用比如智能家居系统.)
2.多路I\O转接服务器(多任务I\O服务器)
核心思想:不再由应用程序自己监听客服端的连接,由内核替代.主要的实现方法有三种:
1> select:1.监听的文件描述符存储于FD_SETSIZE(一般为1024),可以改变,需要编译内核,但是改大了之后,效率也会降低).(FD_SETSIZE-存储socket文件描述符,区别进程文件描述符)2.时间复杂度(O(n))3.
2> poll:突破了1024的限制(命令查看进程文件描述符:ulimit -a (查看open file),一般为1024,但是可以更改,但受硬件影响,一般也有一个上限值.)2.时间复杂度O(n).
3> epoll
注意:这三个对管道也适用,只有有文件描述符的都可以监听.

1.多进程\多线程版高并发服务器

优点:处理快;
缺点:一个进程或者线程对应一个客服端,客服端连接数量有限;内存压力大,资源利用效率低;

1>.多进程版

/***********************************************
Data:2020-12-2
Explanation:
使用多进程实现高并发服务器:父进程负责监听\创建子进程\子进程的回收(注册信号的方式);子进程与客服端交互.注意描述符的关闭.
***********************************************/
#include<stdlib.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <signal.h>
#include <string.h>
#include<unistd.h>
#include <arpa/inet.h>
#include <ctype.h>
#include<stdio.h>
#include <sys/wait.h>
#include <errno.h>

#define MULTI_SEVER_IP  "127.0.0.1"
#define MULTI_SERVER_PORT 6667
char buf[2048];//接受客服端的数据
void my_perror(const char * str)
{
   
	perror(str);
	exit(1);
}

void wait_func(int arg)
{
   
	int status;
	while(waitpid(0,&status,WNOHANG)>0) //如果有多个子进程需要回收,一定要使用while(),可以防止多个子进程同时死亡
    if (WIFEXITED(status)) {
   
       printf("child exited, status=%d\n", WEXITSTATUS(status));
   } else if (WIFSIGNALED(status)) {
   
       printf("killed by signal %d\n", WTERMSIG(status));
   }
}

int main()
{
   
	pid_t pid;
	int new_fd;
	char client_ip_buf[1024];
	//1.创建socket,采用ipv4,传输采用tcp协议
	int fd=socket(AF_INET,SOCK_STREAM,0);
	if(fd==-1)
	{
   
		my_perror("fork error");
	}
	//端口服用(2MSL时间里可再次启动server)
    int opt=1;
    setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
	//2.绑定fd和ip\端口号
	struct sockaddr_in multi_server_addr;
	
	memset(&multi_server_addr,0,sizeof(multi_server_addr));
	multi_server_addr.sin_family=AF_INET;
	multi_server_addr.sin_port=htons(MULTI_SERVER_PORT);
	inet_pton(AF_INET,&MULTI_SEVER_IP,&multi_server_addr.sin_addr.s_addr);
	
	int ret=bind(fd,(struct sockaddr *)&multi_server_addr,sizeof(multi_server_addr));
	if(ret==-1)
	{
   
		my_perror("bind error");
	}
	//3.设置同时连接上限
	int ret1=listen(fd,128);
	if(ret1==-1)
	{
   
		my_perror("listen error");
	}
	while(1)
	{
   
			//4.三次握手后,阻塞等待客服端连接
			struct sockaddr_in multi_client_addr;
			socklen_t multi_client_addr_len=sizeof(multi_client_addr);
			new_fd=accept(fd,(struct sockaddr *)&multi_client_addr,&multi_client_addr_len);//慢速系统调用,错误检查注意信号打断
			//打印客服端的信息
			printf("client %s is conneting,port is %d\n",
					inet_ntop(AF_INET,&multi_client_addr.sin_addr.s_addr,client_ip_buf,sizeof(client_ip_buf)),
					ntohs(multi_client_addr.sin_port));
			again:
					if((errno==ECONNABORTED)||(errno==EINTR))//accept为慢速系统调用,在被信号打断的时候,根据实际情况,是否重启
						goto again;
					else if(new_fd==-1)
					{
   
						my_perror("accept error");
					}
			//接受到新的客服端连接,就创建新的进程
			pid=fork();
			if(pid==-1)
			{
   
				my_perror("fork error");
			}
			else if(pid>0)
			{
   
				close(new_fd);
				//注册信号的方式回收子进程
				signal(SIGCHLD,wait_func);
			}
			else if(pid==0)
			{
   
				close(fd);//子进程不用fd,直接关掉(父进程不受影响)
				break; //跳出循环,执行子进程的动作.
			}
	}
	//子进程与客服端交互,父进程负责揽活
	if(pid==0)
	{
   
		while(1)
		{
   
			int n=read(new_fd,buf,sizeof(buf));
			if(n==0)//注意socket读到0表示客服端已经关闭
			{
   
				close(new_fd);
				exit(0);
			}
			else if(n==-1)
			{
   	again1:
				if(errno==EINTR)//read为慢速系统调用,在被信号打断的时候,根据实际情况,是否重启
					goto again1;
				else
				{
   
					perror("read error");
					exit(1);
				}
			}
			else if(n>0)
			{
   
				for(int i=0;i<n;i++)
					buf[i]=toupper(buf[i]);
				write(new_fd,buf,n);//写回客服端
				write(STDOUT_FILENO,buf,n);
			}
		}
	}
	return 0;
}

2>.多线程版

/***********************************************
Data:2020-12-2
Explanation:
使用线进程实现高并发服务器:主线程负责监听\创建子线程(设置为游离态)(注意:创建结构体client_info,将多个客服端的multi_client_addr信息和accept()返回的
描述符捆绑,一起传入pthread_create()函数);子线程与客服端交互.注意1.线程共享文件描述符;2.多线程对全局变量访问时需要加锁(读时共享,写时独占).
***********************************************/
#include<stdlib.h>
#include <pthread.h>
#include <sys/types.h>  
#include <sys/socket.h>
#include <string.h>
#include<unistd.h>
#include <arpa/inet.h>
#include <ctype.h>
#include<stdio.h>
#include <errno.h>

#define MULTI_SEVER_IP  "127.0.0.1"
#define MULTI_SERVER_PORT 6667
#define MAX_CLIENTNUM 100
int num=0;//统计登录客服端实时个数
pthread_mutex_t mutex; //定义一个互斥锁
struct client_info
{
   
	struct sockaddr_in multi_client_addr;
	int new_fd;
};

void my_perror(const char * str)
{
   
	perror(str);
	exit(1);
}
//子线程与客服端交互,父线程负责揽活
void * deal_client_func(void *arg )
{
   
	struct client_info *client_addr=(struct client_info *)arg;
	char buf[2048];//接受客服端的数据
	char client_ip_buf[1024];
	while(1)
		{
   
			int n=read(client_addr->new_fd,buf,sizeof(buf));
			if(n==0)//注意socket读到0表示客服端已经关闭
			{
   
				close(client_addr->new_fd);
				break;
			}
			else if(n==-1)
			{
   	
				again1:
				if(errno==EINTR)//read为慢速系统调用,在被信号打断的时候,根据实际情况,是否重启
					goto again1;
				else
				{
   
					perror("read error");
					break;
				}
			}
			else if(n>0)
			{
   
				for(int i=0;i<n;i++)
					buf[i]=toupper(buf[i
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值