日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
深入理解Linux Socket系統(tǒng)調(diào)用 (linux socket系統(tǒng)調(diào)用)

Linux操作系統(tǒng)廣泛應(yīng)用于服務(wù)器、互聯(lián)網(wǎng)、嵌入式設(shè)備等領(lǐng)域,其成功的原因之一便是其強(qiáng)大的網(wǎng)絡(luò)支持。Linux提供了一套完整的Socket編程API,使得程序員可以方便地實(shí)現(xiàn)網(wǎng)絡(luò)應(yīng)用程序。Socket編程是網(wǎng)絡(luò)編程的基礎(chǔ),對(duì)于開發(fā)網(wǎng)絡(luò)應(yīng)用程序至關(guān)重要。

專注于為中小企業(yè)提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)大觀免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了上1000+企業(yè)的穩(wěn)健成長(zhǎng),幫助中小企業(yè)通過(guò)網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。

本文將系統(tǒng)地介紹linux socket系統(tǒng)調(diào)用相關(guān)知識(shí),包括Socket概念、Socket編程模型、Socket系統(tǒng)調(diào)用接口、Socket編程應(yīng)用例程等,并結(jié)合應(yīng)用場(chǎng)景進(jìn)行實(shí)踐演示,以期讀者能夠,掌握Socket編程技術(shù)。

一、Socket概念

Socket是一種傳輸層協(xié)議,用于實(shí)現(xiàn)進(jìn)程間的網(wǎng)絡(luò)通信,是Linux中程序進(jìn)行網(wǎng)絡(luò)通信的主要手段。Socket提供了一套完整的API,使得程序員能夠方便地進(jìn)行網(wǎng)絡(luò)編程。

在網(wǎng)絡(luò)編程中,Socket常用于描述生成的套接字(socket),套接字是使用網(wǎng)絡(luò)傳輸協(xié)議進(jìn)行通信的兩個(gè)程序之間的一條雙向通信鏈路。套接字可使用網(wǎng)絡(luò)傳輸協(xié)議TCP、UDP、RAW等。

二、Socket編程模型

Socket編程模型是一種典型的客戶端/服務(wù)器模型,其中服務(wù)器程序和客戶端程序分別運(yùn)行在不同的主機(jī)上,通過(guò)對(duì)套接字API的調(diào)用來(lái)實(shí)現(xiàn)進(jìn)程間的通信。Socket編程模型通常包括三個(gè)要素:服務(wù)器、客戶端和Socket。

1、服務(wù)器

服務(wù)器是Socket編程模型中的核心角色,其職責(zé)是等待客戶端的連接請(qǐng)求,并對(duì)連接請(qǐng)求進(jìn)行處理。服務(wù)器通過(guò)Socket系統(tǒng)調(diào)用創(chuàng)建一個(gè)用于偵聽連接請(qǐng)求的套接字,并通過(guò)accept系統(tǒng)調(diào)用對(duì)連接請(qǐng)求進(jìn)行響應(yīng),最后通過(guò)接受到的客戶端請(qǐng)求來(lái)完成進(jìn)程間的通信。

2、客戶端

客戶端是Socket編程模型中的請(qǐng)求方,其職責(zé)是主動(dòng)與服務(wù)器建立Socket連接,并通過(guò)Socket傳輸數(shù)據(jù)??蛻舳送ㄟ^(guò)Socket系統(tǒng)調(diào)用創(chuàng)建一個(gè)用于連接服務(wù)器的套接字,并通過(guò)connect系統(tǒng)調(diào)用與服務(wù)器建立連接。建立連接后,客戶端可以使用send和recv系統(tǒng)調(diào)用來(lái)發(fā)送和接受數(shù)據(jù)。

3、Socket

Socket是Socket編程模型中進(jìn)程間通信的主要手段,其實(shí)現(xiàn)方式與文件讀寫類似,可以使用系統(tǒng)調(diào)用對(duì)其進(jìn)行讀寫操作。對(duì)于服務(wù)器端,Socket主要用來(lái)偵聽客戶端連接請(qǐng)求,創(chuàng)建客戶端與服務(wù)器之間的連接;對(duì)于客戶端,Socket主要用來(lái)主動(dòng)發(fā)起連接請(qǐng)求,并完成數(shù)據(jù)傳輸操作。

