服務器之select

select

  1. select能監聽的文件描述符個數受限于FD_SETSIZE,一般為1024,單純改變進程打開的文件描述符個數并不能改變select監聽文件個數
  2. 解決1024以下客戶端時使用select是很合適的,但如果鏈接客戶端過多,select采用的是輪詢模型,會大大降低服務器響應效率,不應在select上投入更多精
#include <sys/select.h>
/* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);nfds:         監控的文件描述符集里最大文件描述符加1,因為此參數會告訴內核檢測前多少個文件描述符的狀態readfds:    監控有讀數據到達文件描述符集合,傳入傳出參數writefds:    監控寫數據到達文件描述符集合,傳入傳出參數exceptfds:    監控異常發生達文件描述符集合,如帶外數據到達異常,傳入傳出參數timeout:    定時阻塞監控時間,3種情況1.NULL,永遠等下去2.設置timeval,等待固定時間3.設置timeval里時間均為0,檢查描述字后立即返回,輪詢struct timeval {long tv_sec; /* seconds */long tv_usec; /* microseconds */};void FD_CLR(int fd, fd_set *set);     //把文件描述符集合里fd清0int FD_ISSET(int fd, fd_set *set);     //測試文件描述符集合里fd是否置1void FD_SET(int fd, fd_set *set);     //把文件描述符集合里fd位置1void FD_ZERO(fd_set *set);             //把文件描述符集合里所有位清0

server

/* server.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 6666int main(int argc, char *argv[])
{int i, maxi, maxfd, listenfd, connfd, sockfd;int nready, client[FD_SETSIZE];     /* FD_SETSIZE 默認為 1024 */ssize_t n;fd_set rset, allset;char buf[MAXLINE];char str[INET_ADDRSTRLEN];             /* #define INET_ADDRSTRLEN 16 */socklen_t cliaddr_len;struct sockaddr_in cliaddr, servaddr;listenfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));Listen(listenfd, 20);         /* 默認最大128 */maxfd = listenfd;             /* 初始化 */
maxi = -1;                    /* client[]的下標 */for (i = 0; i < FD_SETSIZE; i++)client[i] = -1;         /* 用-1初始化client[] */FD_ZERO(&allset);
FD_SET(listenfd, &allset); /* 構造select監控文件描述符集 */for ( ; ; ) {rset = allset;             /* 每次循環時都從新設置select監控信號集 */nready = select(maxfd+1, &rset, NULL, NULL, NULL);if (nready < 0)perr_exit("select error");if (FD_ISSET(listenfd, &rset)) { /* new client connection */cliaddr_len = sizeof(cliaddr);connfd = Accept(listenfd, (struct sockaddr *)&cliaddr, &cliaddr_len);printf("received from %s at PORT %d\n",inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),ntohs(cliaddr.sin_port));for (i = 0; i < FD_SETSIZE; i++) {if (client[i] < 0) {client[i] = connfd; /* 保存accept返回的文件描述符到client[]里 */break;}}/* 達到select能監控的文件個數上限 1024 */if (i == FD_SETSIZE) {fputs("too many clients\n", stderr);exit(1);}FD_SET(connfd, &allset);     /* 添加一個新的文件描述符到監控信號集里 */if (connfd > maxfd)maxfd = connfd;         /* select第一個參數需要 */if (i > maxi)maxi = i;                 /* 更新client[]最大下標值 */if (--nready == 0)continue;                 /* 如果沒有更多的就緒文件描述符繼續回到上面select阻塞監聽,負責處理未處理完的就緒文件描述符 */}for (i = 0; i <= maxi; i++) {     /* 檢測哪個clients 有數據就緒 */if ( (sockfd = client[i]) < 0)continue;if (FD_ISSET(sockfd, &rset)) {if ( (n = Read(sockfd, buf, MAXLINE)) == 0) {Close(sockfd);        /* 當client關閉鏈接時,服務器端也關閉對應鏈接 */FD_CLR(sockfd, &allset); /* 解除select監控此文件描述符 */client[i] = -1;} else {int j;for (j = 0; j < n; j++)buf[j] = toupper(buf[j]);Write(sockfd, buf, n);}if (--nready == 0)break;}}}close(listenfd);return 0;
}

