結論:
1、採用TCP通信時,客戶端不需要bind()他自己的IP和端口號,而服務器必須要bind()自己本機的IP和端口號;
2、若採用UDP通信時(這裏是有客戶端和服務器之分才這麼說的,若是指定特定端口的UDP對等通信則不一樣了),客戶端也可以不需要bind()他自己的IP和端口號,而服務器需要bind自己IP地址和端口號;
原因:
1、
因爲服務器是時時在監聽有沒有客戶端的連接,如果服務器不綁定IP和端口的話,客戶端上線的時候怎麼連到服務器呢,所以服務器要綁定IP和端口,而客戶端就不需要了,客戶端上線是主動向服務器發出請求的,因爲服務器已經綁定了IP和端口,所以客戶端上線的就向這個IP和端口發出請求,這時因爲客戶開始發數據了(發上線請求),系統就給客戶端分配一個隨機端口,這個端口和客戶端的IP會隨着上線請求一起發給服務器,服務收到上線請求後就可以從中獲起發此請求的客戶的IP和端口,接下來服務器就可以利用獲起的IP和端口給客戶端迴應消息了。
2、採用UDP通信
1)若有客戶端和服務器之分的程序,創建sock後即可在該socket上用recvfrom/sendto方法發送接受數據了,因爲客戶端只需要用sendto發送數據到指定的地址,當然若是bind了,程序也沒什麼問題,區別就是系統用默認自動bind()指定你自己的socket參數地址(特別是在指定特定端口的UDP對等通信)只是這種情況沒有這樣用的。
那UDP服務器是怎麼知道客戶端的IP地址和UDP端口?
一般來說有兩種方式:
一種是客戶端發消息顯式地告訴服務器IP地址和端口,消息內容就包括IP地址和UDP端口。
另外一種就是隱式的,服務器從收到的包的頭部中得到包的源IP地址和端口。
2)若是沒有客戶端和服務器之分的程序,即自己指定特定端口的UDP對等通信,則客戶端和服務器都需要bind()IP地址和端口了。
通常udp服務端根本不需要知道客戶端的socket,它直接建立一個socket用於發送即可,udp通信的關鍵只在於IP和端口。
多個客戶端如果需要點到點分發,必須給服務端socket循環設置每個客戶端的IP併發出,但更常用的是廣播分發,服務端socket設定一個X.X.X.255的廣播地址並始終向它發送,每個客戶端建立的socket只需要綁定這個廣播地址便可以收到。
客戶端用不用bind 的區別
Bind()函數在成功被調用時返回0;出現錯誤時返回"-1"並將errno置爲相應的錯誤號。需要注意的是,在調用bind函數時一般不要將端口號置爲小於1024的值,因爲1到1024是保留端口號,你可以選擇大於1024中的任何一個沒有被佔用的端口號。
有連接的socket客戶端通過調用Connect函數在socket數據結構中保存本地和遠端信息,無須調用bind(),因爲這種情況下只需知道目的機器的IP地址,而客戶通過哪個端口與服務器建立連接並不需要關心,socket執行體爲你的程序自動選擇一個未被佔用的端口,並通知你的程序數據什麼時候打開端口。(當然也有特殊情況,linux系統中rlogin命令應當調用bind函數綁定一個未用的保留端口號,還有當客戶端需要用指定的網絡設備接口和端口號進行通信等等)
1.需要在建連前就知道端口的話,需要 bind
2.需要通過指定的端口來通訊的話,需要 bind
具體到上面那兩個程序,本來用的是TCP,客戶端就不用綁定端口了,綁定之後只能運行一個client 的程序,是屬於自己程序中人爲設定的障礙,而從服務器那邊得到的客戶機連接端口號(是系統自動分配的)與這邊客戶機綁定的端口號根本是不相關的,所以客戶 綁定也就失去了意義。
=======================================================
客戶端調用bind 的作用及UDP客戶端調用connect 的問題
在水木上看到一個關於在客戶端調用bind的討論,
- 1.#include <sys/socket.h>
- 2.#include <unistd.h>
- 3.#include <string.h>
- 4.#include <stdio.h>
- 5.#include <arpa/inet.h>
- 6.#include <stdlib.h>
- 7.
- 8.#define MAXLINE 80
- 9.#define SERV_PORT 8888
- 10.
- 11.struct sockaddr_in servaddr;
- 12.
- 13.void do_cli(FILE *fp,int sockfd,struct sockaddr *pservaddr,socklen_t servlen)
- 14.{
- 15. int n;
- 16. char sendline[MAXLINE],recvline[MAXLINE + 1];
- 17.
- 18. #ifdef UDP_CONNECT
- 19. /* connect to server */
- 20. if(connect(sockfd,(struct sockaddr *)pservaddr,servlen) == -1)
- 21. {
- 22. perror("connect error");
- 23. exit(1);
- 24. }
- 25. #endif
- 26.
- 27. while(fgets(sendline,MAXLINE,fp) != NULL)
- 28. {
- 29. #ifdef UDP_CONNECT
- 30. /* read a line and send to server */
- 31. write(sockfd,sendline,strlen(sendline));
- 32. #else
- 33. sendto(sockfd, sendline, strlen(sendline), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
- 34. #endif
- 35.
- 36. printf("write over\n");
- 37. /* receive data from server */
- 38. n = read(sockfd,recvline,MAXLINE);
- 39. if(n == -1)
- 40. {
- 41.
- 42. perror("read error");
- 43. exit(1);
- 44. }
- 45. recvline[n] = 0; /* terminate string */
- 46. fputs(recvline,stdout);
- 47. }
- 48.}
- 49.
- 50.int main(int argc,char **argv)
- 51.{
- 52. int sockfd;
- 53.
- 54. /* check args */
- 55. if(argc != 2)
- 56. {
- 57. printf("usage: udpclient serverip\n");
- 58. exit(1);
- 59. }
- 60.
- 61. /* init servaddr */
- 62. bzero(&servaddr,sizeof(servaddr));
- 63. servaddr.sin_family = AF_INET;
- 64. servaddr.sin_port = htons(SERV_PORT);
- 65. if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr) <= 0)
- 66. {
- 67. printf("[%s] is not a valid IPaddress\n",argv[1]);
- 68. exit(1);
- 69. }
- 70. sockfd = socket(AF_INET,SOCK_DGRAM,0);
- 71. do_cli(stdin,sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
- 72. return 0;
- 73.}