Linux:多进程、多线程服务器的实现解析(有图有代码有真相!!!)

一、问题引入

阻塞型的网络编程接口


几乎所有的程序员第一次接触到的网络编程都是从 listen()、send()、recv()等接口开始的。使用这些接口可以很方便的构建服务器 /客户机的模型。
我们假设希望建立一个简单的服务器程序,实现向单个客户机提供类似于“一问一答”的内容服务。


我们注意到,大部分的 socket接口都是阻塞型的。所谓阻塞型接口是指系统调用(一般是 IO接口)不返回调用结果并让当前线程一直阻塞,只有当该系统

调用获得结果或者超时出错时才返回。实际上,除非特别指定,几乎所有的 IO接口 (包括 socket 接口 )都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用 send()的同时,线程将被

阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。这给多客户机、多业务逻辑的网络编程带来了挑战。这时,很多程序员可能会选择多线程的方式来解决这个问题。


二、多进程多线程

应对多客户机的网络应用,最简单的解决方式是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进

程),这样任何一个连接的阻塞都不会影响其他的连接。具体使用多进程还是多线程,并没有⼀一个特定的模式。传统意义上,进程的开

销要远远大于线程,所以,如果需要同时为较多的客户机提供服务,则不推荐使用多进程;如果单个服务执行体需要消耗较多的 CPU 资源,譬如需要进行

大规模或长时间的数据运算或文件访问,则进程较为安全。通常,使用pthread_create () 创建新线程,fork() 创建新进程。



我们假设对上述的服务器 / 客户机模型,提出更高的要求,即让服务器同时为多个客户机提供一问一答的服务。于是有了如上的模型。
在上述的线程 / 时间图例中,主线程持续等待客户端的连接请求,如果有连接,则创建新线程,并在新线程中提供为前例同样的问答服务。
很多初学者可能不明白为何一个 socket 可以 accept 多次。实际上,socket的设计者可能特意为多客户机的情况留下了伏笔,让 accept() 能够返回一个新
的 socket。下面是 accept 接口的原型:输入参数 sockfd 是从 socket(),bind() 和 listen() 中沿用下来的 socket 句柄


值。执行完 bind() 和 listen() 后,操作系统已经开始在指定的端口处监听所有的连接请求,如果有请求,则将该连接请求加入请求队列。调用 accept() 接口
正是从 socket s 的请求队列抽取第一个连接信息,创建⼀一个与 socked同类的新的 socket 返回句柄。新的 socket 句柄即是后续 read() 和 recv() 的输入参
数。如果请求队列当前没有请求,则 accept() 将进⼊入阻塞状态直到有请求进入队列。


1、多进程服务器、客户端实现简单通信

