socket套接字編程(1)——基本函數
TCP交互流程:
服務器:1. 創建socket;2. 綁定socket和端口號;3. 監聽端口號;4. 接收來自客戶端的連接請求;5. 從socket中讀取字符;6. 關閉socket。
客戶端:1. 創建socket;2. 連接制定計算機的端口;3. 向socket中寫入信息;4. 關閉socket。
創建socket:
socket函數
int socket (int __family, int __type, int __protocol);
__family是協議域,也稱協議族。常見的有AF_INET(ipv4)。
__type指定socket類型。SOCK_STREAM即TCP協議,SOCK_DGRAM即UDP協議。
__protocol指定協議。
該函數返回的socket描述字存在於協議族空間中,但是並沒有一個具體的地址。如果想要給它賦予一個地址,就必須調用bind()函數,否則系統就在調用connect()和listen()時自動隨機分配一個端口。
這裏註意:type和protocol並不能隨意組合。當protocol為0時,會自動選擇type類型對應的默認協議。
創建socket的樣例代碼如下:
//創建TCP套接字 //AF_INET:網絡連接,ipv4 //SOCK_STREAM:TCP連接 int fd = socket(AF_INET, SOCK_STREAM, 0);if (fd<0) { std::cout<<"create socket error!"<<std::endl; return 0; } std::cout<<"create socket: "<<fd<<std::endl;
綁定socket和端口號:
bind函數
int bind (int, const struct sockaddr *__my_addr, socklen_t __addrlen);
第一個參數是socket描述字。(我不理解為啥這兒沒有參數名)
__my_addr是指向要綁定給該socket的協議地址。這個地址結構根據socket創建時的地址協議族(family)的不同而不同。
__addrlen對應的是地址的長度。
如果該函數執行成功,就返回0,否則為SOCKET_ERROR。
//命名套接字 struct sockaddr_in myaddr; memset((void *)&myaddr, 0, sizeof(myaddr)); //關於htonl和htons,參考以下網頁:ntohs, ntohl, htons,htonl的比較和詳解 //https://blog.csdn.net/haoxiaodao/article/details/73162663 myaddr.sin_family = AF_INET; myaddr.sin_addr.s_addr = htonl(INADDR_ANY); myaddr.sin_port = htons(6666); if (bind(fd, (struct sockaddr*)&myaddr, sizeof(myaddr)) < 0) { std::cout<<"name socket error!"<<std::endl; return 0; } std::cout<<"name socket"<<std::endl;
監聽端口號:
作為一個服務器,在調用socket()和bind()之後就會調用listen()來監聽這個socket。為了能夠在套接字上接受進入的連接,服務器程序必須創建一個隊列來保存未處理的請求。
listen函數
int listen (int, int __n);
第一個參數即socket描述子
__n為隊列的大小。
//創建監聽隊列 if (listen(fd, 5) < 0) { std::cout<<"listen failed"<<std::endl; return 0; }
接收來自客戶端的連接請求:
當TCP服務器監聽到了連接請求之後,就會調用accept()函數接收請求,這樣連接就建立好了。
accept函數
int accept (int, struct sockaddr *__peer, socklen_t *);
第一個是socket描述子,第二個是用來接收的客戶端地址,第三個是地址的大小。註意第三個是指針類型,所以要事先構造好大小的變量,然後傳地址進去。
另外,《後臺開發核心技術與應用實踐》中的例子,第二個和第三個都傳的NULL。我的理解是,如果不需要接收這兩個量,就可以傳一個空值進去。
accept函數會返回一個新的socket描述子,這個新的描述子代表了服務端和客戶端的連接。後面可以用於讀取數據以及關閉連接。
//等待並接受連接 const int MAXBUF = 4096; char buff[MAXBUF]; struct sockaddr_in client_addr; int client_addr_len = sizeof(client_addr); int client_fd; while (1) { client_fd = accept(fd, (struct sockaddr*)&client_addr, &client_addr_len); if (client_fd < 0) { std::cout<<"connect error"<<std::endl; continue; } //接收數據 //關閉套接字 }
未完,待補全。
socket套接字編程(1)——基本函數