一、網絡
1.定義
不同主機間進程通信
主機間在硬件層面互聯互通
主機在軟件層面互聯互通
2.國際網絡體系結構
? ? OSI模型(7層):?open?system?interconnect -------理論模型------定義了網絡通信中不同層的協議
1977???國際標準化組織
各種不同體系結構的計算機能在世界范圍內互聯成網。
應用層:要傳輸的數據信息,如文件傳輸,電子郵件等
表示層:數據加密,解密操作,壓縮,解壓縮
會話層:建立數據傳輸通道
傳輸層:傳輸的方式??UDP??TCP???端口號
網絡層:實現數據路由????路由器??ip
數據鏈路層:封裝成幀,點對點通信(局域網內通信),差錯檢測???交換機??ARP
物理層:定義物理設備標準,比如網線,光纖等傳輸介質???比特流??bit??0?1
協議簇
TCP/IP模型:??工業模型(4層)
應用層:HTTP、HTTPS、FTP、TFTP、MQTT
傳輸層:TCP、UDP
網絡層:IP
網絡接口層:網絡接口層既是傳輸數據的物理媒介,也可以為網絡層提供一條準確無誤的線路
5層
應用層:HTTP、HTTPS、FTP、TFTP、MQTT
傳輸層:TCP、UDP
網絡層:IP
數據鏈路層:封裝成幀,點對點通信(局域網內通信),差錯檢測???交換機
物理層:定義物理設備標準,比如網線,光纖等傳輸介質???比特流??bit
?3.協議
應用層協議:
FTP:文件傳輸協議(實現文件上傳/下載)
TFTP:簡單文件傳輸協議(實現文件上傳/下載)
HTTP:超文本傳輸協議(實現超文本(集視頻、圖片、文字于一體的文件類型)傳輸)
HTTPS:加密版超文本傳輸協議
MQTT:消息隊列遙測傳輸協議(物聯網傳輸)----減少帶寬
DNS域名解析協議
傳輸層協議:
UDP:用戶數據報協議
TCP:傳輸控制協議
網絡層:IP協議
IPv4????32位? ? ?IPv6????128位
4.IP地址
IP地址?=?網絡位?+?主機位 ----區分不同主機,軟件地址
網絡位:該IP地址位于哪個網段(局域網)內
主機位:這個網段(局域網)第幾臺主機
子網掩碼:
如:255.255.255.0 (點分十進制 )??
11111111.11111111.11111111.00000000??(計算機存儲形式)?32bits
用來區分IP地址的網絡位和主機位,搭配IP地址使用。
子網掩碼是1的部分對應IP地址的網絡位
子網掩碼是0的部分對應IP地址的主機位
eg:192.168.0.121/24? ?24:網絡位的位數
網段號:?IP地址網絡位不變,主機位全為0,則為該IP地址的網段號? ?網段內的IP能直接通信? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 192.168.1.0
廣播號:IP地址網絡位不變,主機位全為1,則為該IP地址的廣播號? ? 向廣播號發送信息,所有局域網內? ? ? ? ? ? ? IP都能收到此信息? ? 192.168.1.255
網關地址:192.168.1.1
5.IP地址的劃分
(1)A類地址:
范圍:1.0.0.0?-?126.255.255.255
子網掩碼:255.0.0.0??????????126*2^24????????
用于管理大規模網絡
私有IP地址:10.0.0.0?-?10.255.255.255
127.0.0.0???回環地址
(2)B類地址:
范圍:128.0.0.0?-?191.255.255.255
子網掩碼:255.255.0.0?????????2^16
管理大中規模網絡
私有IP地址:172.16.0.0?-?172.31.255.255
(3)C類地址:
范圍:192.0.0.0?-?223.255.255.255
子網掩碼:255.255.255.0????????2^8
管理中小規模網絡
私有IP地址:192.168.0.0?-?192.168.255.255
(4)D類地址:
224.0.0.0?-?239.255.255.255
組播和廣播使用
(5)E類地址:
240.0.0.0?-?255.255.255.254
用來進行實驗
公有IP:由電信公司直接分配,并需要付費的IP地址,?可以直接訪問internet
私有IP:不能直接訪問internet的ip地址
6.端口號
范圍:16位的數值? 0-65535 2字節
作用:唯一的標識一個進程。每一個應用進程都有一個端口號;通訊時用來區分數據包屬于哪一個進程。區分同一主機上的不同網絡進程.
分類:
1)任何TCP/IP實現所提供的服務都用1-1023之間的端口號。
http?:?80? ? FTP:?20/21? ? ?TFPT:?69? ? ?HTTPS:?443? ?MQTT: 833
2)端口號從1024-49151是被注冊的端口號,被IANA指定為特殊服務使用。
3)從49152-65535是動態或私有端口號。
IP+PORT?:?可以找到目標主機上的目標進程
7.TCP/IP封包,拆包過程
二、網絡配置
1.ping命令
? 檢查兩個主機之間是否網絡聯通
ping +IP地址/域名
ping www.baidu.com ----->dns(域名解析服務)
2.永久配置IP地址
(1)將虛擬機設置為橋接模式
? ?虛擬機 --》設置---》網絡適配器---》橋接模式---》確定
(2)將虛擬機的IP地址橋接到無線網卡上
? 編輯 --》虛擬網絡編輯器---》更改設置---》橋接到能上網的網卡上去---》應用---》確定
(3)設置虛擬機的IP地址
?1) 打開虛擬機網卡配置文件:sudo?vim?/etc/network/interfaces
? 2)將文件內容修改為如下:自動獲取IP地址配置如下:(推薦)
auto?lo
iface?lo?inet?loopback?
auto?ens33
iface?ens33?inet?dhcp
? 3)重啟網絡服務?sudo?/etc/init.d/networking?restart
?3.ifconfig命令
?查看當前操作系統中網卡信息??
ens33:虛擬機中的網卡
lo:回環地址(127.0.0.1)
inet:IPv4地址
netmask:子網掩碼
broadcast:廣播號
inet6:IPv6地址
ether:MAC地址?
三、網絡編程之?UDP
UDP(User?Datagram?Protocol):用戶數據報協議---傳輸層
1.特性
(1).發送數據時不需要建立鏈接,節省資源開銷
(2).不安全不可靠的協議 (盡最大交付的協議,可能存在丟包,亂序)//一般用在實時性比較高的廣播,組播//vnc
(3).面向報文。
(4).資源開銷小,效率高.
應用:允許數據丟失,要求實時性高的場景
2.網絡編程模型
B/S :browser/server-->瀏覽器/服務器?
? ? ? ? (1)通用的客戶端 (2)客戶端無需開發 (3)請求的資源均來自于服務端
C/S?:client/server--->客戶端/服務器?
? ? ? ?(1)專用的客戶端 (2)客戶端和服務端都需開發 (3) 客戶端可以存儲部分資源
3.編程
網絡套接字:文件描述符? 為網絡通信抽象出的一個通信端口
(1).socket?
? 套接字:通信對象的抽象,?網絡通信的端口,一個通信鏈的句柄。
int?socket(int?domain,?int?type,?int?protocol);
功能:創建一個用來通信的接口(文件描述符)
參數:domain:通信的協議族(AF_INET:IPv4協議族?AF_INET6:IPv6)
type:SOCK_DGRAM:數據報套接字 (UDP使用此類型)
SOCK_STEAM:流式套接字 (TCP使用此類型)
SOCK_RAW:原始套接字
protocol:默認傳0?按照協議的默認屬性創建
返回值:成功返回用來進行通信的文件描述符;失敗返回-1?
(2).sendto?
?ssize_t?sendto(int?sockfd,?const?void?*buf,?size_t?len,?int?flags,
const?struct?sockaddr?*dest_addr,?socklen_t?addrlen);
功能:向一個IP地址和端口發送數據信息
端口號:區分一臺主機不同的應用程序(0?-?65535)
參數:sockfd:套接字文件描述符
buf:發送數據空間首地址
len:發送數據的長度
flags:發送數據屬性(默認為0)
dest_addr:目的IP地址和端口
addrlen:目的IP地址和端口的長度
返回值:成功返回實際發送字節數;失敗返回-1?
?man 7 ip??
struct?sockaddr_in?{
sa_family_t????sin_family;?/*?address?family:?AF_INET?*/
in_port_t??????sin_port;???/*?port?in?network?byte?order?*/
struct?in_addr?sin_addr;???/*?internet?address?*/
};
struct?in_addr?{
uint32_t???????s_addr;?????/*?address?in?network?byte?order?*/
};
網絡字節序:大端? ? 主機字節序:小端??
?(3).htons----》主機轉網絡字節序
? 主機:小端???host? ? 網絡:大端???network
uint32_t?htonl(uint32_t?hostlong);??????????主機轉網絡
uint16_t?htons(uint16_t?hostshort);????????主機轉網絡
uint32_t?ntohl(uint32_t?netlong);? ? ? ? ? ? 網絡轉主機
uint16_t?ntohs(uint16_t?netshort);??????????網絡轉主機
h:host??? ?n:net? ? ?l:long? ? ?s:short?
(4).inet_addr
?in_addr_t? inet_addr(const?char?*cp);
功能:將字符串IP地址轉換成二進制IP地址形式
char?*inet_ntoa(struct?in_addr?in);
功能:將二進制ip轉換成字符串
(5).recvfrom
? ssize_t?recvfrom(int?sockfd,?void?*buf,?size_t?len,?int?flags,
struct?sockaddr?*src_addr,?socklen_t?*addrlen);
功能:接收網絡發送的數據信息
參數:sockfd:套接字文件描述符
buf:存放數據空間首地址
len:最大能夠接收的字節數
flags:屬性默認為0(阻塞方式)
src_addr:存放發送端IP地址信息的空間首地址
addrlen:想要接收的數據長度的空間首地址
返回值:成功返回實際接收字節數;失敗返回-1?
具有阻塞功能(直到接收到數據,才會繼續向下執行
(6).bind
? int?bind(int?sockfd,?const?struct?sockaddr?*addr,socklen_t?addrlen);
功能:將一個套接字與IP地址和端口號綁定(只能綁定自己的IP地址)
參數:sockfd:套接字文件描述符?
addr:保存自己IP地址和端口號結構體首地址
addrlen:地址的長度
返回值:成功返回0;失敗返回-1?
4.UDP?報文頭
UDP首部有8個字節,由4個字段構成,每個字段都是兩個字節:
+----------------------------------------------------------+
|?16位源端口 (2字節)? |??16位目的端口(2字節)? |
|-------------------------------------------------------------|
|?16位數據長度(2字節)?|??16位校驗和?(2字節)???|
|-------------------------------------------------------------|
|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?數據? ? ? ? ? ? ? ? ?? ? ? ? ? ? ??? |
+--------------------------------------------- --------------+
(1).源端口:?源主機的應用程序使用的端口號。
(2).目的端口:目的主機的應用程序使用的端口號。
(3).長度:是指UDP頭部和UDP數據的字節長度。因為UDP頭?部長度為8字節,所以該字段的最小值為8。
(4).校驗和:檢測UDP數據報在傳輸中是否有錯,有錯則丟棄。
四、wireshark抓包工具的使用
1.?在線安裝wireshark抓包工具
sudo?apt-get?install?wireshark
sudo?wireshark????//啟動wireshark
2.?wireshark作用
可以抓取通過網卡的數據包? 用于軟件代碼出錯調試和錯誤分子
3.使用方法
(1).?sudo?wireshark
(2).?選擇網卡??雙擊any網卡
(3).?選擇過濾條件? tcp.port?==?80?||?udp.port?==?80
(4).?進行一次網絡通信
五、練習
1.使用UDP實現局域網內兩個人的全雙工聊天
//ser.c
#include "head.h"int init_udp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("fail bind");return -1;}return sockfd;
}int main(int argc, const char *argv[])
{int sockfd = init_udp_ser("192.168.1.162", 50000);if (sockfd < 0){return -1;}char buff[1024] = {0};struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&cliaddr, &clilen);pid_t pid = fork();if (pid > 0){while (1){memset(buff, 0, sizeof(buff));ssize_t size = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);if (size < 0){perror("fail recvfrom");close(sockfd);return -1;}printf("A-->B : %s\n", buff);}close(sockfd);}else if (0 == pid){while (1){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin);sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&cliaddr, clilen);}close(sockfd);}else{perror("fail fork");return -1;}return 0;
}
//cli.c
#include "head.h"struct sockaddr_in seraddr;int init_udp_cli()
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("fail socket");return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.1.162");return sockfd;
}int main(int argc, const char *argv[])
{int sockfd = init_udp_cli();if (sockfd < 0){return -1;}sendto(sockfd, "hello", 5, 0, (struct sockaddr *)&seraddr, sizeof(seraddr));pid_t pid = fork();if (pid > 0){char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));fgets(buff, sizeof(buff), stdin);ssize_t size = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&seraddr, sizeof(seraddr));if (size < 0){perror("fail sendto");close(sockfd);return -1;}}close(sockfd);}else if (0 == pid){char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));ssize_t size = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);if (size < 0){perror("fail recvfrom");close(sockfd);return -1;}printf("B-->A: %s\n", buff);}close(sockfd);}else{perror("fail fork");return -1;}return 0;
}
#ifndef __HEAD_H__
#define __HEAD_H__#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>#endif
2. 使用UDP實現一個文件的傳輸
//ser.c
#include "head.h"int init_udp_ser(const char *ip, unsigned short port)
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("fail socket");return -1;}struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(port);seraddr.sin_addr.s_addr = inet_addr(ip);int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("fail bind");return -1;}return sockfd;
}int recv_file(int sockfd, const char *filename)
{int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664);if (fd < 0){perror("fail open file");return -1;}char buff[1024] = {0};off_t len;recvfrom(sockfd, &len, sizeof(len), 0, NULL, NULL);printf("len = %ld\n", len);while (1){ssize_t size = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);len -= size;write(fd, buff, size);printf("len = %ld\n", len);if (len <= 0){break;}}close(fd);
}int main(int argc, const char *argv[])
{int sockfd = init_udp_ser("192.168.1.162", 50000);if (sockfd < 0){return -1;}recv_file(sockfd, "2.jpg");close(sockfd);return 0;
}
#include "head.h"struct sockaddr_in seraddr;int init_udp_cli()
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("fail socket");return -1;}seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.1.162");return sockfd;
}int send_file(int sockfd, const char *filename)
{int fd = open(filename, O_RDONLY);if (fd < 0){perror("fail open file");return -1;}char buff[1024] = {0};off_t len = lseek(fd, 0, SEEK_END);lseek(fd, 0, SEEK_SET);sendto(sockfd, &len, sizeof(len), 0, (struct sockaddr *)&seraddr, sizeof(seraddr));printf("len = %ld\n", len);while (1){ssize_t size = read(fd, buff, sizeof(buff));if (size <= 0){break;}size = sendto(sockfd, buff, size, 0, (struct sockaddr *)&seraddr, sizeof(seraddr));if (size < 0){perror("fail sendto");close(fd);return -1;}usleep(1);}close(fd);return 0;
}int main(int argc, const char *argv[])
{int sockfd = init_udp_cli();if (sockfd < 0){return -1;}send_file(sockfd, "1.jpg");close(sockfd);return 0;
}