营销网站主题有哪些内容,怎么通过互联网做一个服务的网站,wordpress回收站+恢复,二级域名对网站帮助一、什么是多路复用模型 服务器的多路复用模型指的是利用操作系统提供的多路复用机制#xff0c;同时处理多个客户端连接请求的能力。在服务器端#xff0c;常见的多路复用技术包括select、poll和epoll等。这些技术允许服务器同时监听多个客户端连接请求#xff0c;当有请求…一、什么是多路复用模型 服务器的多路复用模型指的是利用操作系统提供的多路复用机制同时处理多个客户端连接请求的能力。在服务器端常见的多路复用技术包括select、poll和epoll等。这些技术允许服务器同时监听多个客户端连接请求当有请求到达时会通知服务器进行处理。通过使用多路复用技术可以避免一个线程只处理一个客户端连接的情况提高服务器的并发性能和响应速度。在实际应用中多路复用技术被广泛地应用于Web服务器、游戏服务器、消息队列等领域。 注下面案例演示采用select结合TCP协议一般不结合UDP协议使用案例也演示了select结合UDP协议。
二、特性 1、支持大量并发连接 多路复用技术可以同时监听多个客户端连接请求避免了一个线程只处理一个客户端连接的情况从而可以支持更多的并发连接。 2、减少系统开销 采用多路复用技术可以减少系统开销因为不需要为每个连接开启一个线程或进程避免了系统资源浪费。 3、提高响应速度 采用多路复用技术可以提高服务器的响应速度因为多个连接可以同时处理避免了连接排队的情况。 4、更好的可扩展性 多路复用技术可以更好的支持服务器的可扩展性因为它可以动态地管理和调度连接方便服务器的扩展和升级。
三、使用场景 1、高并发的Web服务器 对于高并发的Web服务器采用多路复用技术可以同时监听多个客户端连接请求避免了一个线程只处理一个客户端连接的情况从而可以支持更多的并发连接。 2、实时通信服务器 对于实时通信服务器采用多路复用技术可以同时监听多个客户端连接请求可以处理多种类型的通信包括即时通讯、实时游戏等。 3、TCP/IP服务器 对于TCP/IP服务器采用多路复用技术可以提高服务器的性能和可靠性因为多个连接可以同时处理避免了连接排队的情况。 4、网络监控工具 对于网络监控工具采用多路复用技术可以同时处理多个客户端的请求并对网络数据进行监控和分析。
四、模型框架通信流程 1、建立套接字。使用socket() 2、设置端口复用。使用setsockopt() 3、绑定自己的IP地址和端口号。使用bind() 4、设置监听。使用listen() 5、多路复用准备工作。使用文件描述符集合操作 6、循环监听开始多路复用。使用select() 7、处理客户端连接或者数据接收。使用accept()或者recv() 8、关闭套接字。使用close()
五、相关函数API接口 TCP通信流程常规的API那些在本系列的TCP协议里有大量展示这里省略详情可以点击本文开头的链接查看 1、多路复用select // 多路复用select
int select(int nfds, fd_set *readfds,fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);// 接口说明返回值成功返回readfdswritefdsexceptfds中状态发生变化的文件描述符数量失败返回-1参数nfds通常填写三个集合中最大的文件描述符值1让内核检测多少个文件描述符的状态参数readfds监控有读数据到达文件描述符集合参数writefds监控有写数据到达文件描述符集合参数exceptfds监控有异常发生到达文件描述符集合参数timeout设置阻塞等待时间三种情况1、设置为NULL一直阻塞等待2、设置timevl等待固定的时间3、设置timeval里时间为0在检测完描述符后立即返回 2、集合操作 // 把文件描述符集合里fd清0
void FD_CLR(int fd, fd_set *set);// 把文件描述符集合里fd位置1
void FD_SET(int fd, fd_set *set);// 把文件描述符集合里所有位清0
void FD_ZERO(fd_set *set);// 测试文件描述符集合里fd是否置1
int FD_ISSET(int fd, fd_set *set); 六、案例 1、 采用select函数完成多路复用TCP服务器的通信演示用nc命令来模拟客户端 // 多路复用TCP服务器的案例#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#define MAX_LISTEN FD_SETSIZE // 最大能处理的连接数, 1024
#define SERVER_IP 192.168.64.128 // 记得改为自己IP
#define SERVER_PORT 20000 // 不能超过65535也不要低于1000防止端口误用int main(int argc, char *argv[])
{// 1、建立套接字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 htonl(INADDR_ANY);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;}// 5、多路复用的准备工作fd_set client_set, active_set;// (1)、清空活跃的文件描述符集合FD_ZERO(active_set);// (2)、把服务器的套接字文件描述符加入到活跃的文件描述符集合中FD_SET(sockfd, active_set);// (3)、初始化活跃集合中最大的文件描述符int maxfd sockfd;// (4)、初始化能接受的活跃客户端套接字数组int client[MAX_LISTEN];for(int i 0; i MAX_LISTEN; i){client[i] -1; // 空的置为-1活跃的置为对应的文件描述符}uint16_t port 0; // 新的客户端端口号char ip[20] {0}; // 新的客户端IPstruct sockaddr_in client_addr; // 新的客户端地址char recv_msg[128] {0}; // 用来接收客户端的数据printf(wait client...\n);while(1){client_set active_set; // 先备份活跃的集合// 6、多路复用同时监听多个文件描述符状态阻塞等待int num select(maxfd1, client_set, NULL, NULL, NULL);if(num -1){perror(select fail);close(sockfd);return -1;}// 如果监听文件描述符发生变化说明一定有新的客户端连接上来if(FD_ISSET(sockfd, client_set)){int new_client_fd accept(sockfd, (struct sockaddr*)client_addr, addr_len);if(new_client_fd -1){perror(accept fail);continue;}else{// 打印连接的客服端IP和端口号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);// 把新的客户端套接字加入到活跃的集合中FD_SET(new_client_fd, active_set);// 更新最大活跃文件描述符if(maxfd new_client_fd){maxfd new_client_fd;}// 把新的套接字加入到空的活跃客户端套接字数组for(int i 0; i MAX_LISTEN; i){if(client[i] -1){client[i] new_client_fd;break;}}// 如果只有服务器的套接字发生变化新的套接字没有发送数据// 那就继续监听否则需要打印套接字的信息if(--num 0){continue;}}}// 如果客服端发送数据过来for(int i 0; i MAX_LISTEN; i){if(client[i] -1){continue;}// 如果活跃的客户端有发送数据注意这里要采用client_set而不是active_set否则会读取不了数据if(FD_ISSET(client[i], client_set)){// 接收数据memset(recv_msg, 0, sizeof(recv_msg));ret recv(client[i], recv_msg, sizeof(recv_msg), 0);memset(ip, 0, sizeof(ip));strcpy(ip, inet_ntoa(client_addr.sin_addr));port ntohs(client_addr.sin_port);if(ret 0){printf([%s:%d] disconnect\n, ip, port);FD_CLR(client[i], active_set); // 清空对应活跃集合的套接字client[i] -1; // 清空客户端套接字数组// 需要重新更新活跃集合中最大的文件描述符maxfd sockfd;for(int i 0; i MAX_LISTEN; i){if(client[i] ! -1 maxfd client[i]){maxfd client[i];}}}else{printf([%s:%d] send data: %s\n, ip, port, recv_msg);}// 如果所有发生变化的套接字都已经处理完成if(--num 0){break;}}}}close(sockfd);return 0;
} 2、 采用select函数完成多路复用UDP服务器的通信演示用nc命令来模拟客户端 // 多路复用TCP服务器的案例#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 errno.h#define MAX_LISTEN FD_SETSIZE // 最大能处理的连接数, 1024
#define SERVER_IP 192.168.64.128 // 记得改为自己IP
#define SERVER_PORT 20000 // 不能超过65535也不要低于1000防止端口误用int main(int argc, char *argv[])
{// 1、建立套接字int sockfd socket(AF_INET, SOCK_DGRAM, 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 htonl(INADDR_ANY);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、多路复用的准备工作fd_set client_set, active_set;// (1)、清空活跃的文件描述符集合FD_ZERO(active_set);// (2)、把服务器的套接字文件描述符加入到活跃的文件描述符集合中FD_SET(sockfd, active_set);// (3)、初始化活跃集合中最大的文件描述符int maxfd MAX_LISTEN;// (4)、初始化能接受的活跃客户端套接字数组int client[MAX_LISTEN];for(int i 0; i MAX_LISTEN; i){client[i] -1; // 空的置为-1活跃的置为对应的文件描述符}uint16_t port 0; // 新的客户端端口号char ip[20] {0}; // 新的客户端IPstruct sockaddr_in client_addr; // 新的客户端地址char recv_msg[128] {0}; // 用来接收客户端的数据printf(wait client...\n);while(1){client_set active_set; // 先备份活跃的集合// 5、多路复用同时监听多个文件描述符状态阻塞等待int num select(maxfd1, client_set, NULL, NULL, NULL);if(num -1){perror(select fail);close(sockfd);return -1;}else{// 接收数据memset(recv_msg, 0, sizeof(recv_msg));ret recvfrom(sockfd, recv_msg, sizeof(recv_msg), 0, (struct sockaddr*)client_addr, addr_len);memset(ip, 0, sizeof(ip));strcpy(ip, inet_ntoa(client_addr.sin_addr));port ntohs(client_addr.sin_port);printf([%s:%d] send data: %s\n, ip, port, recv_msg);}}close(sockfd);return 0;
} 注TCP和UDP的代码有所不同多路复用监听方式有所不同。
七、总结 多路复用适用于处理连接的客户端的数量小于1024的场景当然你可以改让其超过1024限制这里不做讨论。多路复用模型TCP服务器跟简单的TCP服务器通信流程很像就是在接收客户端时要采用select要进行操作。一般情况下不采用多路复用select结合UDP协议使用但是不代表不行案例给出了演示。