fork_server.c:#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
static int startup(const char *_ip,int _port)
{int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 3; }struct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(_port);local.sin_addr.s_addr=inet_addr(_ip);if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");return 4;}if(listen(sock,10)<0){perror("listen");return 5;}
}
static void usage(const char *proc)
{printf("usage:[local_ip] [local_port]",proc);
}
int main(int argc,char *argv[])
{if(argc!=3){usage(argv[0]);printf("usage");return 1;}int listen_sock=startup(argv[1],atoi(argv[2]));struct sockaddr_in peer;socklen_t len=sizeof(peer);while(1){int new_sock=accept(listen_sock,(struct sockaddr*)&peer,&len);if(new_sock>0){pid_t id=fork();if(id==0){//childclose(listen_sock);char buf[1024];while(1){ssize_t s=read(new_sock,buf,sizeof(buf)-1);if(s>0){buf[s]=0;printf("client say#%s\n",buf);write(new_sock,buf,strlen(buf));}else if(s==0){printf("client quick\n");}else{break;}}close(new_sock);exit(1);}else{//fatherclose(new_sock);if(fork()>0){exit(0);}}}else{perror("new_sock");return 2;}}return 0;
}

fork_client.c:#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
static void usage(const char *proc)
{printf("usage:[server_ip] [server_port]",proc);
}
int main(int argc,char *argv[])
{int sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 1;}struct sockaddr_in server;server.sin_family=AF_INET;server.sin_port=htons(atoi(argv[2]));server.sin_addr.s_addr=inet_addr(argv[1]);if(connect(sock,(struct sockaddr*)&server,sizeof(server))<0){perror("connect");return 2;}char buf[1024];while(1){printf("please enter:");fflush(stdout);ssize_t s=read(0,buf,sizeof(buf)-1);if(s>0){buf[s-1]=0;write(sock,buf,strlen(buf));ssize_t _s=read(sock,buf,sizeof(buf)-1);if(_s>0){buf[_s]=0;printf("server echo:%s\n",buf);}}}close(sock);return 0;
}


2、多线程实现简单服务器(远程登陆:telnet)

thread_server.c#include<stdio.h>
#include<pthread.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<string.h>
void* handleRequest(void* arg)
{char buf[10240];int sock=(int)arg;while(1){ssize_t s=read(sock,buf,sizeof(buf)-1);//successif(s>0){buf[s]=0;printf("%s\n",buf);const char *msg= "HTTP/1.1 200 OK\r\n\r\n<html><h1>This is title</h1></html>\r\n";write(sock,msg,strlen(msg));break;}else if(s==0)   {printf("client is quit!\n");break;}else{perror("read");break;}}close(sock);
}
int startup(const char *_ip,int _port)
{//create socketint sock=socket(AF_INET,SOCK_STREAM,0);if(sock<0){perror("socket");return 2;}int flag=1;setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));//bindstruct sockaddr_in local;local.sin_family=AF_INET;local.sin_port=htons(_port);local.sin_addr.s_addr=inet_addr(_ip);if(bind(sock,(struct sockaddr*)&local,sizeof(local))<0){perror("bind");return 3;}//listenif(listen(sock,10)<0){perror("listen");return 4;}return sock;
}
static void usage(char *proc)
{printf("usage:%s [server_ip] [server_port]",proc);
}
int main(int argc, char *argv[])
{if(argc!=3){usage(argv[0]);return 1;}int listen_sock=startup(argv[1],atoi(argv[2]));struct sockaddr_in peer;socklen_t len=sizeof(peer);while(1){int new_sock=accept(listen_sock,(struct sockaddr*)&peer,&len); if(new_sock<0){perror("accept");continue;}printf("client ip:%s,port:%d\n",inet_ntoa(peer.sin_addr),ntohs(peer.sin_port));pthread_t id;pthread_create(&id,NULL,handleRequest,(void*)new_sock);pthread_detach(id);}return 0;
}






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

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

相关文章

数据结构:神奇的B树实现解析(有图有代码有真相!!!)

一、B树引入 二叉搜索树、平衡二叉树、红黑树都是动态查找树&#xff0c;典型的二叉搜索树结构&#xff0c;查找的时间复杂度和树的高度相关O(log2N)。 1&#xff09;数据杂乱无章-------线性查找--O&#xff08;n&#xff09; 2&#xff09;数据有序-------二分查找 ---O(lo…

Linux:dup/dup2 文件描述符重定向函数(有图有代码有真相!!!)

一、dup/dup2 有时我们希望把标准输入重定向到一个文件&#xff0c;或者把标准输出重定向到一个网络连接。系统调用dup和dup2能够复制文件描述符。dup返回新的文件文件描述符&#xff08;没有用的文件描述符最小的编号&#xff09;。 dup2可以让用户指定返回的文件描述符的值…

Linux:I/O多路转接之select(有图有代码有真相!!!)

一、select引入 一次 I/O 分为两个部分&#xff1a;1&#xff09;等待数据就绪 2&#xff09;进行数据转移 1、select 原理&#xff1a; select的原理就是减少等待数据就绪的比重&#xff0c;巧妙的利用等待队列机制让用户进程适当在没有资源可读/写时睡眠&#xff0c;有资…

Linux: I/O多路转接之poll(有图有代码有真相!!!)

一、poll()函数解析 不同与select使⽤用三个位图来表⽰示三个fdset的⽅方式&#xff0c;poll使⽤用⼀一个 pollfd的指针实现。pollfd结构包含了要监视的event和发⽣生的event&#xff0c; 不再使⽤用select“参数-值”传递的⽅方式。同时&#xff0c;pollfd并没有最⼤大数量限…

kalilinux装到u盘上的弊端_付费下载的歌曲,竟然无法在汽车上播放!原因在这里...

『使用某音乐播放器下载了周杰伦的110首歌曲&#xff0c;其中106首是kgm格式&#xff0c;4首mp3格式&#xff0c;装到U盘后&#xff0c;在其它设备播放只有4首mp3格式的可以播放&#xff0c;其它的均无法播放&#xff0c;请问该如何处理&#xff1f;』网友留言截图这是一位网友…

iconsvg image怎么变为path_昆凌是怎么收服天王周杰伦的?这几招太高明了

周杰伦和昆凌又出来撒狗粮了&#xff01;就在前两天(6月2日)&#xff0c;在参加郎朗的婚礼时&#xff0c;#周杰伦搂昆凌看烟花#的消息悄悄上了热搜。视频中&#xff0c;两人并肩站立&#xff0c;一起欣赏着窗外的美景。周杰伦时不时在昆凌的耳边私语几句&#xff0c;看起来很是…

Linux: I/O多路转接之epoll(有图有代码有真相!!!)

一、基本概念 epoll是Linux内核为处理大批量文件描述符而作了改进的poll&#xff0c;是Linux下多路复用IO接口select/poll的增强版本&#xff0c;它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。 另一点原因就是获取事件的时候&#xff0c;它无须遍历整…

ewebeditor未授权:功能被禁用请先配置授权_SteamPY新功能——外区账号礼物自动领取...

自从PY平台增加了外区代购后发现许多玩家在购买礼物时常会发生收到礼物后准备点击入库时弹出地区不可用的提示这个问题在Steam外区账号一直频繁发生究其因在于Steam账号登录时的IP问题遇到该问题切勿拒收礼物&#xff01;通过Steam客户端清理登录授权注销退出后再次使用账号对应…

Linux: shell 中命令代换 $() 和 ``(有图有代码有真相!!!)

一、命令代换&#xff08;命令替换&#xff09; 由 或 $() 括起来的也是一条命令&#xff0c;shell先执行该命令&#xff0c;再将结果立刻代换到当前命令行中。 简单例子&#xff1a; DATEdate echo $DATE DATE$(date) echo $DATE 执行结果&#xff1a; 二、优缺点&#x…

精雕道路怎么遍弧形_【养护技术】道路“创可贴”——沥青冷补料 六大优势助力道路养护...

点击上面蓝字关注我们微信号&#xff1a;xzgsgl随着城市精细化管理目标不断提高&#xff0c;市政道路养护修补的要求也越来越高。不但对修补的外观、质量有了更高的标准&#xff0c;对修复时限也提出了一定要求&#xff0c;这就要求我们的养护单位快速、优质地完成道路修补任务…

单耳蓝牙耳机怎么连接_蓝牙耳机怎么挑选?推荐性价比高的蓝牙耳机

随着手机逐渐取消了耳机孔&#xff0c;越来越多的人们开始使用上了蓝牙耳机。在当今这个飞速发展的时代&#xff0c;蓝牙耳机无疑成为了新时代的宠儿。无论是上班族还是当代大学生等年轻化群体&#xff0c;耳机的第一选择都是蓝牙耳机。但是面对市面上如此多的蓝牙耳机&#xf…

Linux: shell命令 eval (有图有代码有真相!!!)

一、eval 命令定义 shell中的eval命令将会首先扫描命令行进行所有的替换&#xff0c;然后再执行命令。该命令使用于那些一次扫描无法实现其功能的变量。 该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时候被称为复杂变量。不过这些变量本身并不复杂。eval 命令也可…

Linux:shell脚本命令: /dev/null 21 的理解

1、可以将/dev/null看作"黑洞". 它非常等价于一个只写文件. 所有写入它的内容都会永远丢失. 而尝试从它那儿读取内容则什么也读不到. 然而, /dev/null对命令行和脚本都非常的有用. 禁止标准输出. 1 cat $filename >/dev/null # 文件内容丢失&#xff0c;而不…

qlabel可以选中吗_惊现凡尔赛式排版!原来微信公众号排版样式还可以“变装”?...

各位小伙伴们&#xff0c;要集中注意力了&#xff01;接下来就是考验你们观察力的时候啦&#xff01;快跟着小妹儿看一下&#xff0c;一个样式到底能有多少种玩法&#xff1f;文中使用工具为公众号编辑器-小蚂蚁编辑器。1、添加/删除背景编辑器里的内容样式是可以增加或者删除背…

LInux:shell 彩色进度条实现(有图有代码有真相!!!)

一、进度条原理&#xff08;以前的博客详细讲述过&#xff09;&#xff1a;http://blog.csdn.net/sharp_up/article/details/55506555 二、颜色设置 // 字体颜范围(前景颜色):30~39 30:黑 31:红 32:绿 33:黄 34:蓝色 35:紫色 36:深绿 37:白色 // 字背景颜色范围(背景颜…

vb语言中怎样编码窗体中所有字体加粗_VBText控件中使字体加粗和倾斜的代码是什么...

展开全部VBText控件中使字体加粗和倾e69da5e6ba9062616964757a686964616f31333365656537斜的代码是&#xff1a;加粗 Label1.FontBold True斜体 Label1.FontItalic true拓展资料&#xff1a;TextBox控件&#xff1a;a. 控制Textbox输入格式&#xff0c;我想大多人都遇到这个…

Linux: 系统配置 crond 和 crontab(有图有代码有真相!!!)

1、相关概述 linux下工作调度的种类有&#xff1a;at , cron 一种是例行性的&#xff0c;就是每隔一定的周期来办某事。 一种是突发性的&#xff0c;就是做完这一次没有以后。 crontab这个命令所设置的工作将会一直循环进行下去&#xff0c;循环的时间可以是分钟、小时、…

前端radio单选框默认选中_「radio选中」单选框radio总结(获取值、设置默认选中值、样式) - seo实验室...

radio选中单选框 radio是否1.获取值$("input[namekillOrder]:checked").val();$(input:radio:checked).val()&#xff1b;$("input[typeradio]:checked").val();$(":radio[checked]").each(function(radio){alert($(this).val());2.设置第一个Ra…

LInux:shell 命令:字符串截取

1、cut命令截取 使用说明 cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。 如果不指定 File 参数&#xff0c;cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。 主要参数 -b &#xff1a;以字节为单位进行分割。这些字节位置将忽…

cocostuff10k数据集介绍_(六)COCO数据集的简单介绍

COCO通过大量使用Amazon Mechanical Turk来收集数据。COCO数据集现在有3种标注类型&#xff1a;object instances(目标实例), object keypoints(目标上的关键点), 和image captions(看图说话)&#xff0c;使用JSON文件存储。比如下面就是Gemfield下载的COCO 2017年训练集中的标…