很久之前寫過以上:套接字socket的底層來龍去脈、sockfs文件系統的實現,可以作為本文的前置知識進行學習瀏覽。
先來一張本文中核心的一張圖,具體可以看后面文章的解釋:
本文從socket的bind系統調用進行分析,主要是了解一下bind背后,Linux內核是如何進行端口綁定、如何管理本地眾多的端口號。
先直觀感受bind系統調用背后的端口管理、端口復用
#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[])
{
int sockfd_one;
int err_log;
sockfd_one = socket(AF_INET, SOCK_STREAM, 0); //創建TCP套接字one
if(sockfd_one < 0)
{
perror("sockfd_one");
exit(-1);
}
// 設置本地網絡信息
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(8000); // 端口為8000
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 綁定,端口為8000
err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind sockfd_one");
close(sockfd_one);
exit(-1);
}
int sockfd_two;
sockfd_two = socket(AF_INET, SOCK_STREAM, 0); //創建TCP套接字two
if(sockfd_two < 0)
{
perror("sockfd_two");
exit(-1);
}
// 新套接字sockfd_two,繼續綁定8000端口,綁定失敗
// 因為8000端口已被占用,默認情況下,端口沒有釋放,無法綁定
err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind sockfd_two");
close(sockfd_two);
exit(-1);
}
close(sockfd_one);
close(sockfd_two);
return 0;
}
可以看到端口重復綁定導致了第二個套接字創建失敗,我們通過setsockopt系統調用在創建socket后設置端口可復用:
int opt = 1;
// sockfd為需要端口復用的套接字
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&opt, sizeof(opt));
具體如下:
#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[])
{
int sockfd_one;
int err_log;
sockfd_one = socket(AF_INET, SOCK_STREAM, 0); //創建UDP套接字one
if(sockfd_one < 0)
{
perror("sockfd_one");
exit(-1);
}
// 設置本地網絡信息
struct sockaddr_in my_addr;
bzero(&my_addr, sizeof(my_addr));
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(8000); // 端口為8000
my_addr.sin_addr.s_addr = htonl(INADDR_ANY);
// 在sockfd_one綁定bind之前,設置其端口復用
int opt = 1;
setsockopt( sockfd_one, SOL_SOCKET,SO_REUSEADDR,
(const void *)&opt, sizeof(opt) );
// 綁定,端口為8000
err_log = bind(sockfd_one, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind sockfd_one");
close(sockfd_one);
exit(-1);
}
int sockfd_two;
sockfd_two = socket(AF_INET, SOCK_STREAM, 0); //創建UDP套接字two
if(sockfd_two < 0)
{
perror("sockfd_two");
exit(-1);
}
// 在sockfd_two綁定bind之前,設置其端口復用
opt = 1;
setsockopt( sockfd_two, SOL_SOCKET,SO_REUSEADDR,
(const void *)&opt, sizeof(opt) );
// 新套接字sockfd_two,繼續綁定8000端口,成功
err_log = bind(sockfd_two, (struct sockaddr*)&my_addr, sizeof(my_addr));
if(err_log != 0)
{
perror("bind sockfd_two");
close(sockfd_two);
exit(-1);
}
printf("two socket create success!n");
close(sockfd_one);
close(sockfd_two);
return 0;
}
如上,兩個套接字綁定同一個端口都創建成功。下面將從bind出發分析bind是如何端口管理、復用的。
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
內核
+關注
關注
3文章
1363瀏覽量
40228 -
Linux
+關注
關注
87文章
11230瀏覽量
208937 -
系統
+關注
關注
1文章
1008瀏覽量
21316
發布評論請先 登錄
相關推薦
udp_bind這個綁定的端口怎么解除?
請教下,udp_bind 這個綁定的端口,剛開始是可以的,但是重新綁定時返回錯誤,有什么方法可以在 重新綁定前解除之前的綁定 ?
發表于 04-22 07:41
TCP server 不能 bind 80 端口?
后程序只開一個 AP 模式下的 TCP server ,測試。 ?但是發現 80 端口沒法 bind ,錯誤碼是 -98 ,意思是端口已被占用? 換一個其它端口號(比如 12345)就
發表于 05-14 00:33
端口復用概念
記錄一下,方便以后翻閱~主要內容:1)端口復用;2)端口重映射;官方資料:《STM32中文參考手冊V10》第8章 通用和復用功能IO(GPIO和AFIO)1.
發表于 01-11 07:43
Bind源代碼包安裝
先到官方下載Bind的安裝包 wgetftp://ftp.isc.org/isc/bind9/9.6.0-P1/bind-9.6.0-P1.tar.gz tar xzvf
發表于 04-04 20:30
?23次下載
STM32單片機端口復用和端口重映射
STM32單片機端口復用和端口重映射STM32單片機上有很多I/O口,也有很多的內置外設,比如I2C、ADC、DAC、USART等都屬于內置外設。這些內置外設基本都是與I/O口共用管腳的,也就是I
發表于 12-28 19:23
?8次下載
什么是bind?你真的熟悉bind嗎?
bind()方法創建一個新的函數,在bind()被調用時,這個新函數的this被指定 bind()的第一個參數,而其余參數將作為新函數的參數,供調用
網絡系統調用網絡套接字入口函數
網絡套接字入口函數 //所有的網絡套接字系統調用函數(socket bind listen connect )都使用一個共同的入口函數:sys_socketcall /* 第一個參數call表示被
Linux內核分析 bind端口選擇
給 bind 傳 遞的地址參數中,port 字段為 0,那么就會自動選擇參數。 如代碼所示,當端口port沒有指定時,調用inet_csk_find_open_port(sk, port): if (!port) { head
評論