三、Socket系統(tǒng)調(diào)用

Socket系統(tǒng)調(diào)用是Linux操作系統(tǒng)提供的一套API接口,用于操作Socket。Socket系統(tǒng)調(diào)用為Socket編程提供了多種API,包括創(chuàng)建Socket、建立連接、發(fā)送數(shù)據(jù)、接收數(shù)據(jù)等。

以下是常用的Socket系統(tǒng)調(diào)用:

1、socket:創(chuàng)建一個(gè)新的Socket,返回套接字描述符。

2、bind:將地址和端口號(hào)綁定到Socket上。

3、listen:開始監(jiān)聽來(lái)自客戶端的連接請(qǐng)求。

4、accept:接收客戶端的連接請(qǐng)求,返回一個(gè)新的套接字描述符。

5、connect:主動(dòng)與服務(wù)器建立連接。

6、send:向已連接的Socket中發(fā)送數(shù)據(jù)。

7、recv:從已連接的Socket中接收數(shù)據(jù)。

8、shutdown:關(guān)閉Socket的發(fā)送或接收通道。

四、Socket編程應(yīng)用例程

下面通過(guò)一個(gè)簡(jiǎn)單的Socket編程應(yīng)用例子來(lái)說(shuō)明Socket編程的具體應(yīng)用。

使用Socket編寫一個(gè)簡(jiǎn)單的服務(wù)器來(lái)接受客戶端的輸入,并將其發(fā)送回客戶端。

1、服務(wù)器端程序演示代碼:

“`

#include

#include

#include

#include

#include

#include

#include

int mn(void)

{

int server_fd, client_fd;

socklen_t client_len;

struct sockaddr_in server_addr, client_addr;

char buffer[1024];

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr.s_addr = htonl(INADDR_ANY);

server_addr.sin_port = htons(30001);

if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror(“server: socket error”);

exit(1);

}

if (bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {

perror(“server: bind error”);

exit(1);

}

if (listen(server_fd, 5) == -1) {

perror(“server: listen error”);

exit(1);

}

printf(“server wting for client on port 30001…\n”);

while (1) {

client_len = sizeof(client_addr);

client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &client_len);

if (client_fd == -1) {

perror(“server: accept error”);

continue;

}

printf(“server: connection from client %s\n”, inet_ntoa(client_addr.sin_addr));

while (1) {

memset(buffer, 0, sizeof(buffer));

if (recv(client_fd, buffer, sizeof(buffer), 0) == -1) {

perror(“server: receive error”);

break;

}

if (strcmp(buffer, “quit\n”) == 0) {

printf(“server: client %s quits\n”, inet_ntoa(client_addr.sin_addr));

break;

}

printf(“server: receive message %s”, buffer);

if (send(client_fd, buffer, strlen(buffer), 0) == -1) {

perror(“server: send error”);

break;

}

}

close(client_fd);

}

close(server_fd);

return 0;

}

“`

2、客戶端程序演示代碼:

“`

#include

#include

#include

#include

#include

#include

#include

#include

int mn(int argc, char *argv[])

{

int client_fd, numbytes;

struct hostent *he;

struct sockaddr_in server_addr;

char message[1024];

if (argc != 2) {

fprintf(stderr, “usage: client hostname\n”);

exit(1);

}

if ((he = gethostbyname(argv[1])) == NULL) {

perror(“client: gethostbyname error”);

exit(1);

}

if ((client_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {

perror(“client: socket error”);

exit(1);

}

memset(&server_addr, 0, sizeof(server_addr));

server_addr.sin_family = AF_INET;

server_addr.sin_addr = *((struct in_addr*)he->h_addr);

server_addr.sin_port = htons(30001);

if (connect(client_fd, (struct sockaddr*)&server_addr, sizeof(server_addr)) == -1) {

perror(“client: connect error”);

exit(1);

}

printf(“client: connected to server %s\n”, argv[1]);

while (1) {

memset(message, 0, sizeof(message));

fgets(message, sizeof(message), stdin);

if (strcmp(message, “quit\n”) == 0) {

printf(“client quits\n”);

break;

}

if (send(client_fd, message, strlen(message), 0) == -1) {

perror(“client: send error”);

exit(1);

}

if ((numbytes = recv(client_fd, message, sizeof(message), 0)) == -1) {

perror(“client: recv error”);

exit(1);

}

message[numbytes] = ‘\0’;

printf(“client: receive message %s”, message);

}

close(client_fd);

return 0;

}

“`

運(yùn)行結(jié)果:

1、服務(wù)器端運(yùn)行結(jié)果

“`

server wting for client on port 30001…

server: connection from client 127.0.0.1

server: receive message abc

server: receive message def

server: client 127.0.0.1 quits

“`

2、客戶端運(yùn)行結(jié)果

“`

client: connected to server 127.0.0.1

abc

client: receive message abc

def

client: receive message def

quit

client quits

“`

以上代碼演示了一個(gè)簡(jiǎn)單的Socket編程應(yīng)用,該應(yīng)用實(shí)現(xiàn)了客戶端和服務(wù)器端的互相通信,可以作為Socket編程的入門代碼進(jìn)行學(xué)習(xí)和研究。

相關(guān)問(wèn)題拓展閱讀:

  • linux手冊(cè)翻譯——send(2)
  • Linux系統(tǒng)I/O模型及select、poll、epoll原理和應(yīng)用

linux手冊(cè)翻譯——send(2)

send, sendto, sendmsg – send a message on a socket

系統(tǒng)調(diào)用 send()、sendto() 和 sendmsg() 用于將消息傳輸?shù)搅硪粋€(gè)套接字。

僅當(dāng)套接字處于連接狀態(tài)時(shí)才可以使用 send() 調(diào)用(以便知道預(yù)期的接收者, 也就是說(shuō)send()僅僅用于數(shù)據(jù)流類型的數(shù)據(jù)發(fā)送 ,對(duì)于TCP,服務(wù)端和客戶端都可以使用send/recv;但是對(duì)于UDP,只能是客戶端使用send/recv,服務(wù)端只能使用sendto/recvfrom,因?yàn)榭蛻舳耸沁M(jìn)行了connect操作知道要發(fā)送和接受的地址)。send() 和 write(2) 之間的唯一滲衡區(qū)別是存在 flags 參數(shù)。此外,

send(sockfd, buf, len, flags);

等價(jià)于

sendto(sockfd, buf, len, flags, NULL, 0);

參數(shù) sockfd 是發(fā)送者套接字的文件描述符。

如果在連接模式的套接字(即套接字類型為SOCK_STREAM、SOCK_SEQPACKET)上使用 sendto(),則參數(shù) dest_addr 和 addrlen 將被忽略(當(dāng)它們不是NULL和0時(shí)可能返回錯(cuò)誤EISCONN),若套接字沒有實(shí)際連接(還沒有三次握手建立連接)將返回錯(cuò)誤ENOTCONN。 否則,目標(biāo)地址由 dest_addr 給出, addrlen 指定其大小。 對(duì)于 sendmsg(),目標(biāo)地址由 msg.msg_name 給出, msg.msg_namelen 指定其大小。

對(duì)于 send() 和 sendto(),消息位于 buf 中,長(zhǎng)度為 len 。 對(duì)于sendmsg(),消息存放于 msg.msg_iov 元素指向

數(shù)組數(shù)據(jù)區(qū)

(見下)中。

sendmsg() 調(diào)用還允許發(fā)送輔助數(shù)據(jù)(也稱為控制信息)

。

如果消息太長(zhǎng)而無(wú)法通過(guò)底層協(xié)議原子傳遞( too long to pass atomically through the underlying protocol ),則返回錯(cuò)誤 EMSGSIZE,并且不會(huì)傳輸消息。

No indication of failure to deliver is implicit in a send(). Locally detected errors are indicated by a return value of -1.

當(dāng)消息轎陵不適合套接字的發(fā)送緩沖區(qū)時(shí),send() 通常會(huì)阻塞,除非套接字已置于非阻塞 I/O 模式。 在這種情況下,在非阻塞模式下它會(huì)失敗并顯示錯(cuò)誤 EAGAIN 或 EWOULDBLOCK。

select(2) 調(diào)用可用于確定何時(shí)可以發(fā)送更多數(shù)據(jù)

上面的的描述還是很籠統(tǒng)的,以TCP為例,按我的理解,我認(rèn)為只要發(fā)送緩沖區(qū)有空閑位置,且此時(shí)協(xié)議棧沒有向網(wǎng)絡(luò)發(fā)送數(shù)據(jù),那么就可以寫入,對(duì)于阻塞模式,直到所有數(shù)據(jù)寫入到緩沖區(qū),就會(huì)返回,否則一直阻塞,對(duì)于非阻塞模式,是有一個(gè)超時(shí)時(shí)間的,這個(gè)由 SO_SNDTIMEO 選項(xiàng)控制,詳細(xì)見 socket(7) ,如果當(dāng)前有空閑位置可以發(fā)即當(dāng)前可寫入,那么就寫入到緩沖區(qū),知道超時(shí)之前寫入多少算多少,然后返回成功寫入的字節(jié)數(shù),如果超時(shí)時(shí)任何數(shù)據(jù)都沒寫出去,或者當(dāng)前就是閉喊戚不可寫入,那么返回-1 ,并設(shè)置errno為 EAGAIN 或 EWOULDBLOCK。

The flags argument is the bitwise OR of zero or more of the following flags.

sendmsg() 使用的 msghdr 結(jié)構(gòu)的定義如下:

對(duì)于未連接的套接字 msg_name 指定數(shù)據(jù)報(bào)的目標(biāo)地址,它指向一個(gè)包含地址的緩沖區(qū); msg_namelen 字段應(yīng)設(shè)置為地址的大小。 對(duì)于連接的套接字,這些字段應(yīng)分別指定為 NULL 和 0。

這里的未連接指的是數(shù)據(jù)報(bào)協(xié)議,連接指的是數(shù)據(jù)流協(xié)議

The msg_iov and msg_iovlen fields specify scatter-gather locations, as for writev(2).

msg_iov是一個(gè)buffer數(shù)組:

使用 msg_control 和 msg_controllen 成員發(fā)送控制信息(輔助數(shù)據(jù))。 內(nèi)核可以處理的每個(gè)套接字更大控制緩沖區(qū)長(zhǎng)度由 /proc/sys/net/core/optmem_max 中的值限制; 見 socket(7) 。 有關(guān)在各種套接字域中使用輔助數(shù)據(jù)的更多信息,請(qǐng)參閱 unix(7) 和 ip(7)。

msg_flags 字段被忽略。

成功時(shí),返回成功發(fā)送的字節(jié)數(shù),這個(gè)字節(jié)數(shù)并不一定和我們的緩沖區(qū)大小相同

。 出錯(cuò)時(shí),返回 -1,并設(shè)置 errno 以指示錯(cuò)誤。

這些是套接字層生成的一些標(biāo)準(zhǔn)錯(cuò)誤。 底層協(xié)議模塊可能會(huì)產(chǎn)生和返回額外的錯(cuò)誤; 請(qǐng)參閱它們各自的手冊(cè)頁(yè)。

4.4BSD, SVr4, POSIX.1-2023. These interfaces first appeared in 4.2BSD.

POSIX.describes only the MSG_OOB and MSG_EOR flags. POSIX.adds a specification of MSG_NOSIGNAL. The MSG_CONFIRM flag is a Linux extension.

根據(jù) POSIX.1-2023,msghdr 結(jié)構(gòu)的 msg_controllen 字段應(yīng)該是 socklen_t 類型,而 msg_iovlen 字段應(yīng)該是 int 類型,但是 glibc 目前將兩者都視為 size_t。

有關(guān)可用于在單個(gè)調(diào)用中傳輸多個(gè)數(shù)據(jù)報(bào)的 Linux 特定系統(tǒng)調(diào)用的信息,請(qǐng)參閱 sendmmsg(2)。

Linux may return EPIPE instead of ENOTCONN.

getaddrinfo(3) 中顯示了使用 send() 的示例。

Linux系統(tǒng)I/O模型及select、poll、epoll原理和應(yīng)用

理解Linux的IO模型之前,首先要了解一些基本概念,才能理解這些IO模型設(shè)計(jì)的依據(jù)

操作系統(tǒng)使用虛擬內(nèi)旦談磨存來(lái)映射物理內(nèi)存,對(duì)于32位的操作系統(tǒng)來(lái)說(shuō),虛擬地址空間為4G(2^32)。操作系統(tǒng)的核心是內(nèi)核,為了保護(hù)用戶進(jìn)程不能直接操作內(nèi)核,保證內(nèi)核安全,操作系統(tǒng)將虛擬地址空間劃分為內(nèi)核空間和用戶空間。內(nèi)核可以訪問(wèn)全部的地址空間,擁有訪問(wèn)底層硬件設(shè)備的權(quán)限,普通的應(yīng)用程序需要訪問(wèn)硬件設(shè)備必須通過(guò)

系統(tǒng)調(diào)用

來(lái)實(shí)現(xiàn)。

對(duì)于Linux系統(tǒng)來(lái)說(shuō),將虛擬內(nèi)存的更高1G字節(jié)的空間作為內(nèi)核空間僅供內(nèi)核使用,低3G字節(jié)的空間供用戶進(jìn)程使用,稱為用戶空間。

又被稱為標(biāo)準(zhǔn)I/O,大多數(shù)文件系統(tǒng)的默認(rèn)I/O都是緩存I/O。在Linux系統(tǒng)的緩存I/O機(jī)制中,操作系統(tǒng)會(huì)將I/O的數(shù)據(jù)緩存在頁(yè)緩存(內(nèi)存)中,也就是數(shù)據(jù)先被拷貝到內(nèi)核的緩沖區(qū)(內(nèi)核地址空間),然后才會(huì)從內(nèi)核緩沖區(qū)拷貝到應(yīng)用程序的緩沖區(qū)(用戶地址空間)。

這種方式很明顯的缺點(diǎn)就是數(shù)據(jù)傳輸過(guò)程中需要再應(yīng)用程序地址空間和內(nèi)核空間進(jìn)行多次數(shù)據(jù)拷貝操作,這些操作帶來(lái)的CPU以及內(nèi)存的開銷是非常大的。

由于Linux系統(tǒng)采用的緩存I/O模式,對(duì)于一次I/O訪問(wèn),以讀操作舉例,數(shù)據(jù)先會(huì)被拷貝到內(nèi)核緩沖區(qū),然后才會(huì)從內(nèi)核緩沖區(qū)拷貝到應(yīng)用程序的緩存區(qū),當(dāng)一個(gè)read系統(tǒng)調(diào)用發(fā)生的時(shí)候,會(huì)經(jīng)歷兩個(gè)階段:

正是因?yàn)檫@兩個(gè)狀態(tài),Linux系統(tǒng)才產(chǎn)生了多種不同的網(wǎng)絡(luò)I/O模式的方案

Linux系統(tǒng)默認(rèn)情況下所有socke都是blocking的,一個(gè)讀操作流程如下:

以UDP socket為例,當(dāng)用戶進(jìn)程調(diào)用了recvfrom系統(tǒng)調(diào)用,如果數(shù)據(jù)還沒準(zhǔn)備好,應(yīng)用進(jìn)程被阻塞,內(nèi)核直到數(shù)據(jù)到來(lái)且將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到了應(yīng)用進(jìn)程緩沖區(qū),然后向用戶進(jìn)程返回結(jié)果,用戶進(jìn)程才解除block狀態(tài),重新運(yùn)行起來(lái)。

阻塞模行下只是阻塞了當(dāng)前的應(yīng)用進(jìn)程,其他進(jìn)程還可以執(zhí)行,不消耗CPU時(shí)間,CPU的利用率較高。

Linux可以設(shè)置socket為非阻塞的,非阻塞模式下執(zhí)行一個(gè)讀操作流程如下:

當(dāng)用戶進(jìn)程發(fā)出recvfrom系統(tǒng)調(diào)用時(shí),如果kernel中的數(shù)據(jù)還沒準(zhǔn)備好,模斗recvfrom會(huì)立即返回一個(gè)error結(jié)果,不會(huì)阻塞用戶進(jìn)程,用戶進(jìn)程收到error時(shí)知道數(shù)據(jù)還沒準(zhǔn)備好,過(guò)一會(huì)再調(diào)用recvfrom,直到kernel中的數(shù)據(jù)準(zhǔn)備好了,內(nèi)核就立即將數(shù)據(jù)拷貝到用戶內(nèi)存然后返回ok,這個(gè)過(guò)程需要用戶進(jìn)程去輪詢內(nèi)核數(shù)據(jù)是否準(zhǔn)備好。

非阻塞模型下由于要處理更多的系統(tǒng)調(diào)用,因此CPU利用率比較低。

應(yīng)用進(jìn)程使用sigaction系統(tǒng)調(diào)用,內(nèi)核立即返回,等到kernel數(shù)據(jù)準(zhǔn)備好時(shí)會(huì)給用戶進(jìn)程發(fā)送一個(gè)信號(hào),告訴用戶進(jìn)程可以進(jìn)行IO操作了,然后用戶進(jìn)程再調(diào)用IO系統(tǒng)調(diào)用如recvfrom,將數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到應(yīng)用進(jìn)程。流程如下:

相比于輪詢的方式,不需要多次系統(tǒng)調(diào)用輪詢,信號(hào)驅(qū)動(dòng)IO的CPU利用率更高。

異步IO模型與其他模型更大的區(qū)別是,異步IO在系統(tǒng)調(diào)用返回的時(shí)候所有操作都已經(jīng)完成,應(yīng)用進(jìn)程既不需要等待數(shù)據(jù)準(zhǔn)備,也不需要在數(shù)據(jù)到來(lái)后等待數(shù)據(jù)從內(nèi)核緩沖區(qū)拷貝到用戶緩沖區(qū),流程如下:

在數(shù)據(jù)拷貝完成后,kernel會(huì)給用戶進(jìn)程發(fā)送一個(gè)信號(hào)告訴其read操作完成了。

是用select、poll等待數(shù)據(jù),可以等待多個(gè)socket中的任一個(gè)變?yōu)榭勺x,這一過(guò)程會(huì)被阻塞,當(dāng)某個(gè)套接字?jǐn)?shù)據(jù)到來(lái)時(shí)返回,之后再用recvfrom系統(tǒng)調(diào)用把數(shù)據(jù)從內(nèi)核緩存區(qū)復(fù)制到用戶進(jìn)程,流程如下:

流程類似阻塞IO,甚至比阻塞IO更差,多使用了一個(gè)系統(tǒng)調(diào)用,但是IO多路復(fù)用更大的侍兄特點(diǎn)是讓單個(gè)進(jìn)程能同時(shí)處理多個(gè)IO事件的能力,又被稱為事件驅(qū)動(dòng)IO,相比于多線程模型,IO復(fù)用模型不需要線程的創(chuàng)建、切換、銷毀,系統(tǒng)開銷更小,適合高并發(fā)的場(chǎng)景。

select是IO多路復(fù)用模型的一種實(shí)現(xiàn),當(dāng)select函數(shù)返回后可以通過(guò)輪詢fdset來(lái)找到就緒的socket。

