很久之前寫過以上:套接字socket的底層來龍去脈、sockfs文件系統(tǒng)的實現(xiàn),可以作為本文的前置知識進行學習瀏覽。
先來一張本文中核心的一張圖,具體可以看后面文章的解釋:

本文從socket的bind系統(tǒng)調用進行分析,主要是了解一下bind背后,Linux內核是如何進行端口綁定、如何管理本地眾多的端口號。
先直觀感受bind系統(tǒng)調用背后的端口管理、端口復用
#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); //創(chuàng)建TCP套接字one
if(sockfd_one < 0)
{
perror("sockfd_one");
exit(-1);
}
// 設置本地網(wǎng)絡信息
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); //創(chuàng)建TCP套接字two
if(sockfd_two < 0)
{
perror("sockfd_two");
exit(-1);
}
// 新套接字sockfd_two,繼續(xù)綁定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;
}

可以看到端口重復綁定導致了第二個套接字創(chuàng)建失敗,我們通過setsockopt系統(tǒng)調用在創(chuàng)建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); //創(chuàng)建UDP套接字one
if(sockfd_one < 0)
{
perror("sockfd_one");
exit(-1);
}
// 設置本地網(wǎng)絡信息
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); //創(chuàng)建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,繼續(xù)綁定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;
}

如上,兩個套接字綁定同一個端口都創(chuàng)建成功。下面將從bind出發(fā)分析bind是如何端口管理、復用的。
-
內核
+關注
關注
4文章
1436瀏覽量
42470 -
Linux
+關注
關注
88文章
11622瀏覽量
217831 -
系統(tǒng)
+關注
關注
1文章
1043瀏覽量
22163
發(fā)布評論請先 登錄
udp_bind這個綁定的端口怎么解除?
TCP server 不能 bind 80 端口?
端口復用概念
Bind源代碼包安裝
STM32單片機端口復用和端口重映射

bind系統(tǒng)調用背后的端口管理復用
評論