Linux IO模型漫談(4)- 非阻塞IO


首先先說一下,阻塞IO會在哪些地方阻塞住呢?輸入操作read, 輸出操作write,接受請求操作accept,發送請求操作connect,這四個地方阻塞進程。

非阻塞IO的模型圖示在前面的章節有講過,它和阻塞IO的最大區別就是:如果連接或者操作不能立即建立,那么連接的建立照樣能發起,只是會返回一個錯誤信息。

同樣,先說明幾個用到的函數和操作:

1 fcntl函數

其全名為”file control“。顧名思義,fcntl可以執行各種操作符控制操作。

#include <fcntl.h>

int fcntl(int fd, int cmd, .. /* int arg */)

第一個參數fd是文件描述符

第二個參數cmd是操作命令,比如設置套接字阻塞非阻塞的命令為F_SETFL, 設置套接字屬主的命令為F_SETOWN

第三個參數以后,是操作命令的參數。比如設置非阻塞IO型的F_SETFL的參數為O_NONBLOCK

所以設置非阻塞IO的典型設置代碼為:

flags = flags | O_NONBLOCK;

fcntl(fd, F_SETFL, flags);

2 非阻塞IO返回的錯誤

對於不能滿足的非阻塞IO操作,System V會返回EAGAIN錯誤,而源自Berkeley的實現返回EWOULDBLOCK。大多數當前系統把這兩個錯誤碼定義為相同的值。

對不能滿足的非阻塞IO連接,系統會返回EINPROGRESS

按照非阻塞的定義,我們只需要將cli做下面修改:

3客戶端代碼

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>


int main(int argc, char* argv[])
{
    int socketfd, n;
    socketfd = socket(AF_INET, SOCK_STREAM, 0);
    fcntl(socketfd, F_SETFL, O_NONBLOCK);
    
    struct sockaddr_in serv_addr;
		
    bzero((char *)&serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    serv_addr.sin_port = htons(7777);

    for(;;) {
        if(n = connect(socketfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
            if(errno == EINPROGRESS) {
                printf("EINPROGRESS\n");
            }
        } else {
            break;
        }
    }
		
    write(socketfd, "client message", 14);
		
    char buffer[256];
    bzero(buffer, 256);
    read(socketfd, buffer, 255);
		
    printf("server return message:%s\r\n", buffer);
		
    return 0;

}
 

運行方式:

1 server不啟動

2 client啟動,則會在connect這個地方進入無限循環。

 

好吧,是不是覺得有問題?

1 這種模型,客戶端使用輪詢不斷調用IO操作,那么,CPU就會一直用於輪詢,造成cpu的浪費。

2 這種模型,代碼量比阻塞的模型大很多

所以這個模型實際上是很少使用的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM