ToB企服应用市场:ToB评测及商务社交产业平台

标题: 【网络编程】高性能并发服务器源码剖析 [打印本页]

作者: 丝    时间: 2024-6-20 20:23
标题: 【网络编程】高性能并发服务器源码剖析
 

  hello !大家好呀! 接待大家来到我的网络编程系列之洪水网络攻击,在这篇文章中,你将会学习到在网络编程中怎样搭建一个高性能的并发服务器,而且我会给出源码进行剖析,以及手绘UML图来帮助大家来明白,盼望能让大家更能了解网络编程技能!!!
  盼望这篇文章能对你有所帮助
,大家要是觉得我写的不错的话,那就点点免费的小爱心吧!

  
               
  目录
一.网络服务器 
 1.1 平凡循环网络服务器

2.2 简单并发网络服务器
2.2.1简单的并发服务器模型
2.2.2使用历程的并发服务器
2.2.3使用线程的并发服务器
2.2.4其他并发服务器模型
二.使用互斥锁实现单线程处理单个客户
2.1 具体步骤
2.2服务器代码模板
三.源码剖析


一.网络服务器 

 1.1 平凡循环网络服务器

对于平凡的循环网络服务器,着实就是服务器使用循环的方法逐个对客户的毗连进行处理,处理完一个毗连后再处理下一个毗连,其过程如下:

最简单的代码模型我还是给大家:
  1. #include<t_stdio.h>
  2. #include<sys/types.h>         
  3. #include <sys/socket.h>
  4. #include<arpa/inet.h>
  5. #include <sys/socket.h>
  6. #include<ctype.h>
  7. #include<unistd.h>
  8. int main(void){
  9.     struct sockaddr_in serv,cli;
  10.     socklen_t cli_len;
  11.     char buf[128];
  12.     char IP[32];
  13.     //创建一个通讯端点,返回该端点的文件描述符
  14.     //创建一个ipv4的tcp连接端口
  15.     int s_fd=socket( AF_INET ,SOCK_STREAM ,0);
  16.     //需要对server变量成员初始化
  17.     serv.sin_family=AF_INET;
  18.     serv.sin_port=htons(5556);
  19.     serv.sin_addr.s_addr=htonl(INADDR_ANY);
  20.     //将s_fd和本地地址,端口号绑定
  21.     int b=bind(s_fd,(struct sockaddr *)&serv,sizeof(serv));
  22.     if(b==-1)E_MSG("bind",-1);
  23.     if(s_fd==-1)E_MSG("socket",-1);
  24.     //将s_fd设置为被动连接,监听客户端连接的到来
  25.     //将客户端到来的连接放入未决连接队列中
  26.     //指定未决连接队列的长度
  27.     listen(s_fd,5);
  28.     while(1){
  29.         //从s_fd设备的未连接队列中提取一个进程进行处理
  30.         //返回一个连接描述符,使用这个连接描述符与客户端进行通讯
  31.         int c_fd=accept(s_fd,(struct sockaddr *)&cli,&cli_len);
  32.         if(c_fd==-1)E_MSG("accept",-1);
  33.         //binary--->text
  34.         inet_ntop(AF_INET,&cli.sin_addr,IP,32);
  35.         printf("client ip: %s\n",IP);
  36.         //代码执行到这里,三次握手以及完成,可以进行数据传输了
  37.         //从c_fd中读取客户端发送过来的请求信息
  38.         int r = read(c_fd,buf,128);
  39.         //处理客户端的请求信息
  40.         int i;
  41.          for(i=0;i<r;i++){
  42.             buf[i]=toupper(buf[i]);
  43.          }
  44.          //将处理结果回送客户端
  45.          write(c_fd,buf,r);
  46.         //关闭本次连接
  47.         close(c_fd);
  48.     }
  49.     return 0;
  50. }
复制代码
这是最简单的循环服务器代码,功能是将客户传过来的字符串全部转换为大写,这个最简单代码盼望大家能全部弄懂,关于内里还有不懂的,可以去看我我前面的博客:[C++/Linux] socket套接字函数-CSDN博客