client

/* client.c */
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <netinet/in.h>
#include "wrap.h"#define MAXLINE 80
#define SERV_PORT 6666int main(int argc, char *argv[])
{struct sockaddr_in servaddr;char buf[MAXLINE];int sockfd, n;sockfd = Socket(AF_INET, SOCK_STREAM, 0);bzero(&servaddr, sizeof(servaddr));servaddr.sin_family = AF_INET;inet_pton(AF_INET, "127.0.0.1", &servaddr.sin_addr);servaddr.sin_port = htons(SERV_PORT);Connect(sockfd, (struct sockaddr *)&servaddr, sizeof(servaddr));while (fgets(buf, MAXLINE, stdin) != NULL) {Write(sockfd, buf, strlen(buf));n = Read(sockfd, buf, MAXLINE);if (n == 0)printf("the other side has been closed.\n");elseWrite(STDOUT_FILENO, buf, n);}Close(sockfd);return 0;
}

包含了”wrap.c”和“wrap.h”文件在上兩篇博客中,這里就不重復給出了

轉載于:https://www.cnblogs.com/wanghao-boke/p/11409496.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/384849.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/384849.shtml
英文地址,請注明出處:http://en.pswp.cn/news/384849.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

服務器之poll

poll服務器方法采用將監聽端口用數組存放起來&#xff0c;這樣就不需要輪詢的監聽整個文件描述符了 #include <poll.h> int poll(struct pollfd *fds, nfds_t nfds, int timeout);struct pollfd {int fd; /* 文件描述符 */short events; /* 監控的事件 */short revents; …

Mysql數據庫簡單使用(二)

Mysql導入.sql文件 進入數據庫&#xff08;要導入的數據庫&#xff09;數據庫中有要導入.sql文件名的數據庫&#xff0c;沒有則新建。source 路徑文件名souce /home/robot/csql.sql 數據庫文件.sql文件放在/home/robot目錄下 按照時間刪除數據庫數據 DELETE FROM 表名 WHERE 時…

Python3集合

集合&#xff08;set&#xff09;是一個無序的不重復元素序列。 可以使用大括號{ } 或set&#xff08;&#xff09;函數來創建集合&#xff0c;注意&#xff1a;創建一個空集合必須用set(),{ }是用來創建一個空字典的。 創建格式&#xff1a; param {value01,value02,…} set(…

Python3條件判斷

if語句&#xff1a; Python中if語句的一般形式如下&#xff1a; if condition_1:statement_block_1 elif condition_2:statement_block_2 else:statement_block_3 if語句關鍵詞&#xff1a; if – elif – else 注意&#xff1a; 每個條件后面要使用冒號:使用縮進來劃分語句塊&…

Python3循環

Python中while語句的一般形式&#xff1a; while 判斷條件: 語句 同樣需要注意冒號和縮進&#xff0c;另外在Python中沒有do…while循環 下面的實例計算1到100總和 ##calc.py n 100sum 0 counter 1 while counter < n:sum sum countercounter 1print("total from…

Python3迭代器和生成器

迭代器 迭代是Python最強大的功能之一&#xff0c;是訪問元素集合的一種方法。 迭代器是一個可以記住遍歷的位置的對象。 迭代器對象從集合的第一個元素開始訪問&#xff0c;直到所有的元素被訪問完結束&#xff0c;迭代器只能向前不會后退。 迭代器有兩個基本方法&#xff0c;…

Pythton3實例

計算1-100之和 #add.py n 0 sum 0 for n in range(0,101):sum n print(sum) 實現99乘法法則 #mul.py i 1 while i < 9:j 1while j < i:mut j*iprint("%d * %d %d"%(j,i,mut),end" ")j 1print(" ")i 1 運算結果: robotubuntu:~/wa…

Python3函數

函數是組織好的&#xff0c;可重復使用的&#xff0c;用來實現單一&#xff0c;或相關功能的代碼段。 函數能提高應用的模塊性&#xff0c;和代碼的重復使用率。 定義一個函數 可以定義一個由自己想要功能的函數&#xff0c;以下是簡單規則&#xff1a; l 函數代碼塊是以def關…

epoll函數

