之前在TCP/IP的網絡通信的學習中,主要關注的都是高併發,高性能的方面,忽略了一些基本的概念,特別是端口這個東西,這個東西在服務器開發過程中可能看起來也不是很麻煩,在服務器上就是一個bind(),在客戶端指定一下目標端口就行了,也沒有太深入理解其中的東西,今天就來好好的總結梳理一下。
還是以服務器和客戶端的會話爲例,什麼是端口呢?如果把IP地址比作一間房子 ,端口就是出入這間房子的門。真正的房子只有幾個門,但是一個IP地址的端口 可以有65536(即:256×256)個之多!端口是通過端口號來標記的,端口號只有整數,範圍是從0 到65535(256×256-1)。端口其實就是隊,操作系統爲各個進程分配了不同的隊,數據包按照目的端口被推入相應的隊中,等待被進程取用,在極特殊的情況下,這個隊也是有可能溢出的,不過操作系統允許各進程指定和調整自己的隊的大小。一個數據包包括了文件,ip,和端口號,ip是爲了服務器可以找到你的主機,端口號是你接受數據包的門戶, 而所謂的端口監聽,是指主機網絡進程接受到IP數據包後,察看其的目標端口是不是自己的端口號,如果是的話就接受該數據包進行處理。
我們在linux環境來查看一下端口使用情況:
輸入命令netstat -tunap(-t 表示顯示tcp相關 -u表示顯示udp相關 -n表示拒絕顯示別名,能顯示數字全部轉換爲數字 -a表示顯示所有狀態的,-l則表示顯示listen狀態的 不輸入則表示顯示established狀態的 -p表示顯示建立相關鏈接的程序名),效果如下
在ip地址後的冒號,如這個,0.0.0.0表示ip,表示111端口號。
什麼時候需要使用到端口這個東西呢?
1、採用TCP通信時,客戶端不需要bind()他自己的IP和端口號,而服務器必須要bind()自己本機的IP和端口號;
2、若採用UDP通信時(這裏是有客戶端和服務器之分才這麼說的,若是指定特定端口的UDP對等通信則不一樣了),客戶端也可以不需要bind()他自己的IP和端口號,而服務器需要bind自己IP地址和端口號;
再說下客戶端用不用bind的區別
Bind()函數在成功被調用時返回0;出現錯誤時返回"-1"並將errno置爲相應的錯誤號。需要注意的是,在調用bind函數時一般不要將端口號置爲小於1024的值,因爲1到1024是保留端口號,你可以選擇大於1024中的任何一個沒有被佔用的端口號。
有連接的socket客戶端通過調用Connect函數在socket數據結構中保存本地和遠端信息,無須調用bind(),因爲這種情況下只需知道目的機器的IP地址,而客戶通過哪個端口與服務器建立連接並不需要關心,socket執行體爲你的程序自動選擇一個未被佔用的端口,並通知你的程序數據什麼時候打開端口。(當然也有特殊情況,linux系統中rlogin命令應當調用bind函數綁定一個未用的保留端口號,還有當客戶端需要用指定的網絡設備接口和端口號進行通信等等)
1.需要在建連前就知道端口的話,需要 bind
2.需要通過指定的端口來通訊的話,需要 bind
再說一個問題,爲什麼你用瀏覽器打開一個網站不需要輸入端口呢?不是說好客戶端訪問服務器需要指定端口號的嗎?其實,是你的瀏覽器默認幫助你的ip地址後面加上了:80,80端口是默認的http端口,所以就不需要你輸入網址時加端口啦,如果你自己搭建了一個服務器,比如nginx,你把config文件裏的listen端口改成其他端口,你看你的瀏覽器還是否能夠不加端口訪問。