socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念
生活随笔
收集整理的這篇文章主要介紹了
socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
話題回到“黑社會辦公室”的例子,講概念已經扯得比較遠了,不過,這一節我們還得講概念,不過好在有些程序的例子。如果大家不想翻回去看TcpServer類的原型,我這里直接給出這個頭文件的完整源代碼:
//Filename:?TcpServerClass.hpp
#ifndef?TCPSERVERCLASS_HPP_INCLUDED
#define?TCPSERVERCLASS_HPP_INCLUDED
#include?<unistd.h>
#include?<iostream>
#include?<sys/socket.h>
#include?<arpa/inet.h>
class?TcpServer
{
private:
????int?listenSock;
????int?communicationSock;
????sockaddr_in?servAddr;
????sockaddr_in?clntAddr;
public:
????TcpServer(int?listen_port);
????bool?isAccept();
????void?handleEcho();
};
#endif?//?TCPSERVERCLASS_HPP_INCLUDED 我們已經解釋了為什么listenSock和communicationSock的類型是int,以及sockaddr_in是什么結構,現在來寫這個類的構造函數:
TcpServer::TcpServer(int?listen_port)
{
????if?(?(listenSock?=?socket(PF_INET,?SOCK_STREAM,?IPPROTO_TCP))?<?0?)?{
????????throw?"socket()?failed";
????}
????memset(&servAddr,?0,?sizeof(servAddr));
????servAddr.sin_family?=?AF_INET;
????servAddr.sin_addr.s_addr?=?htonl(INADDR_ANY);
????servAddr.sin_port?=?htons(listen_port);
????if?(?bind(listenSock,?(sockaddr*)&servAddr,?sizeof(servAddr))?<?0?)?{
????????throw?"bind()?failed";
????}
????if?(?listen(listenSock,?10)?<?0?)?{
????????throw?"listen()?failed";
????}
} 好,先看看程序培養一下感覺,我們還得說概念。
數據封裝(Data Encapsutation)
??????? 我們前面說到了網絡分層:鏈路——網絡——傳輸——應用。數據從應用程序里誕生,傳送到互聯網上每一層都會進行一次封裝:
Data>>Application>>TCP/UDP>>IP>>OS(Driver, Kernel & Physical Address)
我們用socket重點描述的是協議,包括網絡協議(IP)和傳輸協議(TCP/UDP)。
sockaddr重點描述的是地址,包括IP地址和TCP/UDP端口。
socket()函數
??? 我們從TcpServer::TcpServer()函數可以看到,socket和sockaddr的產生是可以相互獨立的。socket()的函數原型是:
int?socket(int?protocolFamily,?int?type,?int?protocol); 在Linux中的實現為:
#include?<sys/socket.h>
/*?Create?a?new?socket?of?type?TYPE?in?domain?DOMAIN,?using
???protocol?PROTOCOL.??If?PROTOCOL?is?zero,?one?is?chosen?automatically.
???Returns?a?file?descriptor?for?the?new?socket,?or?-1?for?errors.??*/
extern?int?socket?(int?__domain,?int?__type,?int?__protocol)?__THROW; 第一個參數是協議簇(Linux里面叫作域,意思一樣的),還是那句話,我們這篇教程用到的就僅僅是一個PF_INET(protocol family : internet),很多時候你會發現人們也經常在這里賦值為AF_INET,事實上,當前,AF_INET就是PF_INET的一個#define,但是,寫成PF_INET從語義上會更加嚴謹。這也就是TCP/IP協議簇中的IP協議(Internet Protocol),網絡層的協議。
后面兩個參數定義傳輸層的協議。
第二個參數是傳輸層協議類型,我們教程里用到的宏,只有兩個:SOCK_STREAM(數據流格式)和SOCK_DGRAM(數據報格式);(具體是什么我們以后討論)
第三個參數是具體的傳輸層協議。當賦值為0的時候,系統會根據傳輸層協議類型自動匹配和選擇。事實上,當前,匹配SOCK_STREAM的就是TCP協議;而匹配SOCK_DGRAM就是UDP協議。所以,我們指定了第二個參數,第三個就可以簡單的設置為0。不過,為了嚴謹,我們最好還是把具體協議寫出來,比如,我們的例子中的TCP協議的宏名稱:IPPROTO_TCP。
數據的“地址”
??????? 從數據封裝的模型,我們可以看到數據是怎么從應用程序傳遞到互聯網的。我們說過,數據的傳送是通過socket進行的。但是socket只描述了協議類型。要讓數據正確的傳送到某個地方,必須添加那個地方的sockaddr地址;同樣,要能接受網絡上的數據,必須有自己的sockaddr地址。
??????? 可見,在網絡上傳送的數據包,是socket和sockaddr共同“染指”的結果。他們共同封裝和指定了一個數據包的網絡協議(IP)和IP地址,傳輸協議(TCP/UDP)和端口號。
網絡字節和本機字節的相互轉換
??????? sockaddr結構中的IP地址(sin_addr.s_addr)和端口號(sin_port)將被封裝到網絡上傳送的數據包中,所以,它的結構形式需要保證是網絡字節形式。我們這里用到的函數是htons()和htonl(),這些縮寫的意思是:
h: host,主機(本機)
n: network,網絡
to: to轉換
s: short,16位(2字節,常用于端口號)
l: long, 32位(4字節,常用于IP地址)
“反過來”的函數也是存在的ntohs()和ntohl()。
動作與持續行為
??????? 本節最后的一個概念可以跟計算機無關。作為動詞,有些可以描述動作,有些是描述一重持續的行為狀態的(就如同一般動詞和be動詞一樣)。扯到C++來說,我們可以把持續行為封裝到函數內部,只留出動作的接口。事實上,構造函數中的bind()和listen()就是這種描述持續狀態的行為函數。 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
//Filename:?TcpServerClass.hpp
#ifndef?TCPSERVERCLASS_HPP_INCLUDED
#define?TCPSERVERCLASS_HPP_INCLUDED
#include?<unistd.h>
#include?<iostream>
#include?<sys/socket.h>
#include?<arpa/inet.h>
class?TcpServer
{
private:
????int?listenSock;
????int?communicationSock;
????sockaddr_in?servAddr;
????sockaddr_in?clntAddr;
public:
????TcpServer(int?listen_port);
????bool?isAccept();
????void?handleEcho();
};
#endif?//?TCPSERVERCLASS_HPP_INCLUDED 我們已經解釋了為什么listenSock和communicationSock的類型是int,以及sockaddr_in是什么結構,現在來寫這個類的構造函數:
TcpServer::TcpServer(int?listen_port)
{
????if?(?(listenSock?=?socket(PF_INET,?SOCK_STREAM,?IPPROTO_TCP))?<?0?)?{
????????throw?"socket()?failed";
????}
????memset(&servAddr,?0,?sizeof(servAddr));
????servAddr.sin_family?=?AF_INET;
????servAddr.sin_addr.s_addr?=?htonl(INADDR_ANY);
????servAddr.sin_port?=?htons(listen_port);
????if?(?bind(listenSock,?(sockaddr*)&servAddr,?sizeof(servAddr))?<?0?)?{
????????throw?"bind()?failed";
????}
????if?(?listen(listenSock,?10)?<?0?)?{
????????throw?"listen()?failed";
????}
} 好,先看看程序培養一下感覺,我們還得說概念。
數據封裝(Data Encapsutation)
??????? 我們前面說到了網絡分層:鏈路——網絡——傳輸——應用。數據從應用程序里誕生,傳送到互聯網上每一層都會進行一次封裝:
Data>>Application>>TCP/UDP>>IP>>OS(Driver, Kernel & Physical Address)
我們用socket重點描述的是協議,包括網絡協議(IP)和傳輸協議(TCP/UDP)。
sockaddr重點描述的是地址,包括IP地址和TCP/UDP端口。
socket()函數
??? 我們從TcpServer::TcpServer()函數可以看到,socket和sockaddr的產生是可以相互獨立的。socket()的函數原型是:
int?socket(int?protocolFamily,?int?type,?int?protocol); 在Linux中的實現為:
#include?<sys/socket.h>
/*?Create?a?new?socket?of?type?TYPE?in?domain?DOMAIN,?using
???protocol?PROTOCOL.??If?PROTOCOL?is?zero,?one?is?chosen?automatically.
???Returns?a?file?descriptor?for?the?new?socket,?or?-1?for?errors.??*/
extern?int?socket?(int?__domain,?int?__type,?int?__protocol)?__THROW; 第一個參數是協議簇(Linux里面叫作域,意思一樣的),還是那句話,我們這篇教程用到的就僅僅是一個PF_INET(protocol family : internet),很多時候你會發現人們也經常在這里賦值為AF_INET,事實上,當前,AF_INET就是PF_INET的一個#define,但是,寫成PF_INET從語義上會更加嚴謹。這也就是TCP/IP協議簇中的IP協議(Internet Protocol),網絡層的協議。
后面兩個參數定義傳輸層的協議。
第二個參數是傳輸層協議類型,我們教程里用到的宏,只有兩個:SOCK_STREAM(數據流格式)和SOCK_DGRAM(數據報格式);(具體是什么我們以后討論)
第三個參數是具體的傳輸層協議。當賦值為0的時候,系統會根據傳輸層協議類型自動匹配和選擇。事實上,當前,匹配SOCK_STREAM的就是TCP協議;而匹配SOCK_DGRAM就是UDP協議。所以,我們指定了第二個參數,第三個就可以簡單的設置為0。不過,為了嚴謹,我們最好還是把具體協議寫出來,比如,我們的例子中的TCP協議的宏名稱:IPPROTO_TCP。
數據的“地址”
??????? 從數據封裝的模型,我們可以看到數據是怎么從應用程序傳遞到互聯網的。我們說過,數據的傳送是通過socket進行的。但是socket只描述了協議類型。要讓數據正確的傳送到某個地方,必須添加那個地方的sockaddr地址;同樣,要能接受網絡上的數據,必須有自己的sockaddr地址。
??????? 可見,在網絡上傳送的數據包,是socket和sockaddr共同“染指”的結果。他們共同封裝和指定了一個數據包的網絡協議(IP)和IP地址,傳輸協議(TCP/UDP)和端口號。
網絡字節和本機字節的相互轉換
??????? sockaddr結構中的IP地址(sin_addr.s_addr)和端口號(sin_port)將被封裝到網絡上傳送的數據包中,所以,它的結構形式需要保證是網絡字節形式。我們這里用到的函數是htons()和htonl(),這些縮寫的意思是:
h: host,主機(本機)
n: network,網絡
to: to轉換
s: short,16位(2字節,常用于端口號)
l: long, 32位(4字節,常用于IP地址)
“反過來”的函數也是存在的ntohs()和ntohl()。
動作與持續行為
??????? 本節最后的一個概念可以跟計算機無關。作為動詞,有些可以描述動作,有些是描述一重持續的行為狀態的(就如同一般動詞和be動詞一樣)。扯到C++來說,我們可以把持續行為封裝到函數內部,只留出動作的接口。事實上,構造函數中的bind()和listen()就是這種描述持續狀態的行為函數。 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎
總結
以上是生活随笔為你收集整理的socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《冰雪奇缘》团队打造:迪士尼新动画电影《
- 下一篇: 初识WINCE的HIVE注册表