預備知識
2) 註冊埠(registered ports):從1024到49151。它們鬆散地繫結於一些服務。也就是說有許多服務繫結於這些埠,這些埠同樣用於許多其它目的。例如:許多系統處理動態埠從1024左右開始。
3) 動態和/或私有埠(dynamic and/or private ports):從49152到65535。理論上,不應為服務分配這些埠。實際上,機器通常從1024起分配動態埠。但也有例外:sun的rpc埠從32768開始。
使用
tcp與udp段結構中埠位址都是16位元,可以有在0—65535範圍內的埠號。對於這65536個埠號有以下的使用規定:
(1)埠號小於256的定義為常用埠,伺服器一般都是通過常用埠號來識別的。任何tcp/ip實現所提供的服務都用1—1023之間的埠號,是由icann來管理的;
(2)客戶端只需保證該埠號在本機上是惟一的就可以了。客戶端口號因存在時間很短暫又稱臨時埠號;
(3)大多數tcp/ip實現給臨時埠號分配1024—5000之間的埠號。大於5000的埠號是為其他伺服器預留的。
伺服器端原始碼:
#include
#include
#include
#include
#include
#include
int startup(const
char* ip,int port) //建立監聽套接字
struct sockaddr_in server;
server.sin_family=af_inet;
server.sin_addr.s_addr=inet_addr(ip);
server.sin_port=htons(port);
socklen_t len=sizeof(server);
if(bind(sock,(struct sockaddr*)&server,len)<0)// 將套接字繫結到伺服器的網路位址上
if(listen(sock,5)<0)// 建立監聽佇列
return sock;
}int main(int argc,char* argv)
int listen_sock=startup(argv[1],atoi(argv[2]));
struct sockaddr_in remote;
socklen_t relen=sizeof(remote);
while(1) //接收連線
printf("client's ip is %s,port is %d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
char buf[1024];
while(1)
else
}close(ret);
}return
0;}
客戶端原始碼:
#include
#include
#include
#include
#include
#include
int main(int argc,char* argv)
int sock=socket(af_inet,sock_stream,0);// 建立客戶端socket
if(sock<0)
struct sockaddr_in server; // 伺服器端網路位址結構
server.sin_family=af_inet;
server.sin_addr.s_addr=inet_addr(argv[1]);
server.sin_port=htons(atoi(argv[2]));
socklen_t len=sizeof(server);
// 與遠端伺服器建立連線
if(connect(sock,(struct sockaddr*)&server,len)<0)
char buf[1024];
while(1)
}close(sock);
return
0;}
執行程式時,會發現乙個現象,當先ctrl+c掉伺服器程序時,再次啟動伺服器程序會出現bind: address already in use的錯誤提示。
錯誤原因如下:
bind 試圖繫結乙個已經在使用的埠。該陷阱也許沒有活動的套接字存在,但仍然禁止繫結埠(bind 返回 eaddrinuse),它由 tcp 套接字狀態 time_wait 引起。該狀態在套接字關閉後約保留 2 到 4 分鐘(2msl)。在 time_wait 狀態退出之後,套接字被刪除,該位址才能被重新繫結而不出問題。
那如果正在開發乙個套接字伺服器,就需要停止伺服器來做一些改動,然後重啟,這種情況就比較麻煩了。但是是有解決方法的:給套接字應用 so_reuseaddr 套接字選項,以便埠可以馬上重用。
伺服器程序修改如下:
#include
#include
#include
#include
#include
#include
int startup(const
char* ip,int port) //建立監聽套階字
struct sockaddr_in server;
server.sin_family=af_inet;
server.sin_addr.s_addr=inet_addr(ip);
server.sin_port=htons(port);
socklen_t len=sizeof(server);
int on=1;
if((setsockopt(sock,sol_socket,so_reuseaddr,&on,sizeof(on)))<0)
if(bind(sock,(struct sockaddr*)&server,len)<0)
if(listen(sock,5)<0)
return sock;
}int main(int argc,char* argv)
int listen_sock=startup(argv[1],atoi(argv[2]));
struct sockaddr_in remote;
socklen_t relen=sizeof(remote);
while(1) //接收連線
printf("client's ip is %s,port is %d\n",inet_ntoa(remote.sin_addr),ntohs(remote.sin_port));
char buf[1024];
while(1)
else
}close(ret);
}return
0;}
此時再次執行程式,先ctrl+c掉伺服器程序,然後再次執行不會再報錯。
你也許會發現,伺服器在建立套接字之後使用了bind函式將sockfd這個⽤於⽹絡通訊的⽂件描述符監聽myaddr所描述的位址和埠號繫結在一起。而客戶端程序並沒有bind。
這是因為,客戶端通過呼叫connect函式在socket資料結構中儲存本地和遠端資訊,無須呼叫bind(),因為這種情況下只需知道目的機器的ip位址,而客戶通過哪個埠與伺服器建立連線並不需要關心,socket執行體為你的程式自動選擇乙個未被占用的埠,並通知你的程式資料什麼時候開啟埠。
計算機網路實驗 UDP套接字程式設計
我用自己的ubuntu16.04來舉例,實驗室的是虛擬機器,差不多 只針對第三個題目,修改伺服器來通過響應客戶端傳送的gettime並傳送給客戶端當前系統時間。ubuntu16.04介面就不說了。我只是多下了chrome,藍燈和uget 建立檔案敲 不知道你自己會把 放在 所以這一步自己注意。沒有 ...
計算機網路之套接字SOCKET
當某個應用程序啟動系統呼叫時,控制權就從應用程序傳遞給了系統呼叫介面。此介面再將控制權傳遞給計算機的作業系統。作業系統將此呼叫轉給某個內部過程,並執行所請求的操作。內部過程一旦執行完畢,控制權就又通過系統呼叫介面返回給應用程序。關於tcp ip協議最著名的api就是berkeleyunix 作業系統...
計算機網路 簡單聊聊套接字 Socket
socket 由來 在學習乙個新知識之前,要去想它為什麼會出現,它的出現解決了什麼問題.這樣印象才會深刻一些.在同乙個主機下,兩個程序間的通訊是很容易,直接把各種通訊細節交給作業系統去做就 ok 了.但是如果兩個程序是處於不同主機下呢?該如何進行通訊呢?而且在實際的應用場景中,是很複雜的,有的使用 ...