2.2 简单并发网络服务器

并发网络服务器是指可以大概同时处理多个客户端哀求的网络服务器。这种服务器的筹划允许它在任何时候处理多个客户端的毗连和哀求,而不会因为某个哀求的处理而阻塞其他哀求。并发服务器可以提高资源的利用率,增强服务器的响应本领,是现代网络应用的底子。下面我将先容几种常见的并发网络服务器模型:
2.2.1简单的并发服务器模型

2.2.2使用历程的并发服务器

这里我手绘一个UML图来帮助大家明白怎样利用历程池:

2.2.3使用线程的并发服务器

这里我手绘一个UML图来帮助大家明白怎样利用线程池:


对于历程和线程大家有不了解的,可以看我前面博客:[C++/Linux] Linux线程详解-CSDN博客

2.2.4其他并发服务器模型


二.使用互斥锁实现单线程处理单个客户

这里我们使用互斥锁来对每个进行上锁,实现单客户单历程处理,
2.1 具体步骤

2.2服务器代码模板

  1. #include <pthread.h>
  2. pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  3. void *handle_client(void *client_socket) {
  4.     int socket = *(int *)client_socket;
  5.     // 加锁
  6.     pthread_mutex_lock(&lock);
  7.     // 处理客户请求
  8.     // ...
  9.     // 释放锁
  10.     pthread_mutex_unlock(&lock);
  11.     // 关闭客户端套接字
  12.     close(socket);
  13.     return NULL;
  14. }
  15. int main() {
  16.     // 创建监听套接字
  17.     // ...
  18.     while (1) {
  19.         int client_socket = accept(listen_socket, NULL, NULL);
  20.         // 创建线程来处理客户端
  21.         pthread_t thread;
  22.         pthread_create(&thread, NULL, handle_client, &client_socket);
  23.         pthread_detach(thread); // 使线程独立运行
  24.     }
  25.     // 关闭监听套接字
  26.     // ...
  27.     return 0;
  28. }
复制代码

三.源码剖析

  1. #include<t_stdio.h>
  2. #include<t_file.h>
  3. #include<stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <string.h>
  7. #include <arpa/inet.h>
  8. #include<unistd.h>
  9. #include<time.h>
  10. #include<pthread.h>
  11. #include <string.h>
  12. #define bufferlen 1024 //发送/接收数据缓冲区大小
  13. #define server_port 8888 //端口
  14. #define backlog 5 //监听队列
  15. #define max_pthread 3 //最大线程数
  16. //线程处理业务函数
  17. pthread_mutex_t ALOCK = PTHREAD_MUTEX_INITIALIZER ;//创建互斥量
  18. static void * handle_request(void * argv){
  19.     int s_s = *((int *) argv);
  20.     int s_c;
  21.     struct sockaddr_in from ;
  22.     socklen_t len = sizeof(from);
  23.     for(;;){
  24.         time_t now;
  25.         char buf [bufferlen];
  26.         int n=0;
  27.         pthread_mutex_lock(&ALOCK); //进入互斥区
  28.         s_c = accept(s_s , (struct sockaddr *)&from , &len);//接收请求
  29.         pthread_mutex_unlock(&ALOCK); //离开互斥区
  30.         memset(buf , 0 ,bufferlen);
  31.         n = recv(s_c , buf , bufferlen , 0);//接收数据
  32.         
  33.         if(n > 0 && !strncmp(buf , "TIME" , 4))//判断是否为合法接收数据
  34.         {
  35.             memset(buf ,0 ,bufferlen);
  36.             now = time(NULL);
  37.             sprintf(buf , "%24s\r\n",ctime(&now));//时间写入buf
  38.             send(s_c , buf , strlen(buf) , 0);//发送给客户端
  39.         }
  40.         close(s_c);
  41.     }
  42.     return ;
  43. }
  44. //线程创建函数
  45. static void handle_connect(int s){
  46.     int s_s =s;
  47.     pthread_t thread_do[max_pthread];//创建线程数组
  48.     int i=0;
  49.     //创建线程,每一次创建调用线程处理函数
  50.     for(i = 0; i<max_pthread;i++){
  51.         pthread_create(&thread_do[i] , NULL, handle_request , (void *)&s_s);
  52.     }
  53.     //等待线程结束
  54.     for(i = 0; i<max_pthread;i++){
  55.         pthread_join(thread_do[i] , NULL);
  56.     }
  57. }
  58. int main(int argc ,char * argvp[]){
  59.     int s_s;
  60.     struct sockaddr_in local ;//本地地址
  61.     s_s = socket(AF_INET , SOCK_STREAM , 0);
  62.     memset(&local , 0 , sizeof(local));
  63.     local.sin_family = AF_INET;
  64.     local.sin_addr.s_addr = htonl(INADDR_ANY);
  65.     local.sin_port = htons(server_port);
  66.     bind(s_s , (struct sockaddr *)&local ,sizeof(local));//连接本地地址
  67.     listen(s_s , backlog);//创建监听队列
  68.     handle_connect(s_s);
  69.     close(s_s);
  70.     return 0;
  71. }
