面向鏈接的網絡應用程序分爲客戶端和服務器端。服務器端的執行流程通常爲4步,客戶端程序相對簡單,通常須要兩個步驟。服務器
服務器端執行流程4步以下:網絡
(1)調用socket函數,創建一個套接字,該套接字用於接下來的網絡通訊。socket
(2)調用bind函數,將該套接字綁定到一個地址,並制定一個端口號,函數
(3)調用listen函數,使用該套接字監聽鏈接請求spa
(4)當請求來到時,調用accept函數複製該套接字處理請求code
客戶端執行流程2步以下:blog
(1)調用socket函數,建立一個套接字進程
(2)調用connect函數使用該套接字與服務器進行鏈接ci
服務器端和客戶端程序的顯著區別在於客戶端程序不須要調用bind函數,bind函數的做用是將套接字綁定一個IP地址和端口號,由於這兩個元素能夠在網絡環境中惟一地址表示一個進程。若是套接字沒有使用bind函數綁定地址和端口,那麼調用listen函數和connect函數的時候內核會自動爲套接字綁定。由此可知,若是沒有使用bind函數,調用listen函數和connect函數的時候內核會自動爲套接字綁定。看起來好像bind函數是多餘的,但事實並非這樣。字符串
咱們先來看看listen函數和connect是怎麼綁定套接字的,connect函數綁定套接字的時候使用的是一個設置好的地址結構(sockaddr_in)做爲參數,結構中指定了服務器的地址和須要通訊的端口號。可是listen函數沒有這個參數,多以listen函數不可以使用設置好的地址結構,只能由系統設置IP地址和端口號。也就是說在服務器端,若是不使用bind函數的話,建立套接字時使用的是當前系統中空閒端口的套接字。
這樣的話,服務器端的程序不關心客戶端的IP地址,也就說是對應的端口號是內核臨時指派的一個端口,是隨機的,每次執行服務器程序的時候,使用的都是不一樣的端口。可是在客戶端是須要指定通訊的服務器的端口的,若是不使用bind函數,每次的端口是隨機的話,那麼每次重啓服務程序以後都要對客戶端的程序進行調整,這樣作不只不合理,並且工做量很大,所以在服務器端bind函數做用很是重要。
下面是一個使用bind函數的服務器端程序,能夠做爲參考理解。
#include <stdio.h> #include <unistd.h> #include <string.h> #include <stdlib.h> #include <strings.h> #include <ctype.h> #include <sys/socket.h> #include <arpa/inet.h> #define MAX_LINE 100 int main(void) { struct sockaddr_in sin; struct sockaddr_in cin; int l_fd; int c_fd; socklen_t len; char buf[MAX_LINE]; char addr_p[INET_ADDRSTRLEN]; int port = 8000; int n; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); /*創立套接字,使用TCP協議*/ if((l_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("fail to creat socket"); exit(1); } /*將地址和套節字綁定*/ if(bind(l_fd, (struct sockaddr *) &sin, sizeof(sin)) == -1) { perror("fail to bind"); exit(1); } /*開始監聽鏈接請求*/ if(listen(l_fd, 10) == -1) { perror("fail to listren"); exit(1); } printf("waiting...\n"); while(1) { /*接受鏈接請求,今後函數中返回後就能夠開始通訊了*/ if((c_fd = accept(l_fd, (struct sockaddr *) &cin, &len)) == -1) { perror("fail to accept"); exit(1); } /*調用recv函數讀取客戶端傳來的信息,不設置任何特殊的標誌*/ n = recv(c_fd, buf, MAX_LINE, 0); if(n = -1) { perror("fail to receive"); exit(1); } else if(n == 0) { printf("the connect has been closed\n "); close(c_fd); continue; } /*將客戶端地址轉換爲字符串*/ inet_ntop(AF_INET, &cin.sin_addr, addr_p, sizeof(addr_p)); printf("client IP is %s, port is %s \n", addr_p, ntohs(cin.sin_port)); printf("connect is : %s\n", buf); n = strlen(buf); sprintf(buf, "%d", n); /*使用send函數將轉換後的字符串發送給客戶端,不設置任何特殊的標誌*/ n = send(c_fd, buf, strlen(buf) + 1, 0); if(n == -1) { perror("fail to send"); exit(1); } if(cloes(c_fd) == -1) { perror("fail to close"); exit(1); } } return 0; }