I/O多路複用伺服器程式設計
一、實驗目的
理解I/O多路複用技術的原理。
學會編寫基本的單執行緒併發伺服器程式和客戶程式。
二、實驗平臺
ubuntu-8.04作業系統
三、實驗內容
採用I/O多路複用技術實現單執行緒併發伺服器,完成使用一個執行緒處理併發客戶請求的功能。
四、實驗原理
除了可以採用多程序和多執行緒方法實現併發伺服器之外,還可以採用I/O多路複用技術。通過該技術,系統核心緩衝I/O資料,當某個I/O準備好後,系統通知應用程式該I/O可讀或可寫,這樣應用程式可以馬上完成相應的I/O操作,而不需要等待系統完成相應I/O操作,從而應用程式不必因等待I/O操作而阻塞。
與多程序和多執行緒技術相比,I/O多路複用技術的最大優勢是系統開銷小,系統不必建立程序
對於I/O複用典型的應用如下:
(1)當客戶處理多個描述字時(一般是互動式輸入和網路套介面),必須使用I/O複用。
(2)當一個客戶同時處理多個套介面時,而這種情況是可能的,但很少出現。
(3)如果一個TCP伺服器既要處理監聽套介面,又要處理已連線套介面,一般也要用到I/O複用。
(4)如果一個伺服器即要處理TCP,又要處理UDP,一般要使用I/O複用。
(5)如果一個伺服器要處理多個服務或多個協議,一般要使用I/O複用。
I/O複用呼叫select()或poll()函式,並在該函式上阻塞,等待資料報套介面可讀;當select()返回可讀條件時,呼叫
圖8.1 I/O多路複用工作過程
select()函式:
select()函式允許程序指示核心等待多個事件中的任意一個發生,並僅在一個或多個事件發生或經過指定的時間時才喚醒程序。這個函式的形式如下:
------------------------------------------------------------------- #include<sys/time.h> intselect(intmaxfdp1,fd_set*readset,fd_set*writeset, 返回:返回值表示所有描述字集中已準備好的描述字個數。如定時到,則返回0;若出錯,則返回-1。 ------------------------------------------------------------------- |
在上面的引數中可以看到一個timeval結構,這個結構可以提供秒數和毫秒數成員,形式如下:
structtimeval
{
long tv_sec; /second*/
long tv_usec; /*microsecond*/
}
這個timeval結構有以下3種可能:
(1)永遠等待下去:僅在有一個描述字準備好I/O時才返回,因此可以將引數timeout設定為空指標。
(2)等待固定時間:在有一個描述字準備好I/O時返回,但不超過由timeout引數所指timeval結構中指定的秒數和微秒數。
(3)根本不用等待:檢查描述字後立即返回,這稱為輪詢(polling)。
在前兩種情況的等待中,如果程序捕獲了一個訊號並從訊號處理程式返回,那麼等待一般被中斷。
引數readset、writeset和execeptset指定讓核心測試讀、寫、異常條件的描述字。如果我們對它們不感興趣,可將其設為空指標。
select()函式使用描述字集為引數readset(writeset或exceptset)指定多個描述字,描述字集是一個整數陣列,每個數中的每一個對應於一個描述字,例如32位整數,則陣列的第一個元素對應於0~31描述字,第二個元素對應於32~63描述字等。
引數readset、writeset、exceptset為值—結果引數,呼叫select時,指定我們所關心的描述字,返回時結果指示那些描述字已準備好。
引數maxfdp1指定被測試的描述字的個數,它是被測試的最大描述字加1。如要測試1,2,4描述字,則必須測試0,1,2,3,4共5個描述字。
採用select()函式實現I/O多路複用的基本步驟如下:
(1)清空描述符集合;
(2)建立需要監視的描述符與描述符集合的聯絡;
(3)呼叫select()函式;
(4)檢查所有需要監視的描述符,利用FD_ISSET巨集判斷是否已經準備好;
(5)對已經準備好的描述符進行I/O操作。
五、實驗步驟
1、登陸進入ubuntu作業系統,新建一個檔案,命名為io.c。
2、在io.c中編寫相應程式碼並儲存,作為伺服器端程式。客戶端程式程式碼同上次的mproc_client.c一致,部落格地址:http://blog.csdn.net/yueguanghaidao/article/details/7060350
3、開啟一個“終端”,執行命令進入io.c和mproc_client.c所在目錄。
4、執行命令g++ –oioio.c生成可執行檔案io。
5、執行命令./io,執行伺服器端。
6、開啟第2個“終端”,執行命令進入io.c和mproc_client.c所在目錄。
7、執行命令./mproc_client127.0.0.1,模擬客戶1。
8、開啟第3個“終端”,執行命令進入io.c和mproc_client.c所在目錄。
9、執行命令./mproc_client127.0.0.1,模擬客戶2。
10、程式執行結果如下:
伺服器端:
客戶1:
客戶2:
11、在客戶端按下Ctrl+D,關閉客戶連線。
12、認真分析原始碼,體會單執行緒併發伺服器程式和客戶程式的編寫。
六、參考程式(io.c)
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <unistd.h>
- #include<sys/types.h>
- #include<sys/socket.h>
- #include<netinet/in.h>
- #include<arpa/inet.h>
- #include<sys/time.h>
- #define PORT 1234
- #define BACKLOG 5
- #define MAXDATASIZE 1000
- typedefstruct {
- int fd;
- char *name;
- struct sockaddr_in addr;
- char *data;
- }CLIENT;
- void process_cli(CLIENT *client, char* recvbuf, int len);
- void savedata(char*recvbuf, int len, char* data);
- main()
- {
- int i, maxi,maxfd,sockfd;
- int nready;
- ssize_t n;
- fd_set rset, allset;
- int listenfd,connectfd;
- struct sockaddr_in server;
- CLIENT client[FD_SETSIZE];
- char recvbuf[MAXDATASIZE];
- socklen_t sin_size;
- if ((listenfd =socket(AF_INET, SOCK_STREAM, 0)) == -1) {
- perror("Creatingsocket failed.");
- exit(1);
- }
- int opt =SO_REUSEADDR;
- setsockopt(listenfd,SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
- bzero(&server,sizeof(server));
- server.sin_family=AF_INET;
- server.sin_port=htons(PORT);
- server.sin_addr.s_addr= htonl (INADDR_ANY);
- if (bind(listenfd,(struct sockaddr *)&server, sizeof(struct sockaddr)) == -1) {
- perror("Bind()error.");
- exit(1);
- }
- if(listen(listenfd,BACKLOG)== -1){
- perror("listen()error\n");
- exit(1);
- }
- sin_size=sizeof(struct sockaddr_in);
- maxfd = listenfd;
- maxi = -1;
- for (i = 0; i <FD_SETSIZE; i++) {
- client[i].fd =-1;
- }
- FD_ZERO(&allset);
- FD_SET(listenfd,&allset);
- while(1)
- {
- struct sockaddr_in addr;
- rset = allset;
- nready =select(maxfd+1, &rset, NULL, NULL, NULL);
- if(FD_ISSET(listenfd, &rset)) {
- if ((connectfd =accept(listenfd,(struct sockaddr *)&addr,&sin_size))==-1) {
- perror("accept() error\n");
- continue;
- }
- for (i = 0; i <FD_SETSIZE; i++)
- if(client[i].fd < 0) {
- client[i].fd = connectfd;
- client[i].name = newchar[MAXDATASIZE];
- client[i].addr = addr;
- client[i].data = newchar[MAXDATASIZE];
- client[i].name[0] = '\0';
- client[i].data[0] = '\0';
- printf("You got a connection from %s. ",inet_ntoa(client[i].addr.sin_addr) );
- break;
- }
- if (i ==FD_SETSIZE) printf("too many clients\n");
- FD_SET(connectfd, &allset);
- if (connectfd> maxfd) maxfd = connectfd;
- if (i >maxi) maxi = i;
- if (--nready<= 0) continue;
- }
- for (i = 0; i <=maxi; i++) {
- if ( (sockfd= client[i].fd) < 0) continue;
- if(FD_ISSET(sockfd, &rset)) {
- if ( (n =recv(sockfd, recvbuf, MAXDATASIZE,0)) == 0) {
- close(sockfd);
- printf("Client( %s ) closed connection. User's data:%s\n",client[i].name,client[i].data);
- FD_CLR(sockfd, &allset);
- client[i].fd = -1;
- delete client[i].name;
- delete client[i].data;
- }
- else
- process_cli(&client[i], recvbuf, n);
- if(--nready <= 0) break;
- }
- }
- }
- close(listenfd);
- }
- void process_cli(CLIENT *client, char* recvbuf, int len)
- {
- char sendbuf[MAXDATASIZE];
- recvbuf[len-1] ='\0';
- if(strlen(client->name) == 0) {
- memcpy(client->name,recvbuf, len);
- printf("Client'sname is %s.\n",client->name);
- return;
- }
- printf("Receivedclient( %s ) message: %s\n",client->name, recvbuf);
- savedata(recvbuf,len,client->data);
- for (int i1 = 0; i1< len - 1; i1++) {
- sendbuf[i1] =recvbuf[len - i1 -2];
- }
- sendbuf[len - 1] ='\0';
- send(client->fd,sendbuf,strlen(sendbuf),0);
- }
- void savedata(char *recvbuf, int len, char *data)
- {
- int start =strlen(data);
- for (int i = 0; i <len; i++) {
- data[start + i]= recvbuf[i];
- }
- }
相關推薦
I/O多路複用伺服器程式設計
一、實驗目的 理解I/O多路複用技術的原理。 學會編寫基本的單執行緒併發伺服器程式和客戶程式。 二、實驗平臺 ubuntu-8.04作業系統 三、實驗內容 採用I/O多路複用技術實現單執行緒併發伺服器,完成使用一個執行緒處理併發客戶請求的功能。 四、實驗原理 除了可以採用多
網路程式設計(4)select函式實現I/O多路複用伺服器
我按理解整了個基於select模式的單程序多路複用併發伺服器,並寫了個簡單的測試程式測了下,雖然離實用還差得遠,但用來練習select夠用了。 至於如何實現的細節,程式碼註釋算比較清楚,就不多弄了。 一。伺服器部份 單程序併發伺服器程式碼: /*********
嵌入式Linux網路程式設計,I/O多路複用,epoll()示例,epoll()客戶端,epoll()伺服器,單鏈表
文章目錄 1,I/O多路複用 epoll()示例 1.1,epoll()---net.h 1.2,epoll()---client.c 1.3,epoll()---sever.c 1.4,epoll()---linklist.h
嵌入式Linux網路程式設計,I/O多路複用,poll()示例,poll()客戶端,poll()伺服器,單鏈表
文章目錄 1,IO複用poll()示例 1.1,poll()---net.h 1.2,poll()---client.c 1.3,poll()---sever.c 1.4,poll()---linklist.h 1.5,p
嵌入式Linux網路程式設計,I/O多路複用,select()示例,select()客戶端,select()伺服器,單鏈表
文章目錄 1,IO複用select()示例 1.1 select()---net.h 1.2 select()---client.c 1.3 select()---sever.c 1.4 select()---linklist.h
Linux網路程式設計---I/O多路複用之select
1.I/O多路複用(IO multiplexing) 我們之前講了I/O多路複用和其他I/O的區別,在這裡,我們再具體討論下I/O多路複用是怎麼工作? I/O 多路複用技術就是為了解決程序或執行緒阻塞到某個 I/O 系統呼叫而出現的技術,使程序不阻塞於某個特定的 I/O 系統呼叫。
嵌入式Linux網路程式設計,I/O多路複用,阻塞I/O模式,非阻塞I/O模式fcntl()/ioctl(),多路複用I/O select()/pselect()/poll(),訊號驅動I/O
文章目錄 1,I/O模型 2,阻塞I/O 模式 2.1,讀阻塞(以read函式為例) 2.2,寫阻塞 3,非阻塞模式I/O 3.1,非阻塞模式的實現(fcntl()函式、ioctl() 函式)
UNIX網路程式設計-I/O多路複用
目錄 Unix下可用的5種I/O模型 阻塞式I/O模型 非阻塞式I/O模型 I/O複用模型 訊號驅動式I/O模型 非同步I/O模型 各種I/O模型的比較 參考 Unix下可用的5種I/O模型 阻塞式I/O 非阻塞式I/O
Socket網路程式設計_之I/O多路複用
1. IO多路複用: 每一次網路通訊都是一個Socket的I/O流,對於伺服器而言,有兩種方法 1.傳統的多程序併發模型(每進來一個新的I/O流會分配一個新的程序管理。) 2.方法二就是I/O的多路複用
Linux網路程式設計---I/O多路複用之epoll
/* TCP伺服器 用法:./server port */ #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <string
java併發程式設計之IO基礎入門之I/O多路複用技術
在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用多執行緒或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。與傳統的多執行緒/多程序模型比,
Java網路程式設計與NIO詳解2:JAVA NIO 一步步構建I/O多路複用的請求模型
微信公眾號【黃小斜】作者是螞蟻金服 JAVA 工程師,專注於 JAVA 後端技術棧:SpringBoot、SSM全家桶、MySQL、分散式、中介軟體、微服務,同時也懂點投資理財,堅持學習和寫作,相信終身學習的力量!關注公眾號後回覆”架構師“即可領取 Java基礎、進階、專案和架構師等免費學習資料,更有資料
I/O 多路複用
I/O型別: 接下來我們將介紹幾種常見的I/O模型及其區別 阻塞I/O:blocking I/O(如果沒有資訊,則阻塞)  
【Linux】I/O多路複用
五種IO模型 阻塞IO(等待魚上鉤) 在核心將資料準備好之前,系統呼叫會一直等待,所有的套接字,預設是阻塞模式。 等待,拷貝資料到buf中,(等待的時間長) 非阻塞IO(定期檢視是否有魚上鉤) 如果核心還未將資料
I/O多路複用技術(multiplexing)
作者:知乎使用者 連結:https://www.zhihu.com/question/28594409/answer/52835876 來源:知乎 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。 下面舉一個例子,模擬一個tcp伺服器處理30個客戶soc
I/O多路複用之select、poll、epoll
很早之前有寫過篇IO多路複用的文章:https://www.cnblogs.com/klcf0220/archive/2013/05/14/3077003.html 參考連結:https://segmentfault.com/a/1190000003063859 select,poll,epoll都是IO多路
IO基礎入門之I/O多路複用技術
在I/O程式設計過程中,當需要同時處理多個客戶端接入請求時,可以利用多執行緒或者I/O多路複用技術進行處理。I/O多路複用技術通過把多個I/O的阻塞複用到同一個select的阻塞上,從而使得系統在單執行緒的情況下可以同時處理多個客戶端請求。與傳統的多執行緒/多程序模型比,I
淺談網路I/O多路複用模型 select & poll & epoll
我們首先需要知道select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,
I/O多路複用之 epoll 系統呼叫
I/O多路複用除了之前我們提到的select和poll外,epoll 也可以檢查多個檔案描述符的就緒狀態,以達到I/O多路複用的目的。 epoll 系統呼叫是 Linux 系統專有的,在 Linux 核心 2.6 版本新增,epoll 的主要優點有: 當檢
Linux 下I/O多路複用總結
select,poll,epoll都是IO多路複用的機制。I/O多路複用就通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒),能夠通知程式進行相應的讀寫操作。但select,poll,epoll本質上都是同步I/O,因為他們都需要在讀寫事件