复制代码
这段代码是一个简单的网络服务器示例,它使用了 POSIX 线程(pthread)来处理客户端哀求。下面我将逐行表明代码的功能:
  1. #include <t_stdio.h>
  2. #include <t_file.h>
  3. #include <stdlib.h>
  4. #include <sys/types.h>
  5. #include <sys/socket.h>
  6. #include <string.h>
  7. #include <arpa/inet.h>
  8. #include <unistd.h>
  9. #include <time.h>
  10. #include <pthread.h>
  11. #include <string.h>
复制代码
这里包含了须要的头文件,包括标准输入输出、文件操纵、网络编程、字符串操纵、IP地址转换、非阻塞I/O等。
  1. #define bufferlen 1024 //发送/接收数据缓冲区大小
  2. #define server_port 8888 //端口
  3. #define backlog 5 //监听队列
  4. #define max_pthread 3 //最大线程数
复制代码
界说了一些宏,用于设置缓冲区大小、服务器端口、监听队列大小和最大线程数。
  1. //线程处理业务函数
  2. pthread_mutex_t ALOCK = PTHREAD_MUTEX_INITIALIZER ;//创建互斥量
复制代码
界说了一个互斥量 ALOCK,用于线程间的同步。
  1. static void * handle_request(void * argv){
  2.     int s_s = *((int *) argv);
  3.     int s_c;
  4.     struct sockaddr_in from ;
  5.     socklen_t len = sizeof(from);
  6.     for(;;){
  7.         time_t now;
  8.         char buf [bufferlen];
  9.         int n=0;
  10.         pthread_mutex_lock(&ALOCK); //进入互斥区
  11.         s_c = accept(s_s , (struct sockaddr *)&from , &len);//接收请求
  12.         pthread_mutex_unlock(&ALOCK); //离开互斥区
  13.         memset(buf , 0 ,bufferlen);
  14.         n = recv(s_c , buf , bufferlen , 0);//接收数据
  15.         
  16.         if(n > 0 && !strncmp(buf , "TIME" , 4))//判断是否为合法接收数据
  17.         {
  18.             memset(buf ,0 ,bufferlen);
  19.             now = time(NULL);
  20.             sprintf(buf , "%24s\r\n",ctime(&now));//时间写入buf
  21.             send(s_c , buf , strlen(buf) , 0);//发送给客户端
  22.         }
  23.         close(s_c);
  24.     }
  25.     return ;
  26. }
复制代码
handle_request 函数是线程处理业务的核心。它继承一个整数参数 s_s,这是服务器套接字。函数进入一个无穷循环,吸收客户端的毗连(accept 调用),吸收数据(recv 调用),处理数据(如果数据是以 “TIME” 开头的,则返回当前时间),然后关闭客户端套接字。

     好啦!到这里这篇文章就竣事啦,关于实例代码中我写了很多表明,如果大家还有不懂得,可以评论区或者私信我都可以哦
!! 感谢大家的阅读,我还会连续创造网络编程相干内容的,记得点点小爱心和关注哟!
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4