socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念
生活随笔
收集整理的這篇文章主要介紹了
socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
話題回到“黑社會(huì)辦公室”的例子,講概念已經(jīng)扯得比較遠(yuǎn)了,不過(guò),這一節(jié)我們還得講概念,不過(guò)好在有些程序的例子。如果大家不想翻回去看TcpServer類的原型,我這里直接給出這個(gè)頭文件的完整源代碼:
//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 我們已經(jīng)解釋了為什么listenSock和communicationSock的類型是int,以及sockaddr_in是什么結(jié)構(gòu),現(xiàn)在來(lái)寫這個(gè)類的構(gòu)造函數(shù):
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";
????}
} 好,先看看程序培養(yǎng)一下感覺,我們還得說(shuō)概念。
數(shù)據(jù)封裝(Data Encapsutation)
??????? 我們前面說(shuō)到了網(wǎng)絡(luò)分層:鏈路——網(wǎng)絡(luò)——傳輸——應(yīng)用。數(shù)據(jù)從應(yīng)用程序里誕生,傳送到互聯(lián)網(wǎng)上每一層都會(huì)進(jìn)行一次封裝:
Data>>Application>>TCP/UDP>>IP>>OS(Driver, Kernel & Physical Address)
我們用socket重點(diǎn)描述的是協(xié)議,包括網(wǎng)絡(luò)協(xié)議(IP)和傳輸協(xié)議(TCP/UDP)。
sockaddr重點(diǎn)描述的是地址,包括IP地址和TCP/UDP端口。
socket()函數(shù)
??? 我們從TcpServer::TcpServer()函數(shù)可以看到,socket和sockaddr的產(chǎn)生是可以相互獨(dú)立的。socket()的函數(shù)原型是:
int?socket(int?protocolFamily,?int?type,?int?protocol); 在Linux中的實(shí)現(xiàn)為:
#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; 第一個(gè)參數(shù)是協(xié)議簇(Linux里面叫作域,意思一樣的),還是那句話,我們這篇教程用到的就僅僅是一個(gè)PF_INET(protocol family : internet),很多時(shí)候你會(huì)發(fā)現(xiàn)人們也經(jīng)常在這里賦值為AF_INET,事實(shí)上,當(dāng)前,AF_INET就是PF_INET的一個(gè)#define,但是,寫成PF_INET從語(yǔ)義上會(huì)更加嚴(yán)謹(jǐn)。這也就是TCP/IP協(xié)議簇中的IP協(xié)議(Internet Protocol),網(wǎng)絡(luò)層的協(xié)議。
后面兩個(gè)參數(shù)定義傳輸層的協(xié)議。
第二個(gè)參數(shù)是傳輸層協(xié)議類型,我們教程里用到的宏,只有兩個(gè):SOCK_STREAM(數(shù)據(jù)流格式)和SOCK_DGRAM(數(shù)據(jù)報(bào)格式);(具體是什么我們以后討論)
第三個(gè)參數(shù)是具體的傳輸層協(xié)議。當(dāng)賦值為0的時(shí)候,系統(tǒng)會(huì)根據(jù)傳輸層協(xié)議類型自動(dòng)匹配和選擇。事實(shí)上,當(dāng)前,匹配SOCK_STREAM的就是TCP協(xié)議;而匹配SOCK_DGRAM就是UDP協(xié)議。所以,我們指定了第二個(gè)參數(shù),第三個(gè)就可以簡(jiǎn)單的設(shè)置為0。不過(guò),為了嚴(yán)謹(jǐn),我們最好還是把具體協(xié)議寫出來(lái),比如,我們的例子中的TCP協(xié)議的宏名稱:IPPROTO_TCP。
數(shù)據(jù)的“地址”
??????? 從數(shù)據(jù)封裝的模型,我們可以看到數(shù)據(jù)是怎么從應(yīng)用程序傳遞到互聯(lián)網(wǎng)的。我們說(shuō)過(guò),數(shù)據(jù)的傳送是通過(guò)socket進(jìn)行的。但是socket只描述了協(xié)議類型。要讓數(shù)據(jù)正確的傳送到某個(gè)地方,必須添加那個(gè)地方的sockaddr地址;同樣,要能接受網(wǎng)絡(luò)上的數(shù)據(jù),必須有自己的sockaddr地址。
??????? 可見,在網(wǎng)絡(luò)上傳送的數(shù)據(jù)包,是socket和sockaddr共同“染指”的結(jié)果。他們共同封裝和指定了一個(gè)數(shù)據(jù)包的網(wǎng)絡(luò)協(xié)議(IP)和IP地址,傳輸協(xié)議(TCP/UDP)和端口號(hào)。
網(wǎng)絡(luò)字節(jié)和本機(jī)字節(jié)的相互轉(zhuǎn)換
??????? sockaddr結(jié)構(gòu)中的IP地址(sin_addr.s_addr)和端口號(hào)(sin_port)將被封裝到網(wǎng)絡(luò)上傳送的數(shù)據(jù)包中,所以,它的結(jié)構(gòu)形式需要保證是網(wǎng)絡(luò)字節(jié)形式。我們這里用到的函數(shù)是htons()和htonl(),這些縮寫的意思是:
h: host,主機(jī)(本機(jī))
n: network,網(wǎng)絡(luò)
to: to轉(zhuǎn)換
s: short,16位(2字節(jié),常用于端口號(hào))
l: long, 32位(4字節(jié),常用于IP地址)
“反過(guò)來(lái)”的函數(shù)也是存在的ntohs()和ntohl()。
動(dòng)作與持續(xù)行為
??????? 本節(jié)最后的一個(gè)概念可以跟計(jì)算機(jī)無(wú)關(guān)。作為動(dòng)詞,有些可以描述動(dòng)作,有些是描述一重持續(xù)的行為狀態(tài)的(就如同一般動(dòng)詞和be動(dòng)詞一樣)。扯到C++來(lái)說(shuō),我們可以把持續(xù)行為封裝到函數(shù)內(nèi)部,只留出動(dòng)作的接口。事實(shí)上,構(gòu)造函數(shù)中的bind()和listen()就是這種描述持續(xù)狀態(tài)的行為函數(shù)。 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
//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 我們已經(jīng)解釋了為什么listenSock和communicationSock的類型是int,以及sockaddr_in是什么結(jié)構(gòu),現(xiàn)在來(lái)寫這個(gè)類的構(gòu)造函數(shù):
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";
????}
} 好,先看看程序培養(yǎng)一下感覺,我們還得說(shuō)概念。
數(shù)據(jù)封裝(Data Encapsutation)
??????? 我們前面說(shuō)到了網(wǎng)絡(luò)分層:鏈路——網(wǎng)絡(luò)——傳輸——應(yīng)用。數(shù)據(jù)從應(yīng)用程序里誕生,傳送到互聯(lián)網(wǎng)上每一層都會(huì)進(jìn)行一次封裝:
Data>>Application>>TCP/UDP>>IP>>OS(Driver, Kernel & Physical Address)
我們用socket重點(diǎn)描述的是協(xié)議,包括網(wǎng)絡(luò)協(xié)議(IP)和傳輸協(xié)議(TCP/UDP)。
sockaddr重點(diǎn)描述的是地址,包括IP地址和TCP/UDP端口。
socket()函數(shù)
??? 我們從TcpServer::TcpServer()函數(shù)可以看到,socket和sockaddr的產(chǎn)生是可以相互獨(dú)立的。socket()的函數(shù)原型是:
int?socket(int?protocolFamily,?int?type,?int?protocol); 在Linux中的實(shí)現(xiàn)為:
#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; 第一個(gè)參數(shù)是協(xié)議簇(Linux里面叫作域,意思一樣的),還是那句話,我們這篇教程用到的就僅僅是一個(gè)PF_INET(protocol family : internet),很多時(shí)候你會(huì)發(fā)現(xiàn)人們也經(jīng)常在這里賦值為AF_INET,事實(shí)上,當(dāng)前,AF_INET就是PF_INET的一個(gè)#define,但是,寫成PF_INET從語(yǔ)義上會(huì)更加嚴(yán)謹(jǐn)。這也就是TCP/IP協(xié)議簇中的IP協(xié)議(Internet Protocol),網(wǎng)絡(luò)層的協(xié)議。
后面兩個(gè)參數(shù)定義傳輸層的協(xié)議。
第二個(gè)參數(shù)是傳輸層協(xié)議類型,我們教程里用到的宏,只有兩個(gè):SOCK_STREAM(數(shù)據(jù)流格式)和SOCK_DGRAM(數(shù)據(jù)報(bào)格式);(具體是什么我們以后討論)
第三個(gè)參數(shù)是具體的傳輸層協(xié)議。當(dāng)賦值為0的時(shí)候,系統(tǒng)會(huì)根據(jù)傳輸層協(xié)議類型自動(dòng)匹配和選擇。事實(shí)上,當(dāng)前,匹配SOCK_STREAM的就是TCP協(xié)議;而匹配SOCK_DGRAM就是UDP協(xié)議。所以,我們指定了第二個(gè)參數(shù),第三個(gè)就可以簡(jiǎn)單的設(shè)置為0。不過(guò),為了嚴(yán)謹(jǐn),我們最好還是把具體協(xié)議寫出來(lái),比如,我們的例子中的TCP協(xié)議的宏名稱:IPPROTO_TCP。
數(shù)據(jù)的“地址”
??????? 從數(shù)據(jù)封裝的模型,我們可以看到數(shù)據(jù)是怎么從應(yīng)用程序傳遞到互聯(lián)網(wǎng)的。我們說(shuō)過(guò),數(shù)據(jù)的傳送是通過(guò)socket進(jìn)行的。但是socket只描述了協(xié)議類型。要讓數(shù)據(jù)正確的傳送到某個(gè)地方,必須添加那個(gè)地方的sockaddr地址;同樣,要能接受網(wǎng)絡(luò)上的數(shù)據(jù),必須有自己的sockaddr地址。
??????? 可見,在網(wǎng)絡(luò)上傳送的數(shù)據(jù)包,是socket和sockaddr共同“染指”的結(jié)果。他們共同封裝和指定了一個(gè)數(shù)據(jù)包的網(wǎng)絡(luò)協(xié)議(IP)和IP地址,傳輸協(xié)議(TCP/UDP)和端口號(hào)。
網(wǎng)絡(luò)字節(jié)和本機(jī)字節(jié)的相互轉(zhuǎn)換
??????? sockaddr結(jié)構(gòu)中的IP地址(sin_addr.s_addr)和端口號(hào)(sin_port)將被封裝到網(wǎng)絡(luò)上傳送的數(shù)據(jù)包中,所以,它的結(jié)構(gòu)形式需要保證是網(wǎng)絡(luò)字節(jié)形式。我們這里用到的函數(shù)是htons()和htonl(),這些縮寫的意思是:
h: host,主機(jī)(本機(jī))
n: network,網(wǎng)絡(luò)
to: to轉(zhuǎn)換
s: short,16位(2字節(jié),常用于端口號(hào))
l: long, 32位(4字節(jié),常用于IP地址)
“反過(guò)來(lái)”的函數(shù)也是存在的ntohs()和ntohl()。
動(dòng)作與持續(xù)行為
??????? 本節(jié)最后的一個(gè)概念可以跟計(jì)算機(jī)無(wú)關(guān)。作為動(dòng)詞,有些可以描述動(dòng)作,有些是描述一重持續(xù)的行為狀態(tài)的(就如同一般動(dòng)詞和be動(dòng)詞一樣)。扯到C++來(lái)說(shuō),我們可以把持續(xù)行為封裝到函數(shù)內(nèi)部,只留出動(dòng)作的接口。事實(shí)上,構(gòu)造函數(shù)中的bind()和listen()就是這種描述持續(xù)狀態(tài)的行為函數(shù)。 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)
總結(jié)
以上是生活随笔為你收集整理的socket 编程入门教程(一)TCP server 端:4、构造函数涉及的概念的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 《冰雪奇缘》团队打造:迪士尼新动画电影《
- 下一篇: 花4000块把宏光MINI EV改成快充