閱讀257 返回首頁    go 技術社區[雲棲]


關於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.1192.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

  1. 啟動綁定在通配ip和1234端口的服務端程序
  2. 使用 telnet 127.0.0.1 1234命令連接服務端
  3. 服務端顯示

    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

  4. 使用 telnet 192.168.0.102 1234 連接服務端

  5. 服務端顯示

    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

  1. 反注釋以下代碼,啟動服務端程序 c // char *host = "127.0.0.1"; // inet_pton(AF_INET, host, &server_addr.sin_addr);
  2. 使用 telnet 127.0.0.1 1234命令連接服務端
  3. 服務端顯示 > 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
  4. 使用 telnet 192.168.0.102 1234 連接服務端
  5. 客戶端顯示 > 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

  上一篇:go  記一個自己項目上線的全過程
  下一篇:go  雲服務器的優勢(阿裏雲)