日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux网络编程——tcp并发服务器(I/O复用之select

發布時間:2023/11/30 linux 47 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux网络编程——tcp并发服务器(I/O复用之select 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

http://blog.csdn.net/lianghe_work/article/details/46519633

多線程、多進程相比,I/O復用最大的優勢是系統開銷小,系統不需要建立新的進程或者線程,也不必維護這些線程和進程。


代碼示例:

[csharp]?view plain?copy
  • #include?<stdio.h>???
  • #include?<unistd.h>??
  • #include?<stdlib.h>??
  • #include?<errno.h>??
  • #include?<string.h>??
  • #include?<sys/socket.h>??
  • #include?<sys/types.h>??
  • #include?<netinet/in.h>??
  • #include?<arpa/inet.h>??
  • #include?<sys/select.h>??
  • ?
  • #define?SERV_PORT?8080??
  • #define?LIST?20????????????????//服務器最大接受連接??
  • #define?MAX_FD?10??????????????//FD_SET支持描述符數量??
  • ??
  • ??
  • int?main(int?argc,?char?*argv[])??
  • {??
  • ????int?sockfd;??
  • ????int?err;??
  • ????int?i;??
  • ????int?connfd;??
  • ????int?fd_all[MAX_FD];?//保存所有描述符,用于select調用后,判斷哪個可讀??
  • ??????
  • ????//下面兩個備份原因是select調用后,會發生變化,再次調用select前,需要重新賦值??
  • ????fd_set?fd_read;????//FD_SET數據備份??
  • ????fd_set?fd_select;??//用于select??
  • ??
  • ????struct?timeval?timeout;?????????//超時時間備份??
  • ????struct?timeval?timeout_select;??//用于select??
  • ??????
  • ????struct?sockaddr_in?serv_addr;???//服務器地址??
  • ????struct?sockaddr_in?cli_addr;????//客戶端地址??
  • ????socklen_t?serv_len;??
  • ????socklen_t?cli_len;??
  • ??????
  • ????//超時時間設置??
  • ????timeout.tv_sec?=?10;??
  • ????timeout.tv_usec?=?0;??
  • ??????
  • ????//創建TCP套接字??
  • ????sockfd?=?socket(AF_INET,?SOCK_STREAM,?0);??
  • ????if(sockfd?<?0)??
  • ????{??
  • ????????perror("fail?to?socket");??
  • ????????exit(1);??
  • ????}??
  • ??????
  • ????//?配置本地地址??
  • ????memset(&serv_addr,?0,?sizeof(serv_addr));??
  • ????serv_addr.sin_family?=?AF_INET;?????????//?ipv4??
  • ????serv_addr.sin_port?=?htons(SERV_PORT);??//?端口,?8080??
  • ????serv_addr.sin_addr.s_addr?=?htonl(INADDR_ANY);?//?ip??
  • ??
  • ????serv_len?=?sizeof(serv_addr);??
  • ??????
  • ????//?綁定??
  • ????err?=?bind(sockfd,?(struct?sockaddr?*)&serv_addr,?serv_len);??
  • ????if(err?<?0)??
  • ????{??
  • ????????perror("fail?to?bind");??
  • ????????exit(1);??
  • ????}??
  • ??
  • ????//?監聽??
  • ????err?=?listen(sockfd,?LIST);??
  • ????if(err?<?0)??
  • ????{??
  • ????????perror("fail?to?listen");??
  • ????????exit(1);??
  • ????}??
  • ??????
  • ????//初始化fd_all數組??
  • ????memset(fd_all,?-1,?sizeof(fd_all));??
  • ??
  • ????fd_all[0]?=?sockfd;???//第一個為監聽套接字??
  • ??????
  • ????FD_ZERO(&fd_read);??//?清空??
  • ????FD_SET(sockfd,?&fd_read);??//將監聽套接字加入fd_read??
  • ??
  • ????int?maxfd?=?fd_all[0];??//監聽的最大套接字??
  • ??????
  • ????while(1){??
  • ??????
  • ????????//?每次都需要重新賦值,fd_select,timeout_select每次都會變??
  • ????????fd_select?=?fd_read;??
  • ????????timeout_select?=?timeout;??
  • ??????????
  • ????????//?檢測監聽套接字是否可讀,沒有可讀,此函數會阻塞??
  • ????????//?只要有客戶連接,或斷開連接,select()都會往下執行??
  • ????????err?=?select(maxfd+1,?&fd_select,?NULL,?NULL,?NULL);??
  • ????????//err?=?select(maxfd+1,?&fd_select,?NULL,?NULL,?(struct?timeval?*)&timeout_select);??
  • ????????if(err?<?0)??
  • ????????{??
  • ????????????????perror("fail?to?select");??
  • ????????????????exit(1);??
  • ????????}??
  • ??
  • ????????if(err?==?0){??
  • ????????????printf("timeout\n");??
  • ????????}??
  • ??????????
  • ????????//?檢測監聽套接字是否可讀??
  • ????????if(?FD_ISSET(sockfd,?&fd_select)?){//可讀,證明有新客戶端連接服務器??
  • ??????????????
  • ????????????cli_len?=?sizeof(cli_addr);??
  • ??????????????
  • ????????????//?取出已經完成的連接??
  • ????????????connfd?=?accept(sockfd,?(struct?sockaddr?*)&cli_addr,?&cli_len);??
  • ????????????if(connfd?<?0)??
  • ????????????{??
  • ????????????????perror("fail?to?accept");??
  • ????????????????exit(1);??
  • ????????????}??
  • ??????????????
  • ????????????//?打印客戶端的?ip?和端口??
  • ????????????char?cli_ip[INET_ADDRSTRLEN]?=?{0};??
  • ????????????inet_ntop(AF_INET,?&cli_addr.sin_addr,?cli_ip,?INET_ADDRSTRLEN);??
  • ????????????printf("----------------------------------------------\n");??
  • ????????????printf("client?ip=%s,port=%d\n",?cli_ip,ntohs(cli_addr.sin_port));??
  • ??????????????
  • ????????????//?將新連接套接字加入?fd_all?及?fd_read??
  • ????????????for(i=0;?i?<?MAX_FD;?i++){??
  • ????????????????if(fd_all[i]?!=?-1){??
  • ????????????????????continue;??
  • ????????????????}else{??
  • ????????????????????fd_all[i]?=?connfd;??
  • ????????????????????printf("client?fd_all[%d]?join\n",?i);??
  • ????????????????????break;??
  • ????????????????}??
  • ????????????}??
  • ??????????????
  • ????????????FD_SET(connfd,?&fd_read);??
  • ??????????????
  • ????????????if(maxfd?<?connfd)??
  • ????????????{??
  • ????????????????maxfd?=?connfd;??//更新maxfd??
  • ????????????}??
  • ??????????
  • ????????}??
  • ??????????
  • ????????//從1開始查看連接套接字是否可讀,因為上面已經處理過0(sockfd)??
  • ????????for(i=1;?i?<?maxfd;?i++){??
  • ????????????if(FD_ISSET(fd_all[i],?&fd_select)){??
  • ????????????????printf("fd_all[%d]?is?ok\n",?i);??
  • ??????????????????
  • ????????????????char?buf[1024]={0};??//讀寫緩沖區??
  • ????????????????int?num?=?read(fd_all[i],?buf,?1024);??
  • ????????????????if(num?>?0){??
  • ??
  • ????????????????????//收到?客戶端數據并打印??
  • ????????????????????printf("receive?buf?from?client?fd_all[%d]?is:?%s\n",?i,?buf);??
  • ??????????????????????
  • ????????????????????//回復客戶端??
  • ????????????????????num?=?write(fd_all[i],?buf,?num);??
  • ????????????????????if(num?<?0){??
  • ????????????????????????perror("fail?to?write?");??
  • ????????????????????????exit(1);??
  • ????????????????????}else{??
  • ????????????????????????//printf("send?reply\n");??
  • ????????????????????}??
  • ??????????????????????
  • ????????????????}??
  • ????????????????else?if(0?==?num){?//?客戶端斷開時??
  • ??????????????????????
  • ????????????????????//客戶端退出,關閉套接字,并從監聽集合清除??
  • ????????????????????printf("client:fd_all[%d]?exit\n",?i);??
  • ????????????????????FD_CLR(fd_all[i],?&fd_read);??
  • ????????????????????close(fd_all[i]);??
  • ????????????????????fd_all[i]?=?-1;??
  • ??????????????????????
  • ????????????????????continue;??
  • ????????????????}??
  • ??????????????????
  • ????????????}else?{??
  • ????????????????//printf("no?data\n");????????????????????
  • ????????????}??
  • ????????}??
  • ????}??
  • ??????
  • ????return?0;??
  • }??

  • 運行結果:


    總結

    以上是生活随笔為你收集整理的Linux网络编程——tcp并发服务器(I/O复用之select的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。