epoll是Linux下多路復用IO接口select/poll的增強版本&#xff0c;它能顯著提高程序在大量并發連接中只有少量活躍的情況下的系統CPU利用率&#xff0c;因為它會復用文件描述符集合來傳遞結果而不用迫使開發者每次等待事件之前都必須重新準備要被偵聽的文件描述符集合&#xff0…

epoll事件模型

事件模型 EPOLL事件有兩種模型&#xff1a; Edge Triggered (ET) 邊緣觸發只有數據到來才觸發&#xff0c;不管緩存區中是否還有數據。 Level Triggered (LT) 水平觸發只要有數據都會觸發。 思考如下步驟&#xff1a; 假定我們已經把一個用來從管道中讀取數據的文件描述符(RFD)…

epoll反應堆模型代碼

libevent函數庫核心思想 /*** epoll_loop.c ***/ #include<stdio.h> #include<sys/epoll.h> #include<sys/socket.h> #include<arpa/inet.h> #include<fcntl.h> #include<unistd.h> #include<errno.h> #include<string.h> #in…

UDP廣播

廣播是在局域網之間的一對多的通信方式&#xff0c;使用的udp協議 /*** client.c ***/ #include <stdio.h> #include <unistd.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h>#define SERVER_PORT 8000 #define MAXLINE…

UDP組播

多播(組播) 組播組可以是永久的也可以是臨時的。組播組地址中&#xff0c;有一部分由官方分配的&#xff0c;稱為永久組播組。永久組播組保持不變的是它的ip地址&#xff0c;組中的成員構成可以發生變化。永久組播組中成員的數量都可以是任意的&#xff0c;甚至可以為零。那些沒…

Python3數據結構

列表&#xff1a; Python列表是可變的&#xff0c;這是它區別于字符串數組和元組的最重要的特點。列表可以修改&#xff0c;而字符串和元組不能。 以下是Python中列表的描述方法&#xff1a; 方法 描述 list.append(x) 將元素添加到列表結尾 list.extend(L) 通過添加指定列…

sed、awk工具

ed sed意為流編輯器&#xff08;Stream Editor&#xff09;&#xff0c;在Shell腳本和Makefile中作為過濾器使用非常普遍&#xff0c;也就是把前一個程序的輸出引入sed的輸入&#xff0c;經過一系列編輯命令轉換為另一種格式輸出。sed和vi都源于早期UNIX的ed工具&#xff0c;所…

C語言正則表達式

POSIX規定了正則表達式的C語言庫函數&#xff0c;詳見regex(3)。我們已經學習了很多C語言庫函數的用法&#xff0c;讀者應該具備自己看懂man手冊的能力了。本章介紹了正則表達式在grep、sed、awk中的用法&#xff0c;學習要能夠舉一反三&#xff0c;請讀者根據regex(3)自己總結…

makefile通用版本

實際當中程序文件比較大&#xff0c;這時候對文件進行分類&#xff0c;分為頭文件、源文件、目標文件、可執行文件。也就是說通常將文件按照文件類型放在不同的目錄當中&#xff0c;這個時候的Makefile需要統一管理這些文件&#xff0c;將生產的目標文件放在目標目錄下&#xf…

Python3OS文件/方法

Python3OS文件/方法 os模塊提供了非常豐富的方法用來處理文件和目錄。 方法 描述 os.access(path,mode) 檢驗權限模式 os.chdir(path) 改變當前工作目錄 os.chflags(path,flags) 設置路徑的標記為數字標記 os.chmod(path,mode) 更改權限 os.chown(path,uid,gid) 更改…

Python3文件

open()方法 Python open()方法永于打開一個文件&#xff0c;并返回文件對象&#xff0c;并對文件進行處理過程中都需要用到這個方法&#xff0c;如果該文件無法被打開&#xff0c;則拋出OSError 注意&#xff1a;使用open()方法一定要保證關閉文件對象&#xff0c;即調用close(…

Python3輸入輸出

Python兩種輸出值的方式&#xff0c;表達式語句和print()函數。 第三種方式是使用文件對象的write()方法&#xff0c;標準輸出文件可以用sys.stdout的引用。 如果你希望輸出的形式更加多樣&#xff0c;可以使用str.fomat()函數來格式化輸出值。 如果你希望將輸出的值轉化成字符…