《Linux網路程式設計》: 繫結( bind )埠需要注意的問題
阿新 • • 發佈:2019-01-04
所謂繫結(bind)是指別人連線我只能通過我所繫結的埠,相當於,我買了一個手機,別人要想聯絡我,必須要知道我的手機號碼,這時候,我需要怎麼辦呢?我需要給手機插上電話卡,固定一個電話號碼,這樣別人就能通過這個電話號碼聯絡我。手機插上電話卡,固定一個電話號碼,類似於繫結(bind)的過程,繫結(bind)為了固定一個埠號,別的網路程式就可以找到這個埠號,找到這個埠號就能找到這個埠號所對應的網路應用程式。
在網路程式設計裡,通常都是在伺服器裡繫結(bind)埠,這並不是說客戶端裡不能繫結(bind)埠,但這裡需要注意的是,一個網路應用程式只能繫結一個埠( 一個套接字只能 繫結一個埠 )。
一個套接字不能同時繫結多個埠,如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int argc, char *argv[]) { char server_ip[30] = "10.221.20.12"; int sockfd; sockfd = socket(AF_INET, SOCK_DGRAM, 0); //建立UDP套接字 if(sockfd < 0) { perror("socket"); exit(-1); } // 初始化本地網路資訊 struct sockaddr_in my_addr; bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(8000); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // 第一次繫結埠8000 int err_log; err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)); if(err_log != 0) { perror("bind 8000"); close(sockfd); exit(-1); } // 又一次繫結別的埠9000, 會繫結失敗 my_addr.sin_port = htons(9000); err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)); if(err_log != 0) { perror("bind 9000"); close(sockfd); exit(-1); } close(sockfd); return 0; }
程式編譯執行後結果如下:
如果客戶端想繫結埠號,一定要呼叫傳送資訊函式之前繫結( bind )埠,因為在傳送資訊函式( sendto, 或 write ),系統會自動給當前網路程式分配一個隨機埠號,這相當於隨機綁定了一個埠號,這裡只會分配一次,以後通訊就以這個隨機埠通訊,我們再繫結埠號的話,就會繫結失敗。如果我們放在傳送資訊函式( sendto, 或 write )之前繫結,那樣程式將以我們繫結的埠號傳送資訊,不會再隨機分配一個埠號。
繫結失敗例子( UDP )如下:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> int main(int argc, char *argv[]) { char server_ip[30] = "10.221.20.12"; int sockfd; sockfd = socket(AF_INET, SOCK_DGRAM, 0); //建立UDP套接字 if(sockfd < 0) { perror("socket"); exit(-1); } struct sockaddr_in dest_addr; bzero(&dest_addr, sizeof(dest_addr)); dest_addr.sin_family = AF_INET; dest_addr.sin_port = htons(8080); // 伺服器的埠 inet_pton(AF_INET, server_ip, &dest_addr.sin_addr); char send_buf[512] = "this is for test"; // 如果前面沒有繫結埠,sendto()系統會隨機分配一個埠 sendto(sockfd, send_buf, strlen(send_buf), 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));//傳送資料 // 初始化本地網路資訊 struct sockaddr_in my_addr; bzero(&my_addr, sizeof(my_addr)); my_addr.sin_family = AF_INET; my_addr.sin_port = htons(8000); my_addr.sin_addr.s_addr = htonl(INADDR_ANY); // sendto()後面繫結埠,繫結失敗 int err_log; err_log = bind(sockfd, (struct sockaddr*)&my_addr, sizeof(my_addr)); if(err_log != 0) { perror("bind 8000"); close(sockfd); exit(-1); } close(sockfd); return 0; }
程式編譯執行後結果如下: