一,网络服务器
1.单循环网络服务器 —— 同一时刻只能处理一个客户端任务
2.并发服务器 —— 同一时刻能处理多个客户端任务
二,并发服务器
1.多线程
2.IO多路复用
3.多进程
三,IO模型
1.阻塞IO
阻塞IO(Blocking IO)是一种传统的IO操作模式,在这种模式下,当一个IO操作(如读、写)执行时,如果不能立即完成,程序会暂停执行,直到该IO操作完成。类似于fgets, scanf, read, recv, getchar函数
实例
阻塞read.c
#include "head.h"int main(int argc, const char *argv[])
{char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if (-1 == fifofd){perror("fail open fifo");return -1;}while (1){fgets(buff, sizeof(buff), stdin);printf("STDIN : %s\n", buff);memset(buff, 0, sizeof(buff));read(fifofd, buff, sizeof(buff));printf("FIFO : %s\n", buff);}close(fifofd);return 0;
}
阻塞write.c
#include "head.h"int main(int argc, const char *argv[])
{ mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if (-1 == fd){perror("fail open fifo");return -1;}while (1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}
阻塞IO(Blocking IO)是一种传统的IO操作模式,在这种模式下,当一个IO操作(如读、写)执行时,如果不能立即完成,程序会暂停执行,直到该IO操作完成。这种IO模式具有以下几个特点:
1. 同步性
阻塞IO是同步的,意味着应用程序必须等待IO操作完成才能继续执行后续操作。在执行IO操作时,调用线程会被阻塞,无法继续处理其他任务。
2. 线程阻塞
当IO操作不能立即完成时,调用该操作的线程会被挂起,直到IO操作完成。这会导致线程在IO等待期间无法执行其他任务,从而降低CPU的利用率。
3. 编程模型简单
阻塞IO的编程模型相对简单,易于理解和实现。它不需要复杂的轮询或回调机制,直接通过系统调用来完成IO操作。
4. 适用场景
阻塞IO适用于连接数较少且每个连接需要较长时间处理的场景。在这种场景下,由于连接数不多,线程阻塞对整体性能的影响较小。
阻塞IO也适用于对并发性能要求不高的场景,如简单的文件读写操作或小型网络应用。
5. 缺点
在高并发场景下,阻塞IO的效率较低。因为每个连接都需要一个独立的线程来处理,当连接数增多时,会消耗大量的线程资源,可能导致线程资源耗尽。
线程在等待IO操作完成时处于阻塞状态,无法充分利用CPU资源,降低了系统的整体性能。
6. 改进方式
为了解决阻塞IO在高并发场景下的性能问题,可以采用非阻塞IO(Non-blocking IO)或IO多路复用(IO Multiplexing)等技术。非阻塞IO允许程序在等待IO操作完成时继续执行其他任务,而IO多路复用则允许一个线程同时处理多个IO操作。
综上所述,阻塞IO是一种简单但效率较低的IO操作模式,适用于连接数较少且对并发性能要求不高的场景。在高并发场景下,为了提高性能和资源利用率,可以考虑采用非阻塞IO或IO多路复用等更高效的IO操作模式。
2.非阻塞IO
非阻塞IO(Non-Blocking IO)是一种IO操作模式,其特点如下:
非阻塞特性:程序在发起IO请求后,不会等待IO操作完成,而是立即返回,程序可以继续执行后续操作。这提高了程序的运行效率和响应速度。
同步性:虽然非阻塞IO在发起请求后不会阻塞程序,但它是同步的,因为程序需要定期检查IO操作是否完成。这通常通过轮询或事件通知机制来实现。
适用场景:非阻塞IO适用于需要同时处理多个IO操作的并发环境,以及对IO操作响应时间要求较高的场景。
实现方式:非阻塞IO的实现通常依赖于操作系统的支持,例如通过设置socket为非阻塞模式,或使用特定的系统调用(如select、poll、epoll等)来检查IO操作的就绪状态。
总结来说,非阻塞IO允许程序在等待IO操作完成时继续执行其他任务,提高了程序的并发处理能力和响应速度但CPU占用率高。
实现:
1.获取原文件描述属性
2.增加非阻塞属性
3.设置属性
非阻塞read.c
#include "head.h"int main(int argc, const char *argv[])
{char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if (-1 == fifofd){perror("fail open fifo");return -1;}//1. 获取文件原有属性 int flag = fcntl(0, F_GETFL);//增加非阻塞属性//flag = flag | O_NONBLOCK;//去掉非阻塞属性flag = flag & (~O_NONBLOCK);//设置属性fcntl(0, F_SETFL, flag);while (1){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin);printf("STDIN : %s\n", buff);memset(buff, 0, sizeof(buff));read(fifofd, buff, sizeof(buff));printf("FIFO : %s\n", buff);}close(fifofd);return 0;
}
非阻塞write.c
#include "head.h"int main(int argc, const char *argv[])
{ mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if (-1 == fd){perror("fail open fifo");return -1;}while (1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}
3.信号驱动IO
信号驱动IO(Signal-driven IO)是一种异步IO机制,其特点如下:
异步通知:当IO操作准备就绪时,内核通过发送信号(如SIGIO)来通知应用程序。这样,应用程序可以在数据准备好时立即处理,而无需持续轮询或阻塞等待,节省CPU。
注册信号处理函数:应用程序需要预先注册一个信号处理函数,用于在接收到SIGIO信号时执行相应的IO操作。
底层驱动支持:信号驱动IO的实现需要底层驱动的支持,驱动在IO操作准备就绪时负责发送SIGIO信号。
适用场景:信号驱动IO特别适用于需要处理大量并发连接且对IO响应时间要求较高的场景,如网络服务器等。
总结来说,信号驱动IO通过信号机制实现异步IO操作,提高了程序的响应速度和并发处理能力。
实现:
1.增加异步属性
2.并联信号和当前进程
3.注册信号
4.信号调用函数
信号驱动read.c
#include "head.h"void handle(int signo)
{char buff[1024] = {0};fgets(buff, sizeof(buff), stdin);printf("STDIN : %s\n", buff);
}
int main(int argc, const char *argv[])
{signal(SIGIO, handle);char buff[1024] = {0};mkfifo("./myfifo", 0664);int fifofd = open("./myfifo", O_RDONLY);if (-1 == fifofd){perror("fail open fifo");return -1;}//1. 获取文件原有属性 int flag = fcntl(0, F_GETFL);flag = flag | O_ASYNC;fcntl(0, F_SETFL, flag);//2.关联当前进程fcntl(0, F_SETOWN, getpid());while (1){memset(buff, 0, sizeof(buff));read(fifofd, buff, sizeof(buff));printf("FIFO : %s\n", buff);}close(fifofd);return 0;
}
信号驱动write.c
#include "head.h"int main(int argc, const char *argv[])
{ mkfifo("./myfifo", 0664);int fd = open("./myfifo", O_WRONLY);if (-1 == fd){perror("fail open fifo");return -1;}while (1){write(fd, "hello world", 11);sleep(1);}close(fd);return 0;
}