日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

socket編程之bind()函數使用示例詳解_C 語言

作者:蟬沐風 ? 更新時間: 2022-11-24 編程語言

正文

當你創建了socket之后,你會想要把這個socket和你本機上的某個端口號(port)進行關聯。

端口號是內核用來確認將收到的數據包交給哪個具體進程的socket descriptor的依據。

通常在寫服務端程序的時候我們才需要進行關聯,客戶端程序不需要我們手動綁定端口,直接connect()就好了。

端口號具體是怎么綁定

#include <sys/types.h>
#include <sys/socket.h>
int bind(int sockfd, struct sockaddr *my_addr, int addrlen);

sockfdsocket()返回的一個socket file descriptormy_addr是一個指向包含了你的端口號和IP地址信息的struct sockaddr指針;addrlen是以字節為單位的地址長度。

接下來,我們給出一個例子,它將socket和我本機的3490端口進行綁定:

struct addrinfo hints, *res;
int sockfd;
// first, load up address structs with getaddrinfo():
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;  // use IPv4 or IPv6, whichever
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;     // fill in my IP for me
getaddrinfo(NULL, "3490", &hints, &res);
// make a socket:
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
// bind it to the port we passed in to getaddrinfo():
bind(sockfd, res->ai_addr, res->ai_addrlen);

通過使用AI_PASSIVE標識,程序會自動綁定它所在的程序的IP。如果你想精確綁定到本機的某一個IP地址,你就不能用AI_PASSIVE了,而且你還得把getaddrinfo()的第一個參數從NULL改為你想綁定的那個IP地址。

bind()和其他系統調用一樣,發生錯誤的時候返回-1,并且會設置全局變量errno的值。

很多老代碼都會在調用bind()之前手動封裝 struct sockaddr_in 。當然,這里綁定的肯定是IPv4的地址,如果你想使用IPv6,你照樣可以手動封裝struct sockaddr_in6 ,但是極力不推薦你這么做。你還是應該老老實實用 getaddrinfo() ,這樣更優雅、更簡單。

老代碼

// !!! THIS IS THE OLD WAY !!!
int sockfd;
struct sockaddr_in my_addr;
sockfd = socket(PF_INET, SOCK_STREAM, 0);
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(MYPORT);     // short, network byte order
my_addr.sin_addr.s_addr = inet_addr("10.12.110.57");
memset(my_addr.sin_zero, '\0', sizeof my_addr.sin_zero);
bind(sockfd, (struct sockaddr *)&my_addr, sizeof my_addr);

上面這個代碼中,你依然可以把my_addr.sin_addr.s_addr設置為 INADDR_ANY ,它的作用上文提到的AI_PASSIVE一樣,都會讓代碼自動綁定到本機IP。 INADDR_ANY 的IPv6版本是一個全局變量,叫in6addr_any,這個變量會被指定給你的 struct sockaddr_in6sin6_addr字段。

你也可以使用IN6ADDR_ANY_INIT這個宏來初始化變量

調用bind()時有一件事需要你特別注意:不要使用1024以下的端口號,因為這些端口號是被保留使用的,除非你是超級管理員。除了1024以下的,1025~65535之間的隨便用(其他程序占用的除外)。

有時候,你明明重新運行了你的服務端程序,但是bind()報錯了,提示你“Address already in use”。這是為什么?理論上重啟之后端口就會被釋放??!好吧,這是因為有一些連接到socket的連接還懸在內核中,就是它們占用了這個端口號。

端口被占用的問題解決

你可以等一分鐘左右讓它們自行消失,或者在你的代碼加這么幾行:

int yes=1;
//char yes='1'; // Solaris people use this
// lose the pesky "Address already in use" error message
if (setsockopt(listener,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof yes) == -1) {
    perror("setsockopt");
    exit(1);
} 

這樣就不會再出現端口被占用的問題了。

原文鏈接:https://juejin.cn/post/7153559249354752013

欄目分類
最近更新