# 網絡,第 5 部分:關閉端口,重用端口和其他技巧
> 原文:<https://github.com/angrave/SystemProgramming/wiki/Networking%2C-Part-5%3A-Shutting-down-ports%2C-reusing-ports-and-other-tricks>
## 關閉和關閉有什么區別?
當您不再需要從套接字讀取更多數據,寫入更多數據或完成這兩項操作時,請使用`shutdown`調用。當您關閉套接字以進一步寫入(或讀取)時,該信息也會發送到連接的另一端。例如,如果您關閉套接字以便在服務器端進一步寫入,那么片刻之后,阻塞的`read`調用可能會返回 0 以指示不再需要更多字節。
當您的進程不再需要套接字文件描述符時,請使用`close`。
如果在創建套接字文件描述符后`fork` -ed,則所有進程都需要關閉套接字才能重新使用套接字資源。如果關閉套接字以進一步讀取,那么所有進程都會受到影響,因為您已經更改了套接字,而不僅僅是文件描述符。
編寫好的代碼會在調用`close`之前將`shutdown`作為套接字。
## 當我重新運行我的服務器代碼時,它不起作用!為什么?
默認情況下,在套接字關閉后,端口進入超時狀態,在此期間無法重新使用(“綁定到新套接字”)。
通過在綁定到端口之前設置套接字選項 REUSEPORT 可以禁用此行為:
```c
int optval = 1;
setsockopt(sock_fd, SOL_SOCKET, SO_REUSEPORT, &optval, sizeof(optval));
bind(sock_fd, ...);
```
## TCP 客戶端可以綁定到特定端口嗎?
是!實際上,傳出的 TCP 連接會自動綁定到客戶端上未使用的端口。通常不必在客戶端上明確設置端口,因為系統將智能地在合理的接口上找到不可用的端口(例如,如果當前通過 WiFi 連接連接,則為無線卡)。但是,如果您需要專門選擇特定的以太網卡,或者防火墻僅允許來自特定范圍的端口值的傳出連接,則它可能很有用。
要顯式綁定到以太網接口和端口,請在`connect`之前調用`bind`
## 誰連接到我的服務器?
`accept`系統調用可以選擇通過傳入 sockaddr 結構來提供有關遠程客戶端的信息。不同的協議具有`struct sockaddr`的不同變體,它們具有不同的大小。最簡單的結構是`sockaddr_storage`,它足夠大以代表所有可能類型的 sockaddr。請注意,C 沒有任何繼承模型。因此,我們需要將結構顯式地轉換為'base type'結構 sockaddr。
```c
struct sockaddr_storage clientaddr;
socklen_t clientaddrsize = sizeof(clientaddr);
int client_id = accept(passive_socket,
(struct sockaddr *) &clientaddr,
&clientaddrsize);
```
我們已經看到`getaddrinfo`可以構建 addrinfo 條目的鏈接列表(并且每個條目中的每一個都可以包括套接字配置數據)。如果我們想將套接字數據轉換為 IP 和端口地址怎么辦?輸入`getnameinfo`,可用于將本地或遠程套接字信息轉換為域名或數字 IP。類似地,端口號可以表示為服務名稱(例如,端口 80 的“http”)。在下面的示例中,我們請求客??戶端 IP 地址和客戶端端口號的數字版本。
```c
socklen_t clientaddrsize = sizeof(clientaddr);
int client_id = accept(sock_id, (struct sockaddr *) &clientaddr, &clientaddrsize);
char host[256], port[256];
getnameinfo((struct sockaddr *) &clientaddr,
clientaddrsize, host, sizeof(host), port, sizeof(port),
NI_NUMERICHOST | NI_NUMERICSERV);
```
Todo:討論 NI_MAXHOST 和 NI_MAXSERV 以及 NI_NUMERICHOST
## getnameinfo 示例:我的 IP 地址是什么?
要獲取當前計算機的 IP 地址的鏈接列表,請使用`getifaddrs`,它將返回 IPv4 和 IPv6 IP 地址的鏈接列表(以及可能還有其他接口)。我們可以檢查每個條目并使用`getnameinfo`打印主機的 IP 地址。 ifaddrs 結構包括族,但不包括結構的大小。因此,我們需要手動確定基于系列的結構大小(IPv4 v IPv6)
```c
(family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)
```
完整的代碼如下所示。
```c
int required_family = AF_INET; // Change to AF_INET6 for IPv6
struct ifaddrs *myaddrs, *ifa;
getifaddrs(&myaddrs);
char host[256], port[256];
for (ifa = myaddrs; ifa != NULL; ifa = ifa->ifa_next) {
int family = ifa->ifa_addr->sa_family;
if (family == required_family && ifa->ifa_addr) {
if (0 == getnameinfo(ifa->ifa_addr,
(family == AF_INET) ? sizeof(struct sockaddr_in) :
sizeof(struct sockaddr_in6),
host, sizeof(host), port, sizeof(port)
, NI_NUMERICHOST | NI_NUMERICSERV ))
puts(host);
}
}
```
## 什么是我機器的 IP 地址(shell 版本)
答案:使用`ifconfig`(或 Windows 的 ipconfig)但是這個命令會為每個接口生成大量輸出,所以我們可以使用 grep 過濾輸出
```
ifconfig | grep inet
Example output:
inet6 fe80::1%lo0 prefixlen 64 scopeid 0x1
inet 127.0.0.1 netmask 0xff000000
inet6 ::1 prefixlen 128
inet6 fe80::7256:81ff:fe9a:9141%en1 prefixlen 64 scopeid 0x5
inet 192.168.1.100 netmask 0xffffff00 broadcast 192.168.1.255
```
- UIUC CS241 系統編程中文講義
- 0. 簡介
- #Informal 詞匯表
- #Piazza:何時以及如何尋求幫助
- 編程技巧,第 1 部分
- 系統編程短篇小說和歌曲
- 1.學習 C
- C 編程,第 1 部分:簡介
- C 編程,第 2 部分:文本輸入和輸出
- C 編程,第 3 部分:常見問題
- C 編程,第 4 部分:字符串和結構
- C 編程,第 5 部分:調試
- C 編程,復習題
- 2.進程
- 進程,第 1 部分:簡介
- 分叉,第 1 部分:簡介
- 分叉,第 2 部分:Fork,Exec,等等
- 進程控制,第 1 部分:使用信號等待宏
- 進程復習題
- 3.內存和分配器
- 內存,第 1 部分:堆內存簡介
- 內存,第 2 部分:實現內存分配器
- 內存,第 3 部分:粉碎堆棧示例
- 內存復習題
- 4.介紹 Pthreads
- Pthreads,第 1 部分:簡介
- Pthreads,第 2 部分:實踐中的用法
- Pthreads,第 3 部分:并行問題(獎金)
- Pthread 復習題
- 5.同步
- 同步,第 1 部分:互斥鎖
- 同步,第 2 部分:計算信號量
- 同步,第 3 部分:使用互斥鎖和信號量
- 同步,第 4 部分:臨界區問題
- 同步,第 5 部分:條件變量
- 同步,第 6 部分:實現障礙
- 同步,第 7 部分:讀者編寫器問題
- 同步,第 8 部分:環形緩沖區示例
- 同步復習題
- 6.死鎖
- 死鎖,第 1 部分:資源分配圖
- 死鎖,第 2 部分:死鎖條件
- 死鎖,第 3 部分:餐飲哲學家
- 死鎖復習題
- 7.進程間通信&amp;調度
- 虛擬內存,第 1 部分:虛擬內存簡介
- 管道,第 1 部分:管道介紹
- 管道,第 2 部分:管道編程秘密
- 文件,第 1 部分:使用文件
- 調度,第 1 部分:調度過程
- 調度,第 2 部分:調度過程:算法
- IPC 復習題
- 8.網絡
- POSIX,第 1 部分:錯誤處理
- 網絡,第 1 部分:簡介
- 網絡,第 2 部分:使用 getaddrinfo
- 網絡,第 3 部分:構建一個簡單的 TCP 客戶端
- 網絡,第 4 部分:構建一個簡單的 TCP 服務器
- 網絡,第 5 部分:關閉端口,重用端口和其他技巧
- 網絡,第 6 部分:創建 UDP 服務器
- 網絡,第 7 部分:非阻塞 I O,select()和 epoll
- RPC,第 1 部分:遠程過程調用簡介
- 網絡復習題
- 9.文件系統
- 文件系統,第 1 部分:簡介
- 文件系統,第 2 部分:文件是 inode(其他一切只是數據...)
- 文件系統,第 3 部分:權限
- 文件系統,第 4 部分:使用目錄
- 文件系統,第 5 部分:虛擬文件系統
- 文件系統,第 6 部分:內存映射文件和共享內存
- 文件系統,第 7 部分:可擴展且可靠的文件系統
- 文件系統,第 8 部分:從 Android 設備中刪除預裝的惡意軟件
- 文件系統,第 9 部分:磁盤塊示例
- 文件系統復習題
- 10.信號
- 過程控制,第 1 部分:使用信號等待宏
- 信號,第 2 部分:待處理的信號和信號掩碼
- 信號,第 3 部分:提高信號
- 信號,第 4 部分:信號
- 信號復習題
- 考試練習題
- 考試主題
- C 編程:復習題
- 多線程編程:復習題
- 同步概念:復習題
- 記憶:復習題
- 管道:復習題
- 文件系統:復習題
- 網絡:復習題
- 信號:復習題
- 系統編程笑話