網(wǎng)絡(luò)模型
物理層
物理層表示的是比特流傳輸畅形,通常包括串口/COM口、并行/LPT口燃少、USB束亏、網(wǎng)線接口铃在、電話線接口阵具;其中串口包括智能儀表接口(RS-232)、RS-485(聯(lián)網(wǎng)儀表接口)定铜;并行接口包括IEEE1284打印機(jī)掃描儀接口阳液;USB接口包括USB2.0,USB3.0接口揣炕;網(wǎng)線接口:RJ45水晶頭接口帘皿;電話線接口是RJ11;
數(shù)據(jù)鏈路層
數(shù)據(jù)鏈路層畸陡,用于實(shí)現(xiàn)網(wǎng)絡(luò)控制鹰溜,鏈路糾錯(cuò);常用的協(xié)議包括:LLC(Logical Link Control)邏輯鏈路控制協(xié)議丁恭、MAC(Multiple Access Control)多路訪問控制協(xié)議曹动、PPP(Point to Point Protocol)點(diǎn)對(duì)點(diǎn)協(xié)議;
網(wǎng)絡(luò)層
實(shí)現(xiàn)的功能是尋址和路由功能牲览,常用的協(xié)議包括:IP(Internet Protocol)互聯(lián)網(wǎng)協(xié)議墓陈、ARP(Address Resolution Protocol)地址解析協(xié)議、RARP(Reverse Address Resolution Protocol)反向地址解析協(xié)議、RIP(Routing Information Protocol)路由信息協(xié)議贡必、ICMP(Internet Control Message Protocol)互聯(lián)網(wǎng)報(bào)文控制協(xié)議兔港、Enternet(以太網(wǎng)協(xié)議);
傳輸層
用于建立主機(jī)端到端的鏈接仔拟;TCP(Transmission Control Protocol)傳輸控制協(xié)議衫樊、UDP(User Datagram Protocol)用戶數(shù)據(jù)報(bào)協(xié)議;
會(huì)話層
用于建立利花、維護(hù)和管理會(huì)話橡伞;沒有相關(guān)的協(xié)議
表示層
格式轉(zhuǎn)換,加密解密晋被;也沒有常見的協(xié)議兑徘;
應(yīng)用層
用于提供應(yīng)用進(jìn)程通信,常用的協(xié)議包括:文件傳輸協(xié)議FTP(File Transfer Protocol)端口號(hào)為21羡洛;遠(yuǎn)程終端協(xié)議Telnet(Remote Terminal Protocol)挂脑,端口號(hào)為23;簡單郵件傳輸協(xié)議SMTP(Simple Mail Transfer Protocol)欲侮,端口號(hào)為25崭闲;簡單文件傳輸協(xié)議TFTP(Trivial File Transfer Protocol)端口號(hào)為69;超文本傳輸協(xié)議HTTP(Hypertext Transfer Protocol)威蕉,端口號(hào)為80刁俭;安全套接層文本傳輸協(xié)議HTTPS(Hypertext Transfer Protocol over Secure Socket Layer),端口號(hào)為443韧涨;域名解析協(xié)議DNS(Domain Name Service)牍戚,自舉報(bào)協(xié)議BOOT(Bootstrap Protocol);
&8195;總結(jié):
功能角度:
1虑粥、1,2層主要用于解決網(wǎng)絡(luò)信道問題如孝;
2、3,4層主要用于解決傳輸問題娩贷;
3第晰、5,6,7層主要用于處理對(duì)應(yīng)用進(jìn)程的訪問;
控制角度:
1彬祖、1,2,3,是通信子網(wǎng)層茁瘦;
2、4,5,6,7層是主機(jī)控制層
數(shù)據(jù)封裝:
No | 信息單位 | 層 |
---|---|---|
1 | 比特(bit) | 物理層 |
2 | 幀(frame) | 數(shù)據(jù)鏈路層 |
3 | 數(shù)據(jù)包(packet) | 網(wǎng)絡(luò)層 |
4 | 段(segment)/數(shù)據(jù)報(bào)(datagram) | 傳輸層 |
5-7 | 消息(message) | 應(yīng)用層 |
TCP/IP四層模型:
數(shù)據(jù)鏈路層储笑,網(wǎng)絡(luò)層甜熔,傳輸層,應(yīng)用層南蓬;
scoket編程接口
轉(zhuǎn)換操作
字節(jié)轉(zhuǎn)換操作
網(wǎng)絡(luò)序轉(zhuǎn)主機(jī)序:ntohs()纺非,network to host short哑了,表示將unsigned short類型的從網(wǎng)絡(luò)序轉(zhuǎn)換到主機(jī)序;ntohl()烧颖,network to host long弱左,把unsigned long類型從網(wǎng)絡(luò)序轉(zhuǎn)化到主機(jī)序;需要進(jìn)行轉(zhuǎn)換操作一般是端口炕淮;
remote_addr.sin_port = htons(atoi(argv[2]);
主機(jī)序轉(zhuǎn)網(wǎng)絡(luò)序:htons()拆火,host to network short,把unsigned long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序涂圆;htonl()们镜,host to network long,把unsigned long類型從主機(jī)序轉(zhuǎn)換到網(wǎng)絡(luò)序润歉;
IP地址轉(zhuǎn)換操作
IPv4專用:點(diǎn)分十進(jìn)制數(shù)串轉(zhuǎn)網(wǎng)絡(luò)字節(jié)序長整型:inet_aton(const char *string模狭,struct in_addr *addr);string:表示點(diǎn)分十進(jìn)制IP地址字符串踩衩;addr:網(wǎng)絡(luò)字節(jié)序長整型IP地址嚼鹉;返回值0表示成功,非0表示失斍弧锚赤;in_addr_t inet_addr(const char *string);string:表示點(diǎn)分十進(jìn)制IP地址字符串褐鸥;返回值IPADDR_NONE表示失敗线脚,非INADDR_NONE:表示網(wǎng)絡(luò)字節(jié)序長整型IP地址;網(wǎng)絡(luò)序長整型轉(zhuǎn)點(diǎn)分十進(jìn)制數(shù)串:char (inet_ntoa(struct in_addr addr)叫榕;addr:網(wǎng)絡(luò)字節(jié)序長整型IP地址浑侥;返回值:非NULL:表示點(diǎn)分十進(jìn)制IP地址字符串;NULL:表示失敶浠簟锭吨;
?IPv4/IPv6通用(推薦這個(gè)):點(diǎn)分十進(jìn)制數(shù)串轉(zhuǎn)網(wǎng)絡(luò)字節(jié)序長整型:int inet_pton(int af, const char *src,void *dst);af:表示地址簇:AF_INET寒匙,AF_INET6;src:點(diǎn)分十進(jìn)制IP地址串躏将;dst:網(wǎng)絡(luò)字節(jié)序長整型IP地址锄弱;返回值:<0:表示失敗,返回值如果是0表示af或者src格式不對(duì)祸憋;網(wǎng)絡(luò)字節(jié)序長整型轉(zhuǎn)點(diǎn)分十進(jìn)制數(shù)串:const char *inet_ntop(int af,const void *src会宪,char *dst,socklen_t cnt)蚯窥;af:表示地址簇:AF_INET掸鹅,AF_INET6塞帐;src:表示網(wǎng)絡(luò)字節(jié)序長整型IP地址;dst:表示點(diǎn)分十進(jìn)制IP地址字符串巍沙;cnt:表示緩沖區(qū)dst的大锌选;返回值NULL:表示失斁湫榔幸;非NULL表示dst指針;
主機(jī)名轉(zhuǎn)換操作
struct hostent {
h_name //表示主機(jī)名字
h_alicases //以空指針結(jié)尾的主機(jī)別名隊(duì)列
h_addrtype //表示地址類型:AF_INET矮嫉;AF_INET6削咆;
h_length //表示地址長度,在AF_INET地址類型為4蠢笋;
h_addr //第一個(gè)IP地址
h_addr_list //以空指針結(jié)尾的IP地址列表
}
主機(jī)名轉(zhuǎn)地址:struct hostent *gethostbyname(const char *hostname)拨齐;hostname:表示主機(jī)名;返回值:NULL昨寞,表示出錯(cuò)奏黑;非NULL:表示hostent結(jié)構(gòu)指針;
mygethostbyname.c
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <stdio.h>
int main(int argc, char **argv)
{
char *ptr, **pptr;
struct hostent *addr;
char str[32];
ptr = argv[1];
if(2!=argc){
printf("Usage:%s <www.example.com>\n",argv[0]);
return 0;
}
if((addr = gethostbyname(ptr)) == NULL)
{
printf(" gethostbyname error for host:%s\n", ptr);
return 0;
}
printf("hostname len:%d\n",addr->h_length);
printf("hostname type:%d\n",addr->h_addrtype);
printf("official hostname:%s\n",addr->h_name);
for(pptr = addr->h_aliases; *pptr != NULL; pptr++)
printf(" alias:%s\n",*pptr);
switch(addr->h_addrtype)
{
case AF_INET:
case AF_INET6:
pptr=addr->h_addr_list;
for(; *pptr!=NULL; pptr++)
printf(" address:%s\n",
inet_ntop(addr->h_addrtype, *pptr, str, sizeof(str)));
printf(" first address: %s\n",
inet_ntop(addr->h_addrtype, addr->h_addr, str, sizeof(str)));
break;
default:
printf("unknown address type\n");
break;
}
return 0;
}
地址轉(zhuǎn)主機(jī)名:sruct hostent *gethostbyaddr(const char *addr,int len,int type)编矾;addr:網(wǎng)絡(luò)字節(jié)順序地址熟史;len:地址的長度,在AF_INET類型地址中為4窄俏;type:地址類型:AF_INET蹂匹,AF_INET6;返回值:NULL表示出錯(cuò)凹蜈,非NULL表示hostent結(jié)構(gòu)指針限寞;
gethostbyaddr.c
scoket操作
常見操作
創(chuàng)建操作:int socket(int domain,int type,int protocol);domain:表示協(xié)議域:AF_INET仰坦,表示IPv4履植,AF_INET6,表示IPv6悄晃;AF_LOCAL:表示unix域玫霎;type:SCOKET_STREAM:流式套接字,提供面向連接妈橄、可靠地?cái)?shù)據(jù)傳輸服務(wù)庶近, 數(shù)據(jù)按照字節(jié)流、按順序收發(fā)眷蚓,保證在傳輸過程中無丟失鼻种,無冗余;TCP協(xié)議支持該套接字沙热;SOCKET_DGRAM:數(shù)據(jù)報(bào)套接字叉钥,提供面向無連接的服務(wù)罢缸,數(shù)據(jù)收發(fā)無序,不能能夠保證數(shù)據(jù)的準(zhǔn)確到達(dá)投队,UDP協(xié)議支持該套接字枫疆;SCOK_RAMW:表示原始套接字,只允許對(duì)于低于傳輸層的協(xié)議或物理網(wǎng)絡(luò)直接訪問,經(jīng)常用于檢測(cè)新的協(xié)議;
int listenfd = socket(AF_INET,SOCKSTREAM,0)
類型 | 作用 |
---|---|
流式套接字(SOCKET_STREAM) | 提供了一個(gè)面向連接的橄登,可靠地?cái)?shù)據(jù)傳輸服務(wù),數(shù)據(jù)無差錯(cuò)钞螟,無重復(fù)的發(fā)送且按照發(fā)送順序接收,內(nèi)置流量控制谎碍,避免數(shù)據(jù)流淹沒慢的接收方鳞滨。數(shù)據(jù)被看做字節(jié)流,無長度限制蟆淀; |
數(shù)據(jù)包套接字(SOCKET_DGRAM) | 提供無連接服務(wù)拯啦,數(shù)據(jù)報(bào)以獨(dú)立數(shù)據(jù)包的形式被發(fā)送,不提供無差錯(cuò)保證熔任,數(shù)據(jù)可能丟失或重復(fù)褒链,順序發(fā)送,可能亂序接受疑苔; |
原始套接字(SOCKET_RAM) | 可以對(duì)較低層次協(xié)議甫匹,如IP,ICMP直接訪問惦费; |
Protocol:協(xié)議:0:表示自動(dòng)根據(jù)type匹配協(xié)議兵迅;IPPROTO_TCP:表示TCP協(xié)議;IPPROTO_UDP:表示使用UDP協(xié)議薪贫;
返回值:-1:表示失敗恍箭,>0:socket描述符;
?關(guān)閉操作:int close(int fd)瞧省;或者使用函數(shù):int shurdown(int socketfd扯夭,int howto);socket:socket套接字臀突;howto:SHUT_RD:值為0表示關(guān)閉連接的流勉抓;SHUT_WR:值為1表示關(guān)閉連接的寫;SHUT_RDWR:值為2表示連接的讀和寫都關(guān)閉候学;
這兩個(gè)函數(shù)的區(qū)別:close把描述符的引用計(jì)數(shù)減1,僅在計(jì)數(shù)變?yōu)?時(shí)才關(guān)閉套接字纵散;shutdown不管引用計(jì)數(shù)器就激發(fā)TCP的正常連接終止序列梳码;2隐圾、close終止讀和寫兩個(gè)方向的數(shù)據(jù)傳送;shutdown可以指定哪個(gè)方向被關(guān)閉掰茶,或者是都關(guān)閉暇藏;
close(connfd);
close(listenfd);
屬性:設(shè)置socket套接字:int setsockopt(int socketfd, int level,int optname,const void *optval濒蒋,socklen_t optlen)盐碱;socketfd:套接字描述符;level:選項(xiàng)層次:SOL_SOCKET:通用套接字選項(xiàng)沪伙;level:選項(xiàng)層次:SOL_SOCKET:表示通用套接字選項(xiàng)瓮顽;IPPROTO_TCP:表示TCP選項(xiàng);IPPROTO_IP:表示IP選項(xiàng)围橡;IPPROTO_IPv6:表示IPv6選項(xiàng)暖混;
optname:
SOL_SOCKET級(jí)別:
SO_REUSEADDR 讓端口釋放后立即就可以被再次使用,一個(gè)端口釋放后翁授,會(huì)等待兩分鐘之后才能夠被再次使用拣播;
SO_RCVBUF 接收確定緩沖區(qū)大小
SO_SNDBUF 發(fā)送緩沖區(qū)大小
SO_SNDTIMEO 表示發(fā)送實(shí)現(xiàn)
SO_RECVTIMEO 表示接受實(shí)現(xiàn)
SO_BROADCAST 廣播
SO_DONTLINGER 關(guān)閉端口后不進(jìn)入TIME_WAIT狀態(tài)
SO_LINGER 關(guān)閉端口后,進(jìn)入TIME_WAIT狀態(tài)的屬性收擦;
struct linger {
u_short l_onoff;
u_short l_linger;
}
IPPROTO_IP級(jí)別:IP_ADD_MEMBERSHIP:加入指定的組播組
struct ip_mreq{
struct in_addr imr_multiaddr贮配;//組播組的IP地址;
struct in_addr imr_interface塞赂;//本地某一網(wǎng)絡(luò)設(shè)備接口的IP地址泪勒;
}
IP_DROP_MEMBERSHIP:表示離開指定的組播組;IP_MULTCAST_IF:指定發(fā)送組播數(shù)據(jù)的IP地址减途;IP_MULTICAST_LOOP:發(fā)送組播數(shù)據(jù)的主機(jī)是否作為接收組播數(shù)據(jù)的組播成員酣藻;optval:選項(xiàng)值指針;optlen:optval緩沖區(qū)長度鳍置;返回值0表示成功辽剧,-1表示失敗税产;
int flag =1;
setsockopt(listenfd,SQL_SOCKET,SO_REUSEADDR,&flag,sizeof(flag));
屬性的獲扰陆巍:int getoptsockopt(int sockfd,int level辟拷,int optname撞羽,void *optval,socklen_t *optlen)衫冻;sockfd:表示套接字描述符诀紊;level:表示選項(xiàng)層次:SOL_SOCKET:通用套接字選項(xiàng);IPPROTO_TCP:TCP選項(xiàng)隅俘;IPPROTO_IP:表示IP選項(xiàng)邻奠;IPPROTO_IPv6:表示IPv6選項(xiàng)笤喳;
optname:選項(xiàng):SOL_SOCKET級(jí)別:SO_REUSEADDR:讓端口釋放后可以立即被再次使用,一二端口釋放后等待兩分鐘之后才能夠被再次使用碌宴;SO_RECVBUF:表示結(jié)束確定緩沖區(qū)大猩苯啤;SO_SNDBUF:表示發(fā)送緩沖區(qū)大蟹×汀呜象;SO_SNDTIMEO:表示發(fā)送時(shí)限;SO_RECVTIMEO:接收時(shí)限碑隆;SO_BROADCAST:表示廣播恭陡;SO_DONTLINGER:表示關(guān)閉端口后不進(jìn)入TIME_WAIT狀態(tài);SO_LINGER:端口的狀態(tài)進(jìn)入TIME_WAIT的屬性干跛;
struct linger {
u_short l_onoff;
u_short l_linger;
};
IPPROTO_IP級(jí)別:IP_ADD_MEMBERSHIP子姜,表示加入指定的組播組;IP_DROP_MEMBERSHIP:表示離開指定的組播組楼入;IP_MULTICAST_IF:指定發(fā)送組播數(shù)據(jù)的IP地址哥捕;IP_MULTICAST_LOOP:發(fā)送組播數(shù)據(jù)的主機(jī)是否作為接收組播數(shù)據(jù)的組播成員;
?optval:選項(xiàng)指針嘉熊;optlen:optval緩沖區(qū)長度遥赚;返回值0表示成功,-1表示失敳簟凫佛;
?綁定操作:int bind(int socket,const struct sockaddr *address孕惜,socklen_t address_len)愧薛;socket:表示套接字描述符;address:地址和端口號(hào)衫画;address_len:address緩沖區(qū)的長度毫炉;返回值:0表示成功,SOCKET_ERROR:表示失斚髡帧瞄勾;
bind(listenfd,(struct sockaddr*)&local_addr,sizeof(local_addr)));
返回值為-1表示出錯(cuò);
監(jiān)聽操作:int listen(int sockfd弥激,int backlog)进陡;sockfd:監(jiān)聽的socket描述符;backlog:排隊(duì)的最大連接數(shù)目微服;返回值:0表示成功趾疚,-1表示失敗;
listen(listenfd,10)
-1表示失敗盗蟆,10表示隊(duì)列中允許的最大鏈接數(shù)目戈二;
連接操作:int connect(int sockfd,const struct sockaddr* addr舒裤,socket_t addrlen)喳资;sockfd:客戶端的socket描述字;addr:服務(wù)器的socket地址腾供;addrlen:服務(wù)器的socket地址的長度仆邓;返回值0表示成功,-1表示失敯楸睢节值;
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.ain_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]);
connect(connfd,struct sockaddr*)&remote_addr,sizeof(remote_addr));
接受操作:int accept(int sockfd,struct sockaddr *addr榜聂,socklen_t *addrlen)搞疗;sockfd:表示服務(wù)器的socket描述符,用于監(jiān)聽的socket描述符须肆;addr:client的socket地址匿乃;addrlen:client的socket地址長度;返回值:-1表示失斖慊恪幢炸;非-1值表示鏈接描述符;
accept(listenfd,(struct sockaddr*)&remote_addr,&remote_addr_len);
返回值-1表示失斁芗宛徊;
發(fā)送操作:ssize_t wite(int fd, const void* buf,size_t len);fd:表示文件描述符逻澳;buf:表示用于寫入數(shù)據(jù)的位置闸天;len:寫入數(shù)據(jù)的長度;返回值>0表示所寫的字節(jié)的長度斜做;<0表示出錯(cuò)苞氮;
ssize_t send(int socked,const void *buf, size_t len,int flags);sockfd:表示sockfd文件描述符陨享;buf:用于寫入數(shù)據(jù)葱淳;len:寫入數(shù)據(jù)的實(shí)際長度;flags:通常為0抛姑;>0:寫入數(shù)據(jù)的實(shí)際長度赞厕;<0:表示出錯(cuò);ssize_t sendto(int sockfd,const void *buf定硝,size_t len皿桑,ing flags,const struct sockaddr *dest_addr,socklen_t addrlen)诲侮;sockfd:表示sockfd文件描述符镀虐;buf:表示寫入數(shù)據(jù);len:表示寫入數(shù)據(jù)的實(shí)際長度沟绪;flags:通常為0刮便;dest_addr:目標(biāo)socket地址;addrlen:目標(biāo)socket地址的長度绽慈;返回值:>0表示寫入數(shù)據(jù)的實(shí)際字節(jié)數(shù)恨旱;<0:表示出錯(cuò);
?接收操作:ssize_t read(int fd坝疼,void *buf搜贤,size_t len);fd:表示文件描述符钝凶;buf:表示讀取數(shù)據(jù)仪芒;len:表示讀取數(shù)據(jù)的長度;返回值:0:表示讀取到文件的結(jié)束耕陷;>0:書籍所讀取的字節(jié)數(shù)掂名;<0:表示出錯(cuò);ssize_t recv(int sockfd,void *buf啃炸,size_t len铆隘,int flags);fd:表示文件描述符南用;buf:表示讀取的數(shù)據(jù)膀钠;len:表示讀取數(shù)據(jù)的長度;flags:通常設(shè)置為0裹虫;返回值:0表示讀取到文件的結(jié)束肿嘲;>0:表示所讀取的實(shí)際的字節(jié)數(shù);<0:表示出錯(cuò)筑公;ssize_t recvfrom(int sockfd雳窟,void *buf,size_t len匣屡,int flags封救,struct sockaddr *src_addr,socklen_t *addrlen)捣作;fd:文件描述符誉结;buf:表示用于讀取數(shù)據(jù);len:讀取數(shù)據(jù)的長度券躁;flags:通常為0惩坑;dest_addr:目標(biāo)socket地址掉盅;addrlen:目標(biāo)socket地址長度;返回值:0:表示讀取為文件的結(jié)束以舒;>0:表示實(shí)際所讀的字節(jié)數(shù)趾痘;<0:表示出錯(cuò);
#######幾個(gè)相關(guān)的結(jié)構(gòu)體
struct sockaddr {
unisigned short sa_family;
char sa_data[14];
};
IPv4:
struct sockaddr_in {
short sin_family;
unsigned short sin_port;
struct in_addr sin_addr;
unsigned char sin_zero[8];
};
struct in_addr {
in_addr_t s_addr;
};
typedef unsigned int in_addr_t;
IPv6:
struct sockaddr_in6 {
uint8_t sin6_len;//IPv6為固定的24字節(jié)長度蔓钟;
sa_family_t sin6_family; //地址簇類型永票,為AF_INET6;
in_port_t sin6_port; //16位端口號(hào)奋刽,網(wǎng)絡(luò)字節(jié)序瓦侮;
unit32_t sin6_flowinfo;//32位流標(biāo)簽佣谐;/128位IP地址;
struct in6_addr sin6_addr;
};
知識(shí)總結(jié)
特殊地址設(shè)置:通配地址:IPv4:in_addr.sin_addr.s_addr = htonl(INADDR_ANY)方妖;IPv6:in6_addr.sin6_addr = in6adddr_any;回環(huán)地址:
IPv4:in_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK)狭魂;IPv6:in6_addr.sin_addr = in6adr_loopback;廣播地址:IPv4:in_addr.s.addr = htonl(INADDR_BROADCAST)党觅;IPv6:沒有廣播雌澄;
原則
C/S:client/server:必須制定連接/發(fā)送的IP(廣播地址,回環(huán)地址或者某個(gè)具體地址)杯瞻;必須制定連接發(fā)送的port镐牺;
S/C:server/client:IP指定為通配地址,回環(huán)地址或者某個(gè)具體地址魁莉;必須制定綁定監(jiān)聽/接收的port睬涧;
基本流程
TCP:Server:socket-->bind-->listen-->accept-->recv/read-->send/write;Client:socket-->connect-->send/write-->recv/read旗唁;UDP:單播畦浓,組播/廣播;
tcp_client.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(4 != argc){
printf("usage:%s <ip> <#port> <message>\n",argv[0]);
return 1;
}
int connfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == connfd){
perror("socket err");
return 1;
}
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
perror("connect err");
return 1;
}
show_info(connfd);
write(connfd,argv[3],strlen(argv[3])+1);
printf("client send:%s\n",argv[3]);
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
if(-1 == read(connfd,buf,BUFSIZ)){
perror("read err");
return 1;
}
printf("client recv:%s\n",buf);
close(connfd);
}
tcp_client02.c
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
void show_info(int connfd){
struct sockaddr_in local_addr;
bzero(&local_addr,sizeof(local_addr));
socklen_t local_addr_len = sizeof(local_addr);
getsockname(connfd,(struct sockaddr*)&local_addr,&local_addr_len);
printf("client local %s:%d\n",inet_ntoa(local_addr.sin_addr),ntohs(local_addr.sin_port));
struct sockaddr_in peer_addr;
bzero(&peer_addr,sizeof(peer_addr));
socklen_t peer_addr_len = sizeof(peer_addr);
getpeername(connfd,(struct sockaddr*)&peer_addr,&peer_addr_len);
printf("clinet peer %s:%d\n",inet_ntoa(peer_addr.sin_addr),ntohs(peer_addr.sin_port));
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s <ip> <#port> \n",argv[0]);
return 1;
}
int connfd = socket(AF_INET,SOCK_STREAM,0);
if(-1 == connfd){
perror("socket err");
return 1;
}
struct sockaddr_in remote_addr;
bzero(&remote_addr,sizeof(remote_addr));
remote_addr.sin_family = AF_INET;
remote_addr.sin_addr.s_addr = inet_addr(argv[1]);
remote_addr.sin_port = htons(atoi(argv[2]));
if(-1 == connect(connfd,(struct sockaddr*)&remote_addr,sizeof(remote_addr))){
perror("connect err");
return 1;
}
show_info(connfd);
char buf[BUFSIZ];
bzero(buf,BUFSIZ);
while(fgets(buf,BUFSIZ,stdin) != NULL){
write(connfd,buf,strlen(buf)+1);
printf("client send:%s\n",buf);
bzero(buf,BUFSIZ);
if(-1 == read(connfd,buf,BUFSIZ)){
perror("read err");
return 1;
}
printf("client recv:%s\n",buf);
}
close(connfd);
}
基本概念
套接字
socket是一個(gè)編程接口检疫,是一種特殊的文件描述符讶请,everything in unix is a file;
協(xié)議域:AF_INET表示IPv4屎媳;AF_INET6:表示IPv6夺溢;AF_LOCAL表示Unix域;
類型:流式套接字:SOCK_STREAM烛谊,用于表示提供面向連接风响、可靠地?cái)?shù)據(jù)傳輸服務(wù),數(shù)據(jù)按照字節(jié)流晒来,按順序的收發(fā)钞诡,保證在傳輸過程中無丟失郑现,無冗余;TCP協(xié)議支持該套接字荧降;數(shù)據(jù)報(bào)套接字:SOCK_DGRAM接箫,提供面向無連接的服務(wù),數(shù)據(jù)收發(fā)無序朵诫,不能保證數(shù)據(jù)的準(zhǔn)確到達(dá)辛友,UDP支持該套接字;原始套接字:SOCK_RAW剪返,允許對(duì)于傳輸層的協(xié)議或者物理層的直接訪問废累;經(jīng)常用于檢測(cè)新的協(xié)議;
協(xié)議控制:IPPROTO_TCP脱盲;IPPROTO_UDP邑滨;
套接字的五大要素:協(xié)議,本地地址钱反,本地端口掖看,遠(yuǎn)程地址,遠(yuǎn)程端口面哥;
兩種協(xié)議
TCP:Transaction Control Protocol:面向連接的數(shù)據(jù)流哎壳,需要經(jīng)過三次握手,四次斷開的過程尚卫,三次握手的過程是用來確定通信的雙方都存在归榕;在三次握手的過程中存在這幾個(gè)標(biāo)識(shí):synchronous:表示用于建立連接;ACK:acknowledgedgement:用于確認(rèn)連接吱涉;FIN:finish表示用于結(jié)束刹泄;PSH:push表適用于傳送;RST:reset表適用于重置邑飒;URG:urgent:表示緊急指針循签;兩個(gè)號(hào)碼:Sequence number:順序號(hào)碼;acknowledge number:用于確認(rèn)的號(hào)碼疙咸;
TCP鏈接經(jīng)常用于數(shù)據(jù)的完整性要求高县匠,數(shù)據(jù)的可靠性要求高,數(shù)據(jù)的性能要求比較低的情況下撒轮;
UDP:User Datagram Protocol表示無連接的數(shù)據(jù)報(bào)服務(wù)乞旦,類比于發(fā)短信;
分類:單播:municast:表示私聊题山;
廣播:broadcast:
發(fā)送者:打開socket-->打開廣播-->設(shè)置發(fā)送地址和端口-->發(fā)送數(shù)據(jù)-->關(guān)閉socket兰粉;
1、打開socket:cfd = socket(AF_INET,SOCK_DGRAM,0)顶瞳;
2玖姑、打開廣播:setsockopt(cfd,SOL_SOCKET,SO_BROADCAST,&n,sizeof(n))愕秫;其中n:0表示關(guān)閉屬性,非0表示打開屬性焰络;
3戴甩、設(shè)置發(fā)送地址和端口:struct sockaddr_in si;
?si.sin_family = AF_INET;//表示用于設(shè)置協(xié)議族,一般使用的是AF_INET闪彼;
?si.sin_port = htons(8080);//用于綁定并且設(shè)置端口甜孤;
?si.sin_addr.s_addr = inet_addr(“255.255.255.255”);
4、發(fā)送數(shù)據(jù):sendto(cfd,buffer,buffer_size,0,(struct sockaddr *)&si,sizeof(si));
5畏腕、關(guān)閉socket:close(cfd)缴川;
接受者:打開socket-->設(shè)置socket-->設(shè)置接受地址和端口-->端口綁定-->接收數(shù)據(jù)-->關(guān)閉socket;
1、打開socket:int cfd = socket(AF_INET,SOCK_DGRAM,0);
2描馅、設(shè)置接受地址和端口:
?struct sockaddr_in si;
?si.sin_family = AF_INET;//一般使用AF_INET把夸;
?si.sin_port = htohs(8000);
?si.sin_addr.si_addr = INADDR_ANY;//一般使用IP地址,用于表示接收任意IP流昏、任意網(wǎng)卡的發(fā)送給指定端口 數(shù)據(jù)扎即;
3、端口綁定:int ret = bind(cfd,(struct sockaddr *)&si,sizeof(si));
4况凉、接收數(shù)據(jù):recv(cfd,buf,22,0);
5、關(guān)閉socket:close(cfd)各拷;
多播/組播(multicast)
多播地址的范圍是:IPv4,224.0.0.0-->239.255.255.255;
范圍 | 名稱 | 作用 |
---|---|---|
224.0.0.0-->224.0.0.255 | 鏈路組播地址 | 路喲協(xié)議和其他用途保留的地址 |
224.0.1.0-->238.255.255.255 | 用戶組播地址 | 用于全球范圍內(nèi)或者網(wǎng)絡(luò)協(xié)議 |
239.0.0.0-->239.255.255.255 | 本地組播地址 | 內(nèi)部網(wǎng)絡(luò)使用 |
TTL:Time To Live生存時(shí)間值刁绒,IP數(shù)據(jù)包北路由其丟棄之前允許通過的最大的網(wǎng)段數(shù)量,TTL的最大值是255烤黍,默認(rèn)值是64知市,作用是避免IP包在網(wǎng)段中的無限循環(huán)和收發(fā),節(jié)省了網(wǎng)絡(luò)資源速蕊;UDP協(xié)議適用的場(chǎng)景:發(fā)送的數(shù)據(jù)少嫂丙,連接的時(shí)間短,傳輸性能要求高规哲,可靠性完整性要求低跟啤;
路徑
IP地址表示的是Internet中主機(jī)的標(biāo)識(shí),32位的IPv4,128位的IPv6唉锌,表示形式IPv4使用點(diǎn)分十進(jìn)制表示隅肥,IPv6使用點(diǎn)分十進(jìn)制或者點(diǎn)分十六進(jìn)制表示;通配地址:0.0.0.0表示主機(jī)上的所有IP地址袄简,多個(gè)網(wǎng)卡可以共用腥放;回環(huán)地址:127.0.0.1,本地虛擬接口绿语,無網(wǎng)卡可用秃症,用于檢查本地網(wǎng)絡(luò)協(xié)議候址;廣播地址:255.255.255.255當(dāng)前路由器均不允許轉(zhuǎn)發(fā)此類廣播;子網(wǎng)廣播地址:xxx.xxx.xxx.255种柑,全子網(wǎng)廣播xxx.xxx.255.255
域名:DNS用于實(shí)現(xiàn)IP地址和域名之間的對(duì)應(yīng)關(guān)系岗仑;
端口:端口是用來區(qū)分一臺(tái)主機(jī)接收到的數(shù)據(jù)報(bào)應(yīng)該交給那個(gè)進(jìn)程來進(jìn)行處理的;查看端口可以使用nestat -apn莹规;
關(guān)于字節(jié)序
大端:big endian表示將高字節(jié)存儲(chǔ)在起始地址赔蒲;
小段:LE(Little Endian)表示將低字節(jié)存儲(chǔ)在起始地址;
可以使用函數(shù)ntol來進(jìn)行大小端的轉(zhuǎn)換良漱;