網站首頁 編程語言 正文
正文
當你創建了socket之后,你會想要把這個socket和你本機上的某個端口號(port)進行關聯。
端口號是內核用來確認將收到的數據包交給哪個具體進程的socket descriptor
的依據。
通常在寫服務端程序的時候我們才需要進行關聯,客戶端程序不需要我們手動綁定端口,直接connect()
就好了。
端口號具體是怎么綁定
#include <sys/types.h> #include <sys/socket.h> int bind(int sockfd, struct sockaddr *my_addr, int addrlen);
sockfd
是socket()
返回的一個socket file descriptor
;my_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_in6
的sin6_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
相關推薦
- 2022-03-03 百度地圖 添加 左鍵菜單 Cannot read property 'remove' of unde
- 2022-05-13 error hawk@0.10.2: The engine “node“ is incompatib
- 2022-08-02 深入了解Golang的map增量擴容_Golang
- 2024-03-07 做springboot-分模塊技術時新建立Maven模塊時報錯
- 2022-05-05 docker中通過nginx+confd動態生成配置的解決方案_docker
- 2022-08-26 C#中WPF內存回收與釋放LierdaCracker的實現_C#教程
- 2024-03-22 springboot 中 Getmapping獲取參數的方式
- 2022-09-24 ASP.NET?MVC實現文件下載_實用技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支