
1.目標(biāo)
暫時(shí)想不出什么好的應(yīng)用場(chǎng)景,目前想到目標(biāo)就是實(shí)現(xiàn)讓兩個(gè)設(shè)備通過網(wǎng)絡(luò)傳輸數(shù)據(jù),比如開發(fā)板和linux主機(jī)之間傳數(shù)據(jù),以后就可以實(shí)現(xiàn)開發(fā)板通過網(wǎng)絡(luò)上報(bào)數(shù)據(jù)或者主機(jī)通過網(wǎng)絡(luò)控制開發(fā)板。
此外,暫時(shí)不想關(guān)心具體的網(wǎng)絡(luò)模型,更注重于網(wǎng)絡(luò)相關(guān)函數(shù)的直接使用。

2.Linux網(wǎng)絡(luò)編程基礎(chǔ)
2.1 嵌套字
多個(gè)TCP連接或者多個(gè)應(yīng)用程序進(jìn)程 可能需要同一個(gè)TCP端口傳輸數(shù)據(jù)。
為了區(qū)分不同應(yīng)用程序進(jìn)程和連接,許多計(jì)算機(jī)操作系統(tǒng)為應(yīng)用程序與TCP/IP交互提供了稱為**嵌套字(Socket)**的接口。
Linux中的網(wǎng)絡(luò)編程正是通過Socket接口實(shí)現(xiàn)的,Socket是一種文件描述符。
常用的TCP/IP有以下三種類型的嵌套字:
流式嵌套字(SOCK_STREAM)
用于提供面向連接的、可靠的數(shù)據(jù)傳輸服務(wù),即使用TCP進(jìn)行傳輸。
數(shù)據(jù)報(bào)嵌套字(SOCK_DGRAM)
用于提供無連接的服務(wù),即使用UDP進(jìn)行傳輸。
原始嵌套字(SOCK_RAW)
可以讀寫內(nèi)核沒有處理的IP數(shù)據(jù)報(bào),而流式嵌套字只能讀取TCP的數(shù)據(jù),數(shù)據(jù)報(bào)嵌套字只能讀取UDP的數(shù)據(jù)。
因此,如果要訪問其它協(xié)議發(fā)送的數(shù)據(jù)必須使用原始嵌套字,它允許對(duì)底層協(xié)議(如IP或ICMP)直接訪問。
2.2 端口
TCP/IP協(xié)議中的端口,端口號(hào)的范圍從0~65535。
一類是由互聯(lián)網(wǎng)指派名字和號(hào)碼公司ICANN負(fù)責(zé)分配給一些常用的應(yīng)用程序固定使用的“周知的端口”,其值一般為0~1023。例如http的端口號(hào)是80,F(xiàn)TP為21,SSH為22,Te.NET為23等。
還有一類是用戶自己定義的,通常是大于1024的整型值。
2.3 網(wǎng)絡(luò)地址
網(wǎng)絡(luò)通信,歸根到底還是進(jìn)程間的通信(不同計(jì)算機(jī)上的進(jìn)程間通信)。
在網(wǎng)絡(luò)中,每一個(gè)節(jié)點(diǎn)(計(jì)算機(jī)或路由)都有一個(gè)網(wǎng)絡(luò)地址,如192.168.1.4,也就是IP地址。
兩個(gè)進(jìn)程通信時(shí),首先要確定各自所在的網(wǎng)絡(luò)節(jié)點(diǎn)的網(wǎng)絡(luò)地址。
但是,網(wǎng)絡(luò)地址只能確定進(jìn)程所在的計(jì)算機(jī),而一臺(tái)計(jì)算機(jī)上很可能同時(shí)運(yùn)行著多個(gè)進(jìn)程,所以僅憑網(wǎng)絡(luò)地址還不能確定到底是和網(wǎng)絡(luò)中的哪一個(gè)進(jìn)程進(jìn)行通信,因此套接口中還需要包括其他的信息,也就是端口號(hào)(PORT)。
在一臺(tái)計(jì)算機(jī)中,一個(gè)端口號(hào)一次只能分配給一個(gè)進(jìn)程,也就是說,在一臺(tái)計(jì)算機(jī)中,端口號(hào)和進(jìn)程之間是一一對(duì)應(yīng)關(guān)系。
所以,使用端口號(hào)和網(wǎng)絡(luò)地址的組合可以唯一的確定整個(gè)網(wǎng)絡(luò)中的一個(gè)網(wǎng)絡(luò)進(jìn)程。
例如,如網(wǎng)絡(luò)中某一臺(tái)計(jì)算機(jī)的IP為192.168.1.4,操作系統(tǒng)分配給計(jì)算機(jī)中某一應(yīng)用程序進(jìn)程的端口號(hào)為1500,則此時(shí)192.168.1.4 1500就構(gòu)成了一個(gè)套接口。
2.4網(wǎng)絡(luò)地址的格式
在Socket程序設(shè)計(jì)中,struct sockaddr用于記錄網(wǎng)絡(luò)地址,其格式如下:
struct sockaddr
{
unsigned short sa_family; /*協(xié)議族,采用AF_XXX的形式,例如AF_INET(IPv4協(xié)議族)*/
char sa_data[14]; /*14字節(jié)的協(xié)議地址,包含該socket的IP地址和端口號(hào)。*/
};
但在實(shí)際編程中,并不針對(duì)sockaddr數(shù)據(jù)結(jié)構(gòu)進(jìn)行操作,而是用與其等價(jià)的sockaddr_in數(shù)據(jù)結(jié)構(gòu):
struct sockaddr_in
{
short int sa_family; /*地址族*/
unsigned short int sin_port; /*端口號(hào)*/
struct in_addr sin_addr; /*IP地址*/
unsigned char sin_zero[8]; /*填充0 以保持與struct sockaddr同樣大小*/
};

