257
技術社區[雲棲]
關於socket bind的理解
使用bind
函數綁定ip和端口時有如下幾種可能:
ip地址 | 端口 | 結果 |
---|---|---|
通配地址 | 0 | 內核選擇ip地址和端口 |
通配地址 | 非0 | 內核選擇ip地址,進程指定端口 |
本地ip地址 | 0 | 進程指定ip地址,內核選擇端口 |
本地ip地址 | 非0 | 進程指定ip地址和端口 |
使用規則:
1. 服務器進程一般在啟動時都會bind
某個端口(例如 http的80端口),而客戶端進程都不會指定端口。若未調用bind
接口,則內核會為其指定一個臨時端口。
服務端進程也有不指定端口的case,比如rpc服務。服務端進程在
listen
後向rpc服務注冊進程
注冊自己的地址和端口。rpc客戶端隻需要向rpc服務注冊進程
請求對應的服務,即可返回rpc服務的ip和port信息。
2. 若指定ip地址,則該ip地址必須是屬於其主機的網絡接口之一(127.0.0.1
,網卡eth0地址192.168.0.102
,其他網卡地址)。
對於tcp客戶端來說,其指定發送ip數據報的源地址
對於tcp服務端來說,其限定了該socket隻接收目的地址為該ip的connect請求。
若tcp服務端不指定ip,內核會把客戶端發送的syn的目的地址作為服務端的源地址(該connect socket的源地址)
**注:一個listen socket可以accept多個socket連接,accept返回的connect socket的源地址可能為127.0.0.1
,192.168.0.102
,或者其他本機ip **
下麵用代碼證實下:
一般,啟動服務器監聽的代碼如下:
// 服務端代碼
int listenfd, connfd;
struct sockaddr_in server_addr;
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&server_addr, sizeof(server_addr));
// 必須是網絡序
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
server_addr.sin_port = htons(1234);
// 指定ip
// char *host = "127.0.0.1";
// inet_pton(AF_INET, host, &server_addr.sin_addr);
Bind(listenfd, (SA*)&server_addr, sizeof(server_addr));
Listen(listenfd, LISTENQ);
while (1) {
len = sizeof(cli_addr);
connfd = Accept(listenfd, (SA*)&cli_addr, &len);
printf("connect from %s, port:%d\n",
inet_ntop(AF_INET, &cli_addr.sin_addr, buffer, sizeof(buffer)),
ntohs(cli_addr.sin_port));
struct sockaddr_in peer_addr, local_addr;
// 獲取connect fd 的本機ip和port
int err = getsockname(connfd, (SA *)&local_addr, &len);
if (err >=0 ) {
printf("sock name %s, port:%d\n",
inet_ntop(AF_INET, &local_addr.sin_addr, buffer, sizeof(buffer)), ntohs(local_addr.sin_port));
}
// 獲取客戶端的本機ip和port
err = getpeername(connfd, (SA*) &peer_addr, &len);
if (err >=0 ) {
printf("peer sock name %s, port:%d\n",
inet_ntop(AF_INET, &peer_addr.sin_addr, buffer, sizeof(buffer)), ntohs(peer_addr.sin_port));
}
}
服務端程序綁定在通配ip
- 啟動綁定在通配ip和1234端口的服務端程序
- 使用
telnet 127.0.0.1 1234
命令連接服務端 -
服務端顯示
connect from 127.0.0.1, port:58271
sock name 127.0.0.1, port:1234
peer sock name 127.0.0.1, port:58271 使用
telnet 192.168.0.102 1234
連接服務端-
服務端顯示
connect from 192.168.0.102, port:58282
sock name 192.168.0.102, port:1234
peer sock name 192.168.0.102, port:58282
服務端程序綁定在 127.0.0.1
- 反注釋以下代碼,啟動服務端程序
c // char *host = "127.0.0.1"; // inet_pton(AF_INET, host, &server_addr.sin_addr);
- 使用
telnet 127.0.0.1 1234
命令連接服務端 - 服務端顯示 > connect from 127.0.0.1, port:58271 sock name 127.0.0.1, port:1234 peer sock name 127.0.0.1, port:58271
- 使用
telnet 192.168.0.102 1234
連接服務端 - 客戶端顯示 > telnet: connect to address 192.168.0.102: Connection refused telnet: Unable to connect to remote host
注:telnet 操作相當於connect指定了服務端的ip和port
最後更新:2017-10-16 09:33:23