#Socket簡介
是一個(gè)編程接口
是一種特殊的文件描述符(everything in Unix is a file)
并不僅限于TCPIP協(xié)議
面向連接(Transmission Control Protocol - TCPIP)
無連接(User Datagram Protocol-UDP 和 Inter-Network Packet Exchange-IPX)
#Socket類型
流式套接字(SOCK_STREAM)
提供了一個(gè)面向連接,可靠的數(shù)據(jù)傳輸服務(wù),數(shù)據(jù)無差錯(cuò),無重復(fù)的發(fā)送且
按發(fā)送順序接收。內(nèi)設(shè)置流量控制,避免數(shù)據(jù)流淹沒慢的接收方。數(shù)據(jù)被看作是
字節(jié)流,無長度限制
數(shù)據(jù)報(bào)套接字(SOCK_DGRAM)
提供無連接服務(wù)。數(shù)據(jù)包以獨(dú)立數(shù)據(jù)包的形式被發(fā)送,不提供無差錯(cuò)保證,
數(shù)據(jù)可能丟失或重復(fù),順序發(fā)送,可能亂序接收
原始套接字(SOCK_RAW)
可以對(duì)較低層次協(xié)議如IP,ICMP直接訪問
#IP地址
IP地址是Internet中主機(jī)的標(biāo)識(shí)
Internet中的主機(jī)要與別的機(jī)器通信必須具有一個(gè)IP地址
IP地址為32位(IPV4)或者128位(IPV6)
每個(gè)數(shù)據(jù)包都必須攜帶目的IP地址和源IP地址,路由器依靠此信息為數(shù)據(jù)包
選擇路由
表示形式:常用點(diǎn)分形式,如202.38.64.10,最后都會(huì)轉(zhuǎn)換為一個(gè)32位的無符號(hào)
整數(shù)。
#IP地址的轉(zhuǎn)換
inet_aton()
將strptr所指的字符串轉(zhuǎn)換成32位的網(wǎng)絡(luò)字節(jié)序二進(jìn)制值
int inet_aton(const char *strptr, struct in_addr *addrptr);
inet_addr()
功能同上,返回轉(zhuǎn)換后的地址
in_addr_t inet_addr(const char *strptr);
inet_ntoa()
將32位網(wǎng)絡(luò)字節(jié)序二進(jìn)制地址轉(zhuǎn)換成點(diǎn)分十進(jìn)制的字符串。
char *inet_ntoa(struct in_addr inaddr);
#端口號(hào)
為了區(qū)分一臺(tái)主機(jī)接收到的數(shù)據(jù)包應(yīng)該轉(zhuǎn)交給哪個(gè)進(jìn)程來進(jìn)行處理,使用端口號(hào)
來區(qū)分
TCP端口號(hào)與UDP端口號(hào)獨(dú)立(協(xié)議不同可以使用同一個(gè)端口)
三無組:協(xié)議,IP,端口
端口號(hào)一般由IANA(Internet Assigned Numbers Authority)管理
眾所周知端口:1~1023(1~255之間為眾所周知端口,256~1023端口通常由
UNIX系統(tǒng)占用
已登記端口:1024~49151
動(dòng)態(tài)或私有端口:49152~65535
#字節(jié)序
不同類型CPU的主機(jī)中,內(nèi)存存儲(chǔ)多字節(jié)整數(shù)序列有兩種方法,稱為主機(jī)字節(jié)序(HBO):
小端序(little-endian)-低字節(jié)存儲(chǔ)在低地址
將低字節(jié)存儲(chǔ)在起始地址,稱為"Little-Endian"字節(jié)序,Intel,AMD等
采用的是這種方式
大端序(big-endian)-高序字節(jié)存儲(chǔ)在低地址
將高字節(jié)存儲(chǔ)在起始地址,稱為"Big-Endian"字節(jié)序,由ARM,Motorola
等所采用
網(wǎng)絡(luò)中傳輸?shù)臄?shù)據(jù)必須按網(wǎng)絡(luò)字節(jié)序,即大端字節(jié)序
在大部分PC機(jī)上,當(dāng)應(yīng)用進(jìn)程將整數(shù)送入socket前,需要轉(zhuǎn)化成網(wǎng)絡(luò)字節(jié)序;當(dāng)
應(yīng)用進(jìn)程從socket取出整數(shù)后,要轉(zhuǎn)化成小端字節(jié)序
#字節(jié)序轉(zhuǎn)換函數(shù)
把給定系統(tǒng)所采用的字節(jié)序稱為主機(jī)字節(jié)序,為了避免不同類別主機(jī)之間在數(shù)據(jù)
交換時(shí)由于對(duì)于字節(jié)序的不用而導(dǎo)致的差錯(cuò),引入了網(wǎng)絡(luò)字節(jié)序
主機(jī)字節(jié)序到網(wǎng)絡(luò)字節(jié)序:
u_long htonl(u_long hostlong);
u_short htons(u_short short);
網(wǎng)絡(luò)字節(jié)序到主機(jī)字節(jié)序
u_long ntohl(u_long hostlong);
u_short ntohs(u_short short);
#網(wǎng)絡(luò)編程相關(guān)API
int Socket(int domain, int type, int protocol);
int bind(int Sockfd, struct sockaddr *my_addr, int addrlen);
int listen(int sockfd, in backlog);
int accept(int sockfd, struct sockaddr *addr, Socklen_t *addrlen);
int connect(int sockfd, const struct sockaddr *addr, Socklen_t addrlen);
ssize_t send(int sockfd, const void *buf, size_t len, int flags);
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, Socklen_t addrlen);
ssize_t recv(int sockfd, void *buf, size_t len, int flags);
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, Socklen_t *addrlen);
int shutdown(int sockfd, int how);
#command:
netstat -anpt
#地址結(jié)構(gòu)的一般用法
1.定義一個(gè)struct sockaddr_in類型的變量并清空
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
2.填充地址信息
myaddr.sin_family = PF_INET;
myaddr.sin_port = htons(8888);
myaddr.sin_addr.s_addr = inet_addr("192.168.1.100");
3.將該變量強(qiáng)制轉(zhuǎn)換為struct sockaddr類型在函數(shù)中使用
bind(listenfd,(struct sockaddr *)&myaddr, sizeof(myaddr));
#地址轉(zhuǎn)換函數(shù)
unsigned long inet_addr(const char *address);
int inet_aton(const char *cp, struct in_addr *inp);
char *inet_ntoa(struct in_addr in);
socket流程圖: