日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系

發布時間:2024/4/24 linux 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

00. 目錄

文章目錄

    • 00. 目錄
    • 01. TCP服務端和客戶端流程
    • 02. connect函數
    • 03. listen函數
    • 04. 三次握手
    • 05. accept函數
    • 06. 附錄

01. TCP服務端和客戶端流程

02. connect函數

對于客戶端的 connect() 函數,該函數的功能為客戶端主動連接服務器,建立連接是通過三次握手,而這個連接的過程是由內核完成,不是這個函數完成的,這個函數的作用僅僅是通知 Linux 內核,讓 Linux 內核自動完成 TCP 三次握手連接,最后把連接的結果返回給這個函數的返回值(成功連接為0, 失敗為-1)。

通常的情況,客戶端的 connect() 函數默認會一直阻塞,直到三次握手成功或超時失敗才返回(正常的情況,這個過程很快完成)。

03. listen函數

對于服務器,它是被動連接的。舉一個生活中的例子,通常的情況下,移動的客服(相當于服務器)是等待著客戶(相當于客戶端)電話的到來。而這個過程,需要調用listen()函數。

listen() 函數的主要作用就是將套接字( sockfd )變成被動的連接監聽套接字(被動等待客戶端的連接),至于參數 backlog 的作用是設置內核中連接隊列的長度,TCP 三次握手也不是由這個函數完成,listen()的作用僅僅告訴內核一些信息。

這里需要注意的是,listen()函數不會阻塞,它主要做的事情為,將該套接字和套接字對應的連接隊列長度告訴 Linux 內核,然后,listen()函數就結束。

這樣的話,當有一個客戶端主動連接(connect()),Linux 內核就自動完成TCP 三次握手,將建立好的鏈接自動存儲到隊列中,如此重復。

所以,只要 TCP 服務器調用了 listen(),客戶端就可以通過 connect() 和服務器建立連接,而這個連接的過程是由內核完成。

下面為測試的服務器和客戶端代碼,運行程序時,要先運行服務器,再運行客戶端:

服務器

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int argc, char *argv[]) {unsigned short port = 8000; int sockfd;sockfd = socket(AF_INET, SOCK_STREAM, 0);// 創建通信端點:套接字if(sockfd < 0){perror("socket");exit(-1);}struct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET;my_addr.sin_port = htons(port);my_addr.sin_addr.s_addr = htonl(INADDR_ANY);int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));if( err_log != 0){perror("binding");close(sockfd); exit(-1);}err_log = listen(sockfd, 10);if(err_log != 0){perror("listen");close(sockfd); exit(-1);} printf("listen client @port=%d...\n",port);sleep(10); // 延時10ssystem("netstat -an | grep 8000"); // 查看連接狀態return 0; }

客戶端:

#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h> int main(int argc, char *argv[]) {unsigned short port = 8000; // 服務器的端口號char *server_ip = "10.221.20.12"; // 服務器ip地址int sockfd;sockfd = socket(AF_INET, SOCK_STREAM, 0);// 創建通信端點:套接字if(sockfd < 0){perror("socket");exit(-1);}struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr)); // 初始化服務器地址server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);inet_pton(AF_INET, server_ip, &server_addr.sin_addr);int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 主動連接服務器if(err_log != 0){perror("connect");close(sockfd);exit(-1);}system("netstat -an | grep 8000"); // 查看連接狀態while(1);return 0; }

運行程序時,要先運行服務器,再運行客戶端,運行結果如下:

04. 三次握手

這里詳細的介紹一下 listen() 函數的第二個參數( backlog)的作用:告訴內核連接隊列的長度。

為了更好的理解 backlog 參數,我們必須認識到內核為任何一個給定的監聽套接字維護兩個隊列:

1、未完成連接隊列(incomplete connection queue),每個這樣的 SYN 分節對應其中一項:已由某個客戶發出并到達服務器,而服務器正在等待完成相應的 TCP 三次握手過程。這些套接字處于 SYN_RCVD 狀態。

2、已完成連接隊列(completed connection queue),每個已完成 TCP 三次握手過程的客戶對應其中一項。這些套接口處于 ESTABLISHED 狀態。

當來自客戶的 SYN 到達時,TCP 在未完成連接隊列中創建一個新項,然后響應以三次握手的第二個分節:服務器的 SYN 響應,其中稍帶對客戶 SYN 的 ACK(即SYN+ACK),這一項一直保留在未完成連接隊列中,直到三次握手的第三個分節(客戶對服務器 SYN 的 ACK )到達或者該項超時為止(曾經源自Berkeley的實現為這些未完成連接的項設置的超時值為75秒)。

如果三次握手正常完成,該項就從未完成連接隊列移到已完成連接隊列的隊尾。

backlog 參數歷史上被定義為上面兩個隊列的大小之和,大多數實現默認值為 5,當服務器把這個完成連接隊列的某個連接取走后,這個隊列的位置又空出一個,這樣來回實現動態平衡,但在高并發 web 服務器中此值顯然不夠。

05. accept函數

accept()函數功能是從處于 established 狀態的連接隊列頭部取出一個已經完成的連接,如果這個隊列沒有已經完成的連接,accept()函數就會阻塞,直到取出隊列中已完成的用戶連接為止。

如果,服務器不能及時調用 accept() 取走隊列中已完成的連接,隊列滿掉后會怎樣呢?UNP(《unix網絡編程》)告訴我們,服務器的連接隊列滿掉后,服務器不會對再對建立新連接的syn進行應答,所以客戶端的 connect 就會返回 ETIMEDOUT。但實際上Linux的并不是這樣的!

下面為測試代碼,服務器 listen() 函數只指定隊列長度為 2,客戶端有 6 個不同的套接字主動連接服務器,同時,保證客戶端的 6 個 connect()函數都先調用完畢,服務器的 accpet() 才開始調用。

服務器

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int argc, char *argv[]) {unsigned short port = 8000; int sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0){perror("socket");exit(-1);}struct sockaddr_in my_addr;bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET;my_addr.sin_port = htons(port);my_addr.sin_addr.s_addr = htonl(INADDR_ANY);int err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));if( err_log != 0){perror("binding");close(sockfd); exit(-1);}err_log = listen(sockfd, 2); // 等待隊列為2if(err_log != 0){perror("listen");close(sockfd); exit(-1);} printf("after listen\n");sleep(20); //延時 20秒printf("listen client @port=%d...\n",port);int i = 0;while(1){ struct sockaddr_in client_addr; char cli_ip[INET_ADDRSTRLEN] = ""; socklen_t cliaddr_len = sizeof(client_addr); int connfd;connfd = accept(sockfd, (struct sockaddr*)&client_addr, &cliaddr_len); if(connfd < 0){perror("accept");continue;}inet_ntop(AF_INET, &client_addr.sin_addr, cli_ip, INET_ADDRSTRLEN);printf("-----------%d------\n", ++i);printf("client ip=%s,port=%d\n", cli_ip,ntohs(client_addr.sin_port));char recv_buf[512] = {0};while( recv(connfd, recv_buf, sizeof(recv_buf), 0) > 0 ){printf("recv data ==%s\n",recv_buf);break;}close(connfd); //關閉已連接套接字//printf("client closed!\n");}close(sockfd); //關閉監聽套接字return 0; }

客戶端

#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <arpa/inet.h> #include <sys/socket.h> #include <netinet/in.h>void test_connect() {unsigned short port = 8000; // 服務器的端口號char *server_ip = "10.221.20.12"; // 服務器ip地址int sockfd;sockfd = socket(AF_INET, SOCK_STREAM, 0);// 創建通信端點:套接字if(sockfd < 0){perror("socket");exit(-1);}struct sockaddr_in server_addr;bzero(&server_addr,sizeof(server_addr)); // 初始化服務器地址server_addr.sin_family = AF_INET;server_addr.sin_port = htons(port);inet_pton(AF_INET, server_ip, &server_addr.sin_addr);int err_log = connect(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr)); // 主動連接服務器if(err_log != 0){perror("connect");close(sockfd);exit(-1);}printf("err_log ========= %d\n", err_log);char send_buf[100]="this is for test";send(sockfd, send_buf, strlen(send_buf), 0); // 向服務器發送信息system("netstat -an | grep 8000"); // 查看連接狀態//close(sockfd); }int main(int argc, char *argv[]) {pid_t pid;pid = fork();if(0 == pid){test_connect(); // 1pid_t pid = fork();if(0 == pid){test_connect(); // 2}else if(pid > 0){test_connect(); // 3}}else if(pid > 0){test_connect(); // 4pid_t pid = fork();if(0 == pid){test_connect(); // 5}else if(pid > 0){test_connect(); // 6}}while(1);return 0; }

同樣是先運行服務器,在運行客戶端,服務器 accept()函數前延時了 20 秒, 保證了客戶端的 connect() 全部調用完畢后再調用 accept(),運行結果如下:


客戶端運行結果