優(yōu)點(diǎn)是幾乎所有平臺(tái)都支持,缺點(diǎn)在于能夠監(jiān)聽的fd數(shù)量有限,Linux系統(tǒng)上一般為1024,是寫死在宏定義中的,要修改需要重新編譯內(nèi)核。而且每次都要把所有的fd在用戶空間和內(nèi)核空間拷貝,這個(gè)操作是比較耗時(shí)的。

poll和select基本相同,不同的是poll沒有更大fd數(shù)量限制(實(shí)際也會(huì)受到物理資源的限制,因?yàn)橄到y(tǒng)的fd數(shù)量是有限的),而且提供了更多的時(shí)間類型。

總結(jié):select和poll都需要在返回后通過(guò)輪詢的方式檢查就緒的socket,事實(shí)上同時(shí)連的大量socket在一個(gè)時(shí)刻只有很少的處于就緒狀態(tài),因此隨著監(jiān)視的描述符數(shù)量的變多,其性能也會(huì)逐漸下降。

epoll是select和poll的改進(jìn)版本,更加靈活,沒有描述符限制。epoll使用一個(gè)文件描述符管理多個(gè)描述符,將用戶關(guān)系的文件描述符的事件存放到內(nèi)核的一個(gè)事件表中,這樣在用戶空間和內(nèi)核空間的copy只需一次。

epoll_create()用來(lái)創(chuàng)建一個(gè)epoll句柄。

epoll_ctl() 用于向內(nèi)核注冊(cè)新的描述符或者是改變某個(gè)文件描述符的狀態(tài)。已注冊(cè)的描述符在內(nèi)核中會(huì)被維護(hù)在一棵紅黑樹上,通過(guò)回調(diào)函數(shù)內(nèi)核會(huì)將 I/O 準(zhǔn)備好的描述符加入到一個(gè)就緒鏈表中管理。

epoll_wait() 可以從就緒鏈表中得到事件完成的描述符,因此進(jìn)程不需要通過(guò)輪詢來(lái)獲得事件完成的描述符。

當(dāng)epoll_wait檢測(cè)到描述符IO事件發(fā)生并且通知給應(yīng)用程序時(shí),應(yīng)用程序可以不立即處理該事件,下次調(diào)用epoll_wait還會(huì)再次通知該事件,支持block和nonblocking socket。

當(dāng)epoll_wait檢測(cè)到描述符IO事件發(fā)生并且通知給應(yīng)用程序時(shí),應(yīng)用程序需要立即處理該事件,如果不立即處理,下次調(diào)用epoll_wait不會(huì)再次通知該事件。

ET模式在很大程度上減少了epoll事件被重復(fù)觸發(fā)的次數(shù),因此效率要比LT模式高。epoll工作在ET模式的時(shí)候,必須使用nonblocking socket,以避免由于一個(gè)文件句柄的阻塞讀/阻塞寫操作把處理多個(gè)文件描述符的任務(wù)餓死。

【segmentfault】 Linux IO模式及 select、poll、epoll詳解

【GitHub】 CyC2023/CS-Notes

關(guān)于linux socket系統(tǒng)調(diào)用的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。

成都網(wǎng)站設(shè)計(jì)制作選創(chuàng)新互聯(lián),專業(yè)網(wǎng)站建設(shè)公司。
成都創(chuàng)新互聯(lián)10余年專注成都高端網(wǎng)站建設(shè)定制開發(fā)服務(wù),為客戶提供專業(yè)的成都網(wǎng)站制作,成都網(wǎng)頁(yè)設(shè)計(jì),成都網(wǎng)站設(shè)計(jì)服務(wù);成都創(chuàng)新互聯(lián)服務(wù)內(nèi)容包含成都網(wǎng)站建設(shè),小程序開發(fā),營(yíng)銷網(wǎng)站建設(shè),網(wǎng)站改版,服務(wù)器托管租用等互聯(lián)網(wǎng)服務(wù)。


標(biāo)題名稱:深入理解Linux Socket系統(tǒng)調(diào)用 (linux socket系統(tǒng)調(diào)用)
網(wǎng)址分享:http://m.5511xx.com/article/djsjjch.html