#頭條創作挑戰賽#
在Linux中,常見的網絡I/O模型包括阻塞I/O、非阻塞I/O、多路複用I/O和異步I/O。
下面是對每種模型的詳細說明以及同步/異步消息通知機制的示例(以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模型以及同步/異步消息通知機制。請注意,這些示例僅作為示範,實際應用中可能需要根據具體情況進行适當的修改和處理錯誤情況。