計(jì)算機(jī)與計(jì)算機(jī)之間要有統(tǒng)一的連接標(biāo)準(zhǔn)才能夠進(jìn)行通信,,這個(gè)標(biāo)準(zhǔn)稱(chēng)之為互聯(lián)網(wǎng)協(xié)議,而網(wǎng)絡(luò)就是物理鏈接介質(zhì)+互聯(lián)網(wǎng)協(xié)議,。 按照功能不同,,人們將互聯(lián)網(wǎng)協(xié)議分為osi七層或tcp/ip五層或tcp/ip四層,,今天我們一起來(lái)看看unix網(wǎng)絡(luò)通信原理
一、網(wǎng)絡(luò)協(xié)議
國(guó)際標(biāo)準(zhǔn)化組織(ISO)定義了網(wǎng)絡(luò)協(xié)議的基本框架,,被稱(chēng)為OSI模型,。OSI模型包括應(yīng)用層、表示層,、會(huì)話層,、傳輸層、網(wǎng)絡(luò)層,、數(shù)據(jù)鏈路層及物理層,。而OSI模型過(guò)于復(fù)雜至今沒(méi)有得到實(shí)際的應(yīng)用。
TCP/IP協(xié)議模型將OSI的7層協(xié)議模型簡(jiǎn)化為4層,,從而更有利于實(shí)現(xiàn)和使用,。TCP/IP協(xié)議模型包括應(yīng)用層、傳輸層,、網(wǎng)絡(luò)層,、網(wǎng)絡(luò)接口層。
TCP/IP協(xié)議與OSI模型的對(duì)應(yīng)關(guān)系如下圖:
二,、套接字socket
它是一種可以進(jìn)行網(wǎng)絡(luò)通信的內(nèi)核對(duì)象,,它有一個(gè)唯一的標(biāo)識(shí)符,一般稱(chēng)它為socket描述符,,跟文件描述符類(lèi)似,,也可以用read/wrote/close操作。
int socket(int domain, int type, int protocol);/*
功能:創(chuàng)建socket對(duì)象
domain:通信地址類(lèi)型
AF_UNIX / AF_LOCAL :本地進(jìn)程間通信
AF_INET :使用ipv4地址通信
AF_INET6:使用ipv6地址通信
type:
SOCK_STREAM :數(shù)據(jù)流協(xié)議,,TCP面向連接的通信協(xié)議
優(yōu)點(diǎn):安全可靠,,數(shù)據(jù)不丟失,但速度慢,。
一般常用于安全性較高的場(chǎng)景
SOCK_DGRAM :數(shù)據(jù)報(bào)協(xié)議,,UDP面向無(wú)連接的通信協(xié)議
優(yōu)點(diǎn):速度快,數(shù)據(jù)可能會(huì)丟失,,安全性和可靠性于TCP相比不高
一般用于安全性要求不高,,但對(duì)速度有要求的場(chǎng)景。
protocol:特殊協(xié)議一般不使用,,直接寫(xiě) 0*/
準(zhǔn)備通信地址:
基本通信地址
struct sockaddr
{
sa_family_t sa_family;
char sa_data[14];
}
本地通信地址
struct sockaddr_un
{
// 通信地址類(lèi)型
sun_family_t sun_family;
// socket文件的路徑
char sun_path[100];
}
網(wǎng)絡(luò)通信地址
struct sockaddr_in
{
//通信地址類(lèi)型
short int sin_family;
//端口號(hào)
in_port_t sin_port;
//ip地址
struct in_addr sin_addr;
}
準(zhǔn)備好的通信地址通常要將其強(qiáng)制轉(zhuǎn)換成基本通信地址才能傳給函數(shù)使用,。
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//功能:把socket對(duì)象與通信地址建立聯(lián)系
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//功能:連接通信目標(biāo)
//socketaddr:目標(biāo)地址
三、網(wǎng)絡(luò)通信的數(shù)據(jù)存儲(chǔ)方式
個(gè)人計(jì)算機(jī)系統(tǒng)數(shù)據(jù)的存儲(chǔ)方式可能是大端,,也可能是小端,,網(wǎng)絡(luò)通信時(shí)需要的是大端數(shù)據(jù),必須把數(shù)據(jù)轉(zhuǎn)換成大端,。
uint32_t htonl(uint32_t hostlong);
//功能:把32位的主機(jī)字節(jié)序轉(zhuǎn)換成32位的網(wǎng)絡(luò)字節(jié)序
uint16_t htons(uint16_t hostshort);
//功能:把16位的主機(jī)字節(jié)序轉(zhuǎn)換成16位的網(wǎng)絡(luò)字節(jié)序
uint32_t ntohl(uint32_t netlong);
//功能:把32為網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成32位的主機(jī)字節(jié)序
uint16_t ntohs(uint16_t netshort);
//功能:把16為網(wǎng)絡(luò)字節(jié)序轉(zhuǎn)換成16位的主機(jī)字節(jié)序
生成端口號(hào)
端口號(hào)就是一個(gè)16為的無(wú)符號(hào)整數(shù)
uint16_t htons(uint16_t hostshort);
生成ip地址
in_addr_t inet_addr(const char *cp);
//功能:把點(diǎn)分十進(jìn)制的字符串ip地址轉(zhuǎn)換成32位的無(wú)符號(hào)整數(shù)
char *inet_ntoa(struct in_addr in);
//功能:把32位的網(wǎng)絡(luò)字節(jié)序的ip地址轉(zhuǎn)換成點(diǎn)分十進(jìn)制的字符串ip地址
四,、網(wǎng)絡(luò)通信(UDP)
進(jìn)程A:創(chuàng)建socket對(duì)象->準(zhǔn)備地址->綁定->接收數(shù)據(jù)和來(lái)時(shí)的地址->原路返回?cái)?shù)據(jù)->關(guān)閉socket
進(jìn)程B:創(chuàng)建socket對(duì)象->準(zhǔn)備地址->向目標(biāo)發(fā)送數(shù)據(jù)->接收數(shù)據(jù)->關(guān)閉socket
當(dāng)socket對(duì)象被全部關(guān)閉后,,會(huì)在內(nèi)核中停留一段時(shí)間(給一個(gè)重新連接的機(jī)會(huì)),如果再使用同樣的ip地址和端口號(hào)時(shí)就會(huì)失?。ㄑ訒r(shí)關(guān)閉)
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
//功能:接收數(shù)據(jù)并獲取發(fā)送端的地址
//addrlen:是參數(shù),,要得到的src_addr的長(zhǎng)度
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
//功能:發(fā)送數(shù)據(jù)到指定的目標(biāo)
五、網(wǎng)絡(luò)通信(TCP)
面向連接的網(wǎng)絡(luò)通信,,在通信過(guò)程中時(shí)刻保持連接,,這種通信方式類(lèi)似與打電話,能保證安全可靠,、數(shù)據(jù)不丟失,,但與UDP相比傳輸速度略低。
進(jìn)程A:創(chuàng)建socket->準(zhǔn)備地址->綁定->監(jiān)聽(tīng)(設(shè)置隊(duì)列長(zhǎng)度)->等待連接->通信->關(guān)閉,。
進(jìn)程B,;創(chuàng)建socket->準(zhǔn)備地址->連接->通信->關(guān)閉
int listen(int sockfd, int backlog);
//功能:設(shè)置socket對(duì)象最大的排隊(duì)數(shù)量
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
//功能:等待其他主機(jī)與當(dāng)前socket建立連接關(guān)系。
//返回值:建立連接的描述符,,此后通信都用此描述符
int connect(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
//功能:連接通信目標(biāo)
//socketaddr:目標(biāo)地址
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
//功能:網(wǎng)絡(luò)通信專(zhuān)用的數(shù)據(jù)接收
//flag: 0 阻塞
// 1 不阻塞
//返回值:-1 時(shí),,說(shuō)明連接斷開(kāi),此時(shí)應(yīng)該結(jié)束循環(huán)
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
//功能:網(wǎng)絡(luò)通信專(zhuān)用的數(shù)據(jù)發(fā)送
//返回值:-1 時(shí),,說(shuō)明連接斷開(kāi) ,,此時(shí)應(yīng)該結(jié)束循環(huán)