按照 UNP 的說法,連接隊列滿后(這里設置長度為 2,發了 6 個連接),以后再調用 connect() 應該統統超時失敗,但實際上測試結果是:有的 connect()立刻成功返回了,有的經過明顯延遲后成功返回了。對于服務器 accpet() 函數也是這樣的結果:有的立馬成功返回,有的延遲后成功返回

對于上面服務器的代碼,我們把lisen()的第二個參數改為 0 的數,重新運行程序,發現客戶端 connect() 全部返回連接成功(有些會延時)

服務器 accpet() 函數卻不能把連接隊列的所有連接都取出來:
圖片保存下來直接上傳(img-i12tqYDQ-1595920060035)(assets/image-

對于上面服務器的代碼,我們把lisen()的第二個參數改為大于 6 的數(如 10),重新運行程序,發現,客戶端 connect() 立馬返回連接成功, 服務器 accpet() 函數也立馬返回成功。

TCP 的連接隊列滿后,Linux 不會如書中所說的拒絕連接,只是有些會延時連接,而且accept()未必能把已經建立好的連接全部取出來(如:當隊列的長度指定為 0 ),寫程序時服務器的 listen() 的第二個參數最好還是根據需要填寫,寫太大不好(具體可以看cat /proc/sys/net/core/somaxconn,默認最大值限制是 128),浪費資源,寫太小也不好,延時建立連接。

06. 附錄

5.1【Linux】一步一步學Linux網絡編程教程匯總

總結

以上是生活随笔為你收集整理的【Linux网络编程】TCP网络编程中connect listen和accept三者之间的关系的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 新版天堂资源中文8在线 | 999这里有精品 | 精品国产伦一区 | 深夜视频免费在线观看 | 久久久午夜精品福利内容 | 蜜桃传媒一区二区亚洲 | 三级成人 | 亚洲黄色激情 | 手机看片99 | xvideos成人免费视频 | 污视频网址在线观看 | 欧美日韩视频网站 | 日韩久久精品电影 | 日本www| 美女在线免费视频 | 在线视频免费观看一区 | 污视频在线观看网址 | 婷婷综合亚洲 | 成人午夜视频在线观看 | 久久久久久无码精品人妻一区二区 | 蜜臀av免费在线观看 | 日本高清无吗 | 国产喷水福利在线视频 | 亚洲成人精品在线 | 高清不卡一区二区三区 | 欧美少妇性生活 | 久久免费看毛片 | 日韩av网站在线观看 | 成人污视频 | 午夜激情小视频 | 欧美毛片在线观看 | 超碰人人国产 | 日韩精品视频在线免费观看 | 精品国产区一区二 | 草草视频在线观看 | 97精品人妻一区二区三区香蕉 | 日本深夜福利 | 欧美激情国产精品 | 91l九色lporny| 在线看黄网站 | 曰本女人与公拘交酡 | 成人av影院| 蜜桃臀一区二区三区 | 人人看人人澡 | 在线视频一区二区 | 日韩高清在线播放 | 成人精品一区二区三区 | 美女扒开粉嫩尿口 | 久久女同互慰一区二区三区 | 在线 日本 制服 中文 欧美 | 中文字幕人妻一区二区在线视频 | 日韩亚州 | 69av在线播放 | 国产精品伦一区二区三区 | 一呦二呦三呦精品网站 | 涩涩涩在线视频 | 先锋影音在线 | 国产校园春色 | www.热久久| 9.1成人看片 | 久久99精品久久久久 | www.国产精品 | 日韩午夜精品视频 | 欧美性生活一级 | 污污的视频在线观看 | 亚洲成人av电影 | 制服诱惑一区二区三区 | 人人射 | 日韩视频第一页 | 在线观看免费视频一区二区 | 污视频在线 | 人妻久久久一区二区三区 | 性激情视频 | 天堂av一区 | 日本一道本在线 | 国产真实生活伦对白 | 亚洲综合免费观看高清完整版 | 国产精品17p | 日韩精品电影一区 | www.精品久久 | 久久久剧场 | 精品视频在线免费观看 | av不卡在线 | 亚洲图片欧美 | 天天操天天看 | 一区二区三区欧美在线 | 在线播放无码后入内射少妇 | 欧美爱爱小视频 | 夜夜骚av| 九九热综合 | 操穴影院| 亚洲AV无码成人精品一区 | 欧洲国产视频 | 中文在线观看免费网站 | 午夜福利视频一区二区 | 粉嫩欧美一区二区三区 | 国产又粗又硬又长又爽的演员 | 美女无遮挡免费网站 | 国产综合亚洲精品一区二 |