2.4.1 網(wǎng)絡(luò)地址的轉(zhuǎn)換
IP地址通常用數(shù)字加點(diǎn)(如192.168.1.a)表示,而在struct in_addr中使用的式32位整數(shù)表示。因此,Linux提供如下函數(shù)進(jìn)行兩者之間的轉(zhuǎn)換:
- inet_aton()函數(shù):
所需要頭文件
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函數(shù)格式:
int inet_aton(const char *cp, struct in_addr *inp);
函數(shù)功能:將a.b.c.d字符串形式的IP地址轉(zhuǎn)換成32位網(wǎng)絡(luò)序號(hào)IP地址;*cp:存放字符串形式的IP地址的指針*inp:存放32位的網(wǎng)絡(luò)序號(hào)IP地址
返回值:轉(zhuǎn)換成功,返回非0,否則返回0;
- inet_ntoa()函數(shù):客戶機(jī)端:
所需要頭文件
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
函數(shù)格式:
char *inet_ntoa(struct in_addr in);
函數(shù)功能:將32位網(wǎng)絡(luò)序號(hào)IP地址轉(zhuǎn)換成a.b.c.d字符串形式的IP地址;in:Internet主機(jī)地址的結(jié)構(gòu)
返回值:轉(zhuǎn)換成功,返回一個(gè)字符指針,否則返回NULL;

2.4 字節(jié)序
不同的CPU采用對(duì)變量的字節(jié)存儲(chǔ)順序可能不同。
常用的X86結(jié)構(gòu)是小端模式,很多的ARM,DSP都為小端模式,即內(nèi)存的低地址存儲(chǔ)數(shù)據(jù)的低字節(jié),高地址存儲(chǔ)數(shù)據(jù)的高字節(jié)。
而KEIL C51則為大端模式,內(nèi)存的高地址存儲(chǔ)數(shù)據(jù)的低字節(jié),低地址存儲(chǔ)數(shù)據(jù)高字節(jié)。
對(duì)于網(wǎng)絡(luò)傳輸來說,數(shù)據(jù)順序必須是一致的,網(wǎng)絡(luò)字節(jié)順序采用大端字節(jié)序方式。
下面是四個(gè)常用的轉(zhuǎn)換函數(shù):
主機(jī)轉(zhuǎn)網(wǎng)絡(luò):
htons()函數(shù):
所需要頭文件:
#include <netinet/in.h>
函數(shù)格式:
unsigned short int htons(unsigned short int hostshort)
函數(shù)功能:將參數(shù)指定的16位主機(jī)(host)字符順序轉(zhuǎn)換成網(wǎng)絡(luò)(net)字符順序;hostshort:待轉(zhuǎn)換的16位主機(jī)字符順序數(shù)返回值:返回對(duì)應(yīng)的網(wǎng)絡(luò)字符順序數(shù);
- htonl()函數(shù):
所需要頭文件:
#include <netinet/in.h>
函數(shù)格式:
unsigned long int htons(unsigned long int hostlong)
函數(shù)功能:將參數(shù)指定的32位主機(jī)(host)字符順序轉(zhuǎn)換成網(wǎng)絡(luò)(net)字符順序;hostlong:待轉(zhuǎn)換的32位主機(jī)字符順序數(shù)返回值:返回對(duì)應(yīng)的網(wǎng)絡(luò)字符順序數(shù);
網(wǎng)絡(luò)轉(zhuǎn)主機(jī):
- ntohs()函數(shù):
所需要頭文件:
#include <netinet/in.h>
函數(shù)格式:
unsigned short int ntohs(unsigned short int netshort)
函數(shù)功能:將參數(shù)指定的16位網(wǎng)絡(luò)(net)字符順序轉(zhuǎn)換成主機(jī)(host)字符順序;netshort:待轉(zhuǎn)換的16位網(wǎng)絡(luò)字符順序數(shù)
返回值:返回對(duì)應(yīng)的主機(jī)字符順序數(shù);
- ntohl()函數(shù):
所需要頭文件:
#include <netinet/in.h>
函數(shù)格式:
unsigned long int ntohl(unsigned long int netlong)
函數(shù)功能:
將參數(shù)指定的32位網(wǎng)絡(luò)(net)字符順序轉(zhuǎn)換成主機(jī)(host)字符順序;
netshort:待轉(zhuǎn)換的32位網(wǎng)絡(luò)字符順序數(shù)
返回值:
返回對(duì)應(yīng)的主機(jī)字符順序數(shù);