select 版 高并发服务器
生活随笔
收集整理的這篇文章主要介紹了
select 版 高并发服务器
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <ctype.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/select.h>
int main()
{// 1 創建套接字int lfd = socket(AF_INET, SOCK_STREAM, 0);// 2 綁定// 2.1 復用端口int opt = 1;setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));// 2.2 設置IP和端口的結構體struct sockaddr_in server_addr;bzero(&server_addr, sizeof(server_addr)); // 清空結構體server_addr.sin_family = AF_INET;server_addr.sin_port = htons(8888);server_addr.sin_addr.s_addr = htonl(INADDR_ANY);// 2.3 綁定bind(lfd, (struct sockaddr*)&server_addr, sizeof(server_addr));// 3 設置同時監聽上限listen(lfd, 128);// 4 自定義的文件描述符數組,需要監聽的文件描述符就放進client數組,用于select后遍歷判斷事件int client[FD_SETSIZE]; // FD_SETSIZE = 1024int i; // 循環因子for(i = 0; i< FD_SETSIZE; i++)client[i] = -1; // 將文件描述符數組元素都初始化為-1,代表各個位置可用// 5 準備select集合fd_set set, orgset; // orgset是原始集合,set用于保存傳出集合FD_ZERO(&orgset);FD_SET(lfd, &orgset); // 在原始集合中監聽lfd,準備select參2// 6 監聽讀事件int nfds = lfd; // 記錄最大文件描述符編號,準備select參1struct sockaddr_in client_addr;socklen_t client_len = sizeof(client_addr); // 用于接收客戶端信息char buf[BUFSIZ] = {0}; // 讀寫緩存區while(1){set = orgset; // select中參2是傳入傳出屬性,因為不希望改變原始監聽集合orgset,所以使用setint nready = select(nfds+1, &set, NULL, NULL, NULL);if(nready < 0){perror("select err");exit(1);}// 6.1 如果是新連接if(FD_ISSET(lfd, &set)){int cfd = accept(lfd, (struct sockaddr*)&client_addr, &client_len); // 獲得連接描述符char ip[16] = {0};printf("conn from %s at %d\n",inet_ntop(AF_INET, &client_addr.sin_addr.s_addr, ip, sizeof(ip)),ntohs(client_addr.sin_port)); // 打印客戶端信息for(i = 0; i< FD_SETSIZE; i++) // 更新遍歷client數組,將cfd添加進去{if(client[i] < 0){client[i] = cfd; // 給到數組中可用的最小位置break; // 退出for循環}}if(i == FD_SETSIZE) // 如果數組中沒有位置{printf("client too many\n");break; // 退出while循環,執行returm}FD_SET(cfd, &orgset); // 監聽cfd , 更新select參數2if(cfd > nfds) // 增加判斷條件是因為,一旦nfds前有可用位置,nfds不需要更新nfds = cfd; // 更新select參數1if(--nready == 0)continue; // 就一個事件,而且是新連接,沒必要往下執行了}// 6.2 ,如果不是以上情況,那就是普通讀事件for(i = 0; i < FD_SETSIZE ; i++) // 遍歷client數組,看哪個文件描述符變化{if(client[i] < 0)continue; // 如果是-1,代表空位,沒必要向下走了,繼續for循環if(FD_ISSET(client[i], &set)) //判斷傳出set中是否有client[i],如果有,代表有讀事件發生{int n = read(client[i], buf, sizeof(buf));if(n < 0){perror("read err");close(client[i]); // 該文件描述符無用了,關閉FD_CLR(client[i],&orgset); // 更新select參數2,注意:nfds不能動client[i] = -1; // 將client數組元素置為初始態}if(n == 0){printf("client[%d] closed\n", i);close(client[i]);FD_CLR(client[i],&orgset);client[i] = -1;}if(n > 0){write(client[i], buf, n);write(STDOUT_FILENO, buf, n);}if(--nready == 0)break; // 為了防止循環1024}}}close(lfd);return 0;
}
總結
以上是生活随笔為你收集整理的select 版 高并发服务器的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 多路 IO 转接 :select 函数
- 下一篇: 多路 IO 转接 :poll 函数