socket 编程入门教程(一)TCP server 端:6、创建“通讯 ”嵌套字
生活随笔
收集整理的這篇文章主要介紹了
socket 编程入门教程(一)TCP server 端:6、创建“通讯 ”嵌套字
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
這里的“通訊”加上了引號,是因為實際上所有的socket都有通訊的功能,只是在我們的例子中,之前那個socket只負責listen,而這個socket負責接受信息并echo回去。
?我們現看看這個函數:
bool?TcpServer::isAccept()
{
????unsigned?int?clntAddrLen?=?sizeof(clntAddr);
????if?(?(communicationSock?=?accept(listenSock,?(sockaddr*)&clntAddr,?&clntAddrLen))?<?0?)?{
????????return?false;
????}?else?{
????????std::cout?<<?"Client(IP:?"?<<?inet_ntoa(clntAddr.sin_addr)?<<?")?connected.\n";
????????return?true;
????}
}
用accept()創建新的socket
??????? 在我們的例子中,communicationSock實際上是用函數accept()創建的。
int?accept(int?socket,?struct?sockaddr*?clientAddress,?unsigned?int*?addressLength); 在Linux中的實現為:
/*?Await?a?connection?on?socket?FD.
???When?a?connection?arrives,?open?a?new?socket?to?communicate?with?it,
???set?*ADDR?(which?is?*ADDR_LEN?bytes?long)?to?the?address?of?the?connecting
???peer?and?*ADDR_LEN?to?the?address's?actual?length,?and?return?the
???new?socket's?descriptor,?or?-1?for?errors.
???This?function?is?a?cancellation?point?and?therefore?not?marked?with
???__THROW.??*/
extern?int?accept?(int?__fd,?__SOCKADDR_ARG?__addr,
???????????socklen_t?*__restrict?__addr_len); 這個函數實際上起著構造socket作用的僅僅只有第一個參數(另外還有一個不在這個函數內表現出來的因素,后面會討論到),后面兩個指針都有副作用,在socket創建后,會將客戶端sockaddr的數據以及結構體的大小傳回。
??????? 當程序調用accept()的時候,程序有可能就停下來等accept()的結果。這就是我們前一小節說到的block(阻塞)。這如同我們調用std::cin的時候系統會等待輸入直到回車一樣。accept()是一個有可能引起block的函數。請注意我說的是“有可能”,這是因為accept()的block與否實際上決定與第一個參數socket的屬性。這個文件描述符如果是block的,accept()就block,否則就不block。默認情況下,socket的屬性是“可讀可寫”,并且,是阻塞的。所以,我們不修改socket屬性的時候,accept()是阻塞的。
accept()的另一面connect()
??????? accept()只是在server端被動的等待,它所響應的,是client端connect()函數:
int?connect(int?socket,?struct?sockaddr*?foreignAddress,?unsigned?int?addressLength); 雖然我們這里不打算詳細說明這個client端的函數,但是我們可以看出來,這個函數與之前我們介紹的bind()有幾分相似,特別在Linux的實現中:
/*?Open?a?connection?on?socket?FD?to?peer?at?ADDR?(which?LEN?bytes?long).
???For?connectionless?socket?types,?just?set?the?default?address?to?send?to
???and?the?only?address?from?which?to?accept?transmissions.
???Return?0?on?success,?-1?for?errors.
???This?function?is?a?cancellation?point?and?therefore?not?marked?with
???__THROW.??*/
extern?int?connect?(int?__fd,?__CONST_SOCKADDR_ARG?__addr,?socklen_t?__len); connect() 也使用了const的sockaddr,只不過是遠程電腦上的而非bind()的本機。
??????? accept()在server端表面上是通過listen socket創建了新的socket,實際上,這種行為是在接受對方客戶機程序中connect()函數的請求后發生的。綜合起看,被創建的新socket實際上包含了listen socket的信息以及客戶端connect()請求中所包含的信息——客戶端的sockaddr地址。
新socket與sockaddr的關系
??????? accept()創建的新socket(我們例子中的communicationSock,這里我們簡單用newSock來帶指)首先包含了listen socket的信息,所以,newSock具有本機sockaddr的信息;其次,因為它響應于client端connect()函數的請求,所以,它還包含了clinet端sockaddr的信息。
??????? 我們說過,stream流形式的TCP協議實際上是建立起一個“可來可去”的通道。用于listen的通道,遠程機的目標地址是不確定的;但是newSock卻是有指定的本機地址和遠程機地址,所以,這個socket,才是我們真正用于TCP“通訊”的socket。
inet_ntoa()
#include?<arpa/inet.h>
/*?Convert?Internet?number?in?IN?to?ASCII?representation.??The?return?value
???is?a?pointer?to?an?internal?array?containing?the?string.??*/
extern?char?*inet_ntoa?(struct?in_addr?__in)?__THROW; ??????? 對于這個函數,我們可以作為一種,將IP地址,由in_addr結構轉換為可讀的ASCII形式的固定用法。
?我們現看看這個函數:
bool?TcpServer::isAccept()
{
????unsigned?int?clntAddrLen?=?sizeof(clntAddr);
????if?(?(communicationSock?=?accept(listenSock,?(sockaddr*)&clntAddr,?&clntAddrLen))?<?0?)?{
????????return?false;
????}?else?{
????????std::cout?<<?"Client(IP:?"?<<?inet_ntoa(clntAddr.sin_addr)?<<?")?connected.\n";
????????return?true;
????}
}
用accept()創建新的socket
??????? 在我們的例子中,communicationSock實際上是用函數accept()創建的。
int?accept(int?socket,?struct?sockaddr*?clientAddress,?unsigned?int*?addressLength); 在Linux中的實現為:
/*?Await?a?connection?on?socket?FD.
???When?a?connection?arrives,?open?a?new?socket?to?communicate?with?it,
???set?*ADDR?(which?is?*ADDR_LEN?bytes?long)?to?the?address?of?the?connecting
???peer?and?*ADDR_LEN?to?the?address's?actual?length,?and?return?the
???new?socket's?descriptor,?or?-1?for?errors.
???This?function?is?a?cancellation?point?and?therefore?not?marked?with
???__THROW.??*/
extern?int?accept?(int?__fd,?__SOCKADDR_ARG?__addr,
???????????socklen_t?*__restrict?__addr_len); 這個函數實際上起著構造socket作用的僅僅只有第一個參數(另外還有一個不在這個函數內表現出來的因素,后面會討論到),后面兩個指針都有副作用,在socket創建后,會將客戶端sockaddr的數據以及結構體的大小傳回。
??????? 當程序調用accept()的時候,程序有可能就停下來等accept()的結果。這就是我們前一小節說到的block(阻塞)。這如同我們調用std::cin的時候系統會等待輸入直到回車一樣。accept()是一個有可能引起block的函數。請注意我說的是“有可能”,這是因為accept()的block與否實際上決定與第一個參數socket的屬性。這個文件描述符如果是block的,accept()就block,否則就不block。默認情況下,socket的屬性是“可讀可寫”,并且,是阻塞的。所以,我們不修改socket屬性的時候,accept()是阻塞的。
accept()的另一面connect()
??????? accept()只是在server端被動的等待,它所響應的,是client端connect()函數:
int?connect(int?socket,?struct?sockaddr*?foreignAddress,?unsigned?int?addressLength); 雖然我們這里不打算詳細說明這個client端的函數,但是我們可以看出來,這個函數與之前我們介紹的bind()有幾分相似,特別在Linux的實現中:
/*?Open?a?connection?on?socket?FD?to?peer?at?ADDR?(which?LEN?bytes?long).
???For?connectionless?socket?types,?just?set?the?default?address?to?send?to
???and?the?only?address?from?which?to?accept?transmissions.
???Return?0?on?success,?-1?for?errors.
???This?function?is?a?cancellation?point?and?therefore?not?marked?with
???__THROW.??*/
extern?int?connect?(int?__fd,?__CONST_SOCKADDR_ARG?__addr,?socklen_t?__len); connect() 也使用了const的sockaddr,只不過是遠程電腦上的而非bind()的本機。
??????? accept()在server端表面上是通過listen socket創建了新的socket,實際上,這種行為是在接受對方客戶機程序中connect()函數的請求后發生的。綜合起看,被創建的新socket實際上包含了listen socket的信息以及客戶端connect()請求中所包含的信息——客戶端的sockaddr地址。
新socket與sockaddr的關系
??????? accept()創建的新socket(我們例子中的communicationSock,這里我們簡單用newSock來帶指)首先包含了listen socket的信息,所以,newSock具有本機sockaddr的信息;其次,因為它響應于client端connect()函數的請求,所以,它還包含了clinet端sockaddr的信息。
??????? 我們說過,stream流形式的TCP協議實際上是建立起一個“可來可去”的通道。用于listen的通道,遠程機的目標地址是不確定的;但是newSock卻是有指定的本機地址和遠程機地址,所以,這個socket,才是我們真正用于TCP“通訊”的socket。
inet_ntoa()
#include?<arpa/inet.h>
/*?Convert?Internet?number?in?IN?to?ASCII?representation.??The?return?value
???is?a?pointer?to?an?internal?array?containing?the?string.??*/
extern?char?*inet_ntoa?(struct?in_addr?__in)?__THROW; ??????? 對于這個函數,我們可以作為一種,將IP地址,由in_addr結構轉換為可讀的ASCII形式的固定用法。
總結
以上是生活随笔為你收集整理的socket 编程入门教程(一)TCP server 端:6、创建“通讯 ”嵌套字的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 民生信用卡密码输错3次怎么办
- 下一篇: 卸载更新更简单了:Win11进一步削弱控