思考

1. 那网络中进程之间如何通信,浏览器的进程怎么与web服务器通信的?
2. 什么时候用一请求一线程的方式?
3. 什么时候用select/poll?
4. 什么时候用epoll?

准备工作

下面展示socket几个常用的函数listenfd, bind, listen, accept具体作用

// 聘请迎宾的小姐姐
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;
}
// 迎宾的小姐姐在哪个门口工作
if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;
}
// 小姐姐正式走到门口开始迎宾
if (listen(listenfd, 10) == -1) {printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;
}
// 把客户带到大厅介绍一个服务员,coonfd就是服务员
if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;
}

网络连接的简单过程

网络IO模型

阻塞IO

1. 简单一问一答服务器/客户机模型

    当用户进程调用了 read 这个系统调用,kernel 就开始了 IO 的第一个阶段:准备数据。对于network io 来说,很多时候数据在一开始还没有到达(比如,还没有收到一个完整的数据包),这个时候 kernel 就要等待足够的数据到来。而在用户进程这边,整个进程会被阻塞。当 kernel一直等到数据准备好了它就会将数据从 kernel 中拷贝到用户内存,然后 kernel 返回结果,用户进程才解除 block 的状态,重新运行起来。所以,blocking IO 的特点就是在 IO 执行的两个阶段(等待数据和拷贝数据两个阶段)都被block 了。
    几乎所有的程序员第一次接触到的网络编程都是从 listen()、send()、recv() 等接口开始的,这些接口都是阻塞型的。使用这些接口可以很方便的构建服务器/客户机的模型。

代码展示

#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>#define MAXLNE  4096int main(int argc, char **argv)
{int listenfd, connfd, n;struct sockaddr_in servaddr;char buff[MAXLNE];if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(9999);if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}if (listen(listenfd, 10) == -1) {printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}struct sockaddr_in client;socklen_t len = sizeof(client);if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}printf("========waiting for client's request========\n");while (1) {n = recv(connfd, buff, MAXLNE, 0);if (n > 0) {buff[n] = '\0';printf("recv msg from client: %s\n", buff);send(connfd, buff, n, 0);} else if (n == 0) {close(connfd);}//close(connfd);}close(listenfd);return 0;
}

2. 多线程方式

提出问题

    实际上,除非特别指定,几乎所有的 IO 接口 ( 包括 socket 接口 ) 都是阻塞型的。这给网络编程带来了一个很大的问题,如在调用 send()的同时,线程将被阻塞,在此期间,线程将无法执行任何运算或响应任何的网络请求。

解决方案

   改进方案是在服务器端使用多线程(或多进程)。多线程(或多进程)的目的是让每个连接都拥有独立的线程(或进程),这样任何一个连接的阻塞都不会影响其他的连接。具体使用多进程还是多线程并没有一个特定的模式。

适用场景与注意的问题

   户端不多的情况下,在一个局域网内,做几个人的会议这类的,理论上客户端很难突破C10k,使用 pthread_create ()创建新线程。
   多线程的服务器模型似乎完美的解决了为多个客户机提供问答服务的要求,但其实并不尽然。如果要同时响应成百上千路的连接请求,则无论多线程还是多进程都会严重占据系统资源,降低系统对外界响应效率,而线程与进程本身也更容易进入假死状态。
   这时候很多人会考虑使用“线程池”“连接池”。这里就需要深刻理解一下其概念,“线程池”旨在减少创建和销毁线程的频率,其维持一定合理数量的线程,并让空闲的线程重新承担新的执行任务。“连接池”维持连接的缓存池,尽量重用已有的连接、减少创建和关闭连接的频率。所谓“池”始终有其上限,当请求大大超过上限时,“池”构成的系统对外界的响应并不比没有池的时候效果好多少。所以使用“池”必须考虑其面临的响应规模,并根据响应规模调整“池”的大小。

代码展示

#include <errno.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>#include <pthread.h>#define MAXLNE  4096//8m * 4G = 128 , 512
//C10k
void *client_routine(void *arg) { //int connfd = *(int *)arg;char buff[MAXLNE];while (1) {int n = recv(connfd, buff, MAXLNE, 0);if (n > 0) {buff[n] = '\0';printf("recv msg from client: %s\n", buff);send(connfd, buff, n, 0);} else if (n == 0) {close(connfd);break;}}return NULL;
}int main(int argc, char **argv)
{int listenfd, connfd, n;struct sockaddr_in servaddr;char buff[MAXLNE];if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {printf("create socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}memset(&servaddr, 0, sizeof(servaddr));servaddr.sin_family = AF_INET;servaddr.sin_addr.s_addr = htonl(INADDR_ANY);servaddr.sin_port = htons(9999);if (bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) == -1) {printf("bind socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}if (listen(listenfd, 10) == -1) {printf("listen socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}printf("========waiting for client's request========\n");while (1) {struct sockaddr_in client;socklen_t len = sizeof(client);if ((connfd = accept(listenfd, (struct sockaddr *)&client, &len)) == -1) {printf("accept socket error: %s(errno: %d)\n", strerror(errno), errno);return 0;}pthread_t threadid;pthread_create(&threadid, NULL, client_routine, (void*)&connfd);}close(listenfd);return 0;
}

理解多线程方式不足

   假设有A, B, C三个客户端连接服务器,其中A, B发送数据,C连接进来。A, B服务员正在服务,C迎宾的小姐姐迎接。这时候服务器没办法准确的预测哪个fd会有数据来临。大量的客户端链接进来,需处理多个客户端,我们不知道哪个客户端需要我们处理。这时,如果有一个组件把所有的fd放在一起,准确的知道哪个客户端需要我们处理

预知后事,请听下回分解,链接: 网络管理IO - 多路复用IO.

网络IO管理-简单一问一答、多线程方式相关推荐

  1. 后端开发【一大波有用知识】网络通信模型和网络IO管理

    简单的C/S通信模型(accept阻塞的话,就只能一个客户端接进来) socket()函数 //函数原型.返回:若是成功则为非负数,如出错则为 -1 int socket(int domin, int ...

  2. [转]资深CTO:关于技术团队打造与管理的10问10答

    一.你如何衡量软件工程师个人的工作表现?如何衡量整个工程师团队的工作表现? 主要从两方面: 这个员工做的工作是不是他同意做的或者应该做的?(What) 他们是如何完成自己的工作的?(How) 任何绩效 ...

  3. 建立网络口碑打造之一问一答式推广

    问答营销是互动推广创新型营销方法,是互动推广处于第三方平台口牌而建立的网络推广方式的一种,营销方法既能与潜在客户产生互动交流,又能注入企业广告,是做企业品牌口牌.互动推广很好的营销方法的一种. 问答影 ...

  4. mysql io模型_5种网络IO模型

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...

  5. 5种网络IO模型:阻塞IO、非阻塞IO、异步IO、多路复用IO、信号驱动IO

    目录 前言 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO(Asynchronous I/O) 模型间的区别 ...

  6. 从网络IO看高性能框架

    讨论一个高性能框架甚至语言的时候,我们在讨论什么? 三大网络模型阻塞IO+多进程阻塞IO+多线程非阻塞IO+IO多路复用 五种网络IO简介 网络IO的本质 如何区分阻塞IO和非阻塞IO 如何区分同步和 ...

  7. 【Android App】实战项目之实现你问我答的智能语音机器人(超详细 附源码和演示视频)

    需要全部代码请点赞关注收藏后评论区留言私信~~~ 一.需求描述 想必大家都见过商场里的智能语音机器人,你对它提问时它可以自动回答你的问题,接下来我们也实现这样一个机器人,它依靠语音技术完成问询服务 基 ...

  8. 高并发下的网络 IO 模型设计

    今天我们先聊一下高并发下的网络 IO 模型设计 高并发即我们所说的 C10K(一个server 服务 1w 个 client),C10M,写出高并发的程序相信是每个后端程序员的追求,高并发架构其实有一 ...

  9. 网络工程师面试时喜欢问的问题

    1.请写出 568A 与 568B 的线序: T568A 白绿.绿. 白橙.蓝 白蓝.橙 白棕.棕 T568B :白橙.橙 白绿.蓝 白蓝.绿 白棕.棕 2.  什么是三层交换,说说和路由的区别在哪里 ...

最新文章

  1. bash读取txt文件, 并在浏览器中以表格形式输出
  2. 文件输出 java_用Java读写文件(输入/输出)-教程
  3. Python中文编码判别及转换
  4. python的常用语句_python常用语句
  5. FastReport使用一——简介
  6. 机器学习 --- 4. 大内密探HMM(隐马尔可夫)围捕赌场老千(转)
  7. FreeSWITCH channel variables(信道变量)
  8. java车牌识别字符分割_opencv 车牌字符分割 ANN网络识别字符
  9. 「AI产品」产品小姐姐分析抖音背后的计算机视觉技术
  10. 如何设计一个超级牛逼的 Feed 流系统
  11. 英语语法(简单句型篇)
  12. 知识图谱学习(二):电商知识图谱
  13. poi生成word 纸张方向横竖切换
  14. 紫砂壶的起源 计算机操作题,紫砂壶的起源与历史发展
  15. SAP的统驭科目 - 什么是SAP的统驭科目
  16. pom里配置阿里云仓库
  17. 手把手教你抄板(待更新)
  18. 中国石斛行业渠道营销策略与发展态势研究报告2022版
  19. 智慧大田——智能无线灌溉系统
  20. 图像均值、标准差、变异系数的意义

热门文章

  1. Fabric 1.0源代码分析(34) Peer #peer chaincode命令及子命令实现
  2. Fabric 1.0源代码分析(26)Orderer #ledger(Orderer Ledger)
  3. 磐河数据php代码,【名门的骄将】袁绍磐河战公孙,麴义先登...
  4. html5自动局部刷新,HTML页面局部刷新的实现代码
  5. 【软工视频】--需求分析
  6. 2020 年最具潜力的 44 个顶级开源项目
  7. mysql外键的建立和删除更新
  8. Matlab unravel函数,有没有更好的方法在python中执行“unravel”函数?
  9. 图情论文笔记 | 四川大学图书馆关于“十四五”发展规划的初步思考(党跃武)
  10. 西门子1200与欧姆龙E5cc温控器 远程+本地双重控制通讯程序