手绘风格 网站,wordpress 字体图标,社团网站开发模板,软件开发学校Linux网络编程系列 #xff08;够吃#xff0c;管饱#xff09; 1、Linux网络编程系列之网络编程基础 2、Linux网络编程系列之TCP协议编程 3、Linux网络编程系列之UDP协议编程 4、Linux网络编程系列之UDP广播 5、Linux网络编程系列之UDP组播 6、Linux网络编程系列之服务器编…Linux网络编程系列 够吃管饱 1、Linux网络编程系列之网络编程基础 2、Linux网络编程系列之TCP协议编程 3、Linux网络编程系列之UDP协议编程 4、Linux网络编程系列之UDP广播 5、Linux网络编程系列之UDP组播 6、Linux网络编程系列之服务器编程——阻塞IO模型 7、Linux网络编程系列之服务器编程——非阻塞IO模型 8、Linux网络编程系列之服务器编程——多路复用模型 9、Linux网络编程系列之服务器编程——信号驱动模型
一、什么是阻塞IO模型 服务器阻塞IO模型是一种IO模型其中服务器在处理INGRESS和EGRESS网络数据流时阻塞并且无法处理其他连接请求。当服务器接收到一个连接请求时它将读取数据直到读取完成然后进行处理并发送响应这期间该连接请求将会阻塞其他连接请求的处理。
二、特性 1、阻塞IO调用当服务器没有数据可读或者没有缓冲区可写入时服务器将被阻塞。 2、每个连接都需要创建一个新的线程或进程来处理因此服务器开销和资源占用会很大。 3、每个连接需要消耗一定的内存资源来存储相关信息如连接状态和IO缓冲区等。 4、无法处理大量并发连接请求可能会导致连接的延迟和响应时间过长。 5、对于大数据传输阻塞IO可能会一次性读取所有数据并占用大量内存从而导致服务器崩溃或性能下降。 6、由于阻塞IO模型无法实时处理并发连接请求因此无法适应高并发、高吞吐量的应用场景。
三、使用场景 1、小规模的网络应用如小型HTTP服务器、FTP服务器等。 2、对并发连接数量要求不高的网络应用如内部OA系统、ERP系统等。 3、数据传输量较小的网络应用如即时聊天应用、邮件系统等。 4、对实时响应要求不高的网络应用如批处理任务、数据备份等。 5、对于资源受限的系统如嵌入式系统、移动设备等阻塞IO模型也可以用于网络应用。
四、模型框架通信流程 1、建立套接字。使用socket() 2、设置端口复用。使用setsockopt() 3、绑定自己的IP地址和端口号。使用bind() 4、设置监听。使用listen() 5、循环阻塞等待接收新的客户端连接。使用accept() 6、为连接上来的客户端创建一条线程。使用pthread_create() 7、关闭套接字。使用close()
五、相关函数API接口 这里TCP服务通信的API在本系列其他博客中已经有大量讲解这里省略忘记了朋友可以点击本文开头上面对应的链接查看。
六、案例 使用阻塞IO模型结合TCP协议完成服务器通信演示使用nc命令模拟客户端。 // 阻塞IO模型TCP服务器的案例#include stdio.h
#include stdio.h
#include stdlib.h
#include unistd.h
#include string.h
#include sys/types.h
#include sys/socket.h
#include netinet/in.h
#include netinet/ip.h
#include arpa/inet.h
#include pthread.h#define MAX_LISTEN 50 // 最大能处理的连接数
#define SERVER_IP 192.168.64.128 // 记得改为自己IP
#define SERVER_PORT 20000 // 不能超过65535也不要低于1000防止端口误用struct ClientInfo
{int fd;uint16_t port;char ip[20];
};// 线程的例程函数
void *recv_routinue(void *arg)
{int ret 0;char recv_msg[128] {0};struct ClientInfo client *((struct ClientInfo*)arg);pthread_detach(pthread_self()); // 设置强制分离while(1){memset(recv_msg, 0, sizeof(recv_msg));ret recv(client.fd, recv_msg, sizeof(recv_msg), 0);if(ret 0){printf([%s:%d] disconnect\n, client.ip, client.port);pthread_exit(0);}else if(ret 0){printf([%s:%d] send data: %s\n, client.ip, client.port, recv_msg);}}
}int main(int argc, char *argv[])
{// 1、建立套接字指定IPV4网络地址TCP协议int sockfd socket(AF_INET, SOCK_STREAM, 0);if(sockfd -1){perror(socket fail);return -1;}// 2、设置端口复用推荐int optval 1; // 这里设置为端口复用所以随便写一个值int ret setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, optval, sizeof(optval));if(ret -1){perror(setsockopt fail);close(sockfd);return -1;}// 3、绑定自己的IP地址和端口号不可以省略struct sockaddr_in server_addr {0};socklen_t addr_len sizeof(struct sockaddr);server_addr.sin_family AF_INET; // 指定协议为IPV4地址协议server_addr.sin_port htons(SERVER_PORT); // 端口号server_addr.sin_addr.s_addr inet_addr(SERVER_IP); // IP地址ret bind(sockfd, (struct sockaddr*)server_addr, addr_len);if(ret -1){perror(bind fail);close(sockfd);return -1;}// 4、设置监听ret listen(sockfd, MAX_LISTEN);if(ret -1){perror(listen fail);close(sockfd);return -1;}uint16_t port 0;char ip[20] {0};struct sockaddr_in client_addr {0};printf(wait client connect...\n);while(1){// 5、接受连接请求int new_client_fd accept(sockfd, (struct sockaddr*)client_addr, addr_len);if(new_client_fd -1){perror(accept fail);close(sockfd);return -1;}else{memset(ip, 0, sizeof(ip));strcpy(ip, inet_ntoa(client_addr.sin_addr));port ntohs(client_addr.sin_port);printf([%s:%d] connect\n, ip, port);struct ClientInfo client {0};client.fd new_client_fd;client.port port;strcpy(client.ip, ip);// 创建线程一个客户端对应一个线程pthread_t tid;pthread_create(tid, NULL, recv_routinue, (void*)client);}}// 7、关闭套接字close(sockfd);return 0;
} 七、总结 阻塞IO模型适用于系统资源有限小规模通信的场景无法适应高并发、高吞吐量的应用场景。通常做法是一个客户端对应一个线程这样极度消耗系统资源因此也无法处理大规模的客户端连接请求。