天天看點

Linux常見的網絡I/0模型及同步/異步消息通知機制

作者:運維木子李

#頭條創作挑戰賽#

在Linux中,常見的網絡I/O模型包括阻塞I/O、非阻塞I/O、多路複用I/O和異步I/O。

Linux常見的網絡I/0模型及同步/異步消息通知機制

下面是對每種模型的詳細說明以及同步/異步消息通知機制的示例(以C舉例):

阻塞I/O:

在阻塞I/O模型中,當應用程式進行I/O操作時,它将一直阻塞(即暫停執行)直到操作完成。

示例:

// 建立套接字
int sockfd = socket(AF_INET, SOCK_STREAM, 0);

// 建立連接配接
connect(sockfd, (struct sockaddr*)&server_address, sizeof(server_address));

// 發送資料
send(sockfd, buffer, sizeof(buffer), 0);

// 接收資料
recv(sockfd, buffer, sizeof(buffer), 0);

// 關閉套接字
close(sockfd);           

非阻塞I/O:

在非阻塞I/O模型中,應用程式可以繼續執行其他操作,而不需要等待I/O操作的完成。它通過輪詢或使用select或poll函數來檢查I/O操作是否就緒。

示例:

// 設定套接字為非阻塞模式
int flags = fcntl(sockfd, F_GETFL, 0);
fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

// 發送資料
int send_result = send(sockfd, buffer, sizeof(buffer), 0);
if (send_result == -1 && errno == EAGAIN) {
    // 資料未就緒,稍後重試
}

// 接收資料
int recv_result = recv(sockfd, buffer, sizeof(buffer), 0);
if (recv_result == -1 && errno == EAGAIN) {
    // 資料未就緒,稍後重試
}

// 關閉套接字
close(sockfd);           

多路複用I/O:

在多路複用I/O模型中,應用程式使用select、poll或epoll等函數來監視多個檔案描述符的I/O事件,一旦有就緒的檔案描述符,應用程式就可以進行相應的讀寫操作。

示例:

// 建立套接字并綁定到指定端口
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
bind(listen_fd, (struct sockaddr*)&server_address, sizeof(server_address));
listen(listen_fd, 5);

// 建立epoll執行個體并添加監聽套接字
int epoll_fd = epoll_create1(0);
struct epoll_event event;
event.data.fd = listen_fd;
event.events = EPOLLIN;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, listen_fd, &event);

while (1) {
    // 等待事件
    struct epoll_event events[MAX_EVENTS];
    int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);

    // 處理事件
    for (int i = 0; i < num_events; i++) {
        if (events[i].data.fd == listen_fd && events[i].events & EPOLLIN) {
            // 接受連接配接
            int client_fd = accept(listen_fd, (struct sockaddr*)&client_address, &client_address_len);
            // 将用戶端套接字添加到epoll執行個體中
            event.data.fd = client_fd;
            event.events = EPOLLIN;
            epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event);
        } else if (events[i].events & EPOLLIN) {
            // 接收資料
            int client_fd = events[i].data.fd;
            recv(client_fd, buffer, sizeof(buffer), 0);
        }
    }
}

// 關閉套接字和epoll執行個體
close(listen_fd);
close(epoll_fd);           

異步I/O:

在異步I/O模型中,應用程式發起I/O操作并指定回調函數,在資料就緒時,核心會通知應用程式執行相應的回調函數。

示例:

// 打開檔案
int fd = open("file.txt", O_RDONLY | O_DIRECT | O_NONBLOCK);

// 發起異步讀取操作
struct aiocb cb;
memset(&cb, 0, sizeof(struct aiocb));
cb.aio_fildes = fd;
cb.aio_buf = buffer;
cb.aio_nbytes = sizeof(buffer);
cb.aio_offset = 0;
cb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
cb.aio_sigevent.sigev_signo = SIGIO;
aio_read(&cb);

// 設定信号處理函數
void sigio_handler(int signo, siginfo_t *info, void *context) {
    // 讀取完成,處理資料
    ssize_t num_bytes = aio_return(&cb);
    // ...
}

// 關閉檔案
close(fd);           

這些示例展示了Linux中常見的網絡I/O模型以及同步/異步消息通知機制。請注意,這些示例僅作為示範,實際應用中可能需要根據具體情況進行适當的修改和處理錯誤情況。

繼續閱讀