一、目的
? ? ? ? 網絡編程的目的實際上也是進程通信的一種方式,不過它可以在不同的主機上進行通信;
二、需要解決的問題
? 1. 主機與主機之間物理層面必須互聯互通。
- 指的是參與通信的計算機(主機)需要通過物理設備建立連接(光纖、網線),確保數據能夠在物理介質上傳輸
- 具體包括:網卡正常工作、網線或無線信號等傳輸介質連接正常、路由器 / 交換機等網絡設備配置正確
? 2. 進程與進程在軟件層面必須互聯互通。
- 指的是在物理連接通暢的基礎上,不同主機上的應用程序進程需要通過網絡協議進行邏輯連接
- 具體包括:使用正確的 IP 地址和端口號、采用相同的網絡協議(如 TCP/UDP)、進程已正確綁定端口并處于監聽狀態
舉個例子:
這是一個傳輸機制圖解;每個有IP地址的方格代表一個主機;其中,交換機就是局域網內的主機通信的物理設備;但是如果要在廣域網與其他網段的主機進行通信的話,就需要“路由器+ 鏈路” 來負責跨網段轉發。簡單說,左邊局域網和右邊局域網,靠路由器之間的物理鏈路打通,數據就能從左傳到右、右傳到左。
至于進程,兩邊進程得用?相同的協議(比如 TCP/UDP)?說話。比如左邊進程用 TCP 發數據,右邊進程也得用 TCP 收,否則 “語言不通” 沒法交流。而每個進程要通信,得綁定?IP + 端口。比如左邊主機?192.168.0.140
?上的QQ給另一臺主機的QQ發消息,得告訴系統:“我在?192.168.0.140
?這臺機器,監聽?QQ
?端口,別人可以給我發數據”;右邊主機?192.168.1.140
?上的進程同理。如果端口不同,就有可能接收不到信息;
所以,在這里總結幾個概念:
- IP地址:計算機的軟件地址,用來標識計算機設備(由路由器動態分配)
- MAC地址:計算機的硬件地址(固定)
- 網絡的端口號:標記同一主機上的不同網絡進程
需要注意的是:
- 在同一個局域網下,不能有2個一模一樣的ip地址;
- 路由器在進行遠距離數據傳輸的時候,會對路徑進行選擇規劃,力求最短/最快路徑
圖解如下:
三、網絡協議
網絡協議即是不同體系結構設備間,網絡通信的標準
OSI七層模型
意味開放系統互聯模型(open system interconnect)
它是一個理論模型:
應用層 | 要傳輸的數據信息,如文件傳輸,電子郵件等 |
表示層 | 數據加密,解密操作,壓縮,解壓縮(安全性) |
會話層 | 建立數據傳輸通道,? (會話) |
傳輸層 | 傳輸的方式 ?UDP ?TCP ? 端口號 |
網絡層 | 實現數據路由,路徑規劃 ? ?路由器 ?ip |
數據鏈路層 | 封裝成幀(幀數據),點對點通信(局域網內通信),差錯檢測 ? 交換機 ?ARP |
物理層 | 定義物理設備標準、電氣特性,比如網線,光纖等傳輸介質(比特流 ?bit ?0 1) |
TCP/IP模型:應用模型
它是一個應用模型,一共分為5層:
應用層 | |
---|---|
?HTTP | 超文本傳輸協議 |
HTTPS | 超文本傳輸協議(SSL加密算法) |
FTP | 文件傳輸協議(TCP) |
TFTP | 簡單文件傳輸協議(UDP) |
MQTT | 消息隊列遙測傳輸(物聯網協議) |
DNS | 域名解析服務(www.baidu.com轉為IP地址) |
傳輸層 | |
---|---|
TCP | 傳輸控制協議 |
UDP | 用戶數據報協議 |
網絡層 | ||
---|---|---|
IP協議 | IPV4 | IPV6 |
數據鏈路層 | |
---|---|
ARP | 地址解析協議 |
? ? ? ? ? ? ? ? 物理層同上:
物理層 | 定義物理設備標準、電氣特性,比如網線,光纖等傳輸介質(比特流 ?bit ?0 1) |
在有一些定義中,也可能是四層:
- 應用層:同上
- 傳輸層:同上
- 網絡層:同上
- 網絡接口層:包含物理層與數據鏈路層
四、IP協議
網絡層
IPv4 | 32位 |
IPv6 | 128位 |
例:
192.168.1.140 ?? ??? ?(用戶表示形式) ? 點分十進制 ??
11000000 10101000 00000000 01000011?? ?(計算機存儲形式) 32bits
IP地址
IP地址 = 網絡位 + 主機位?
例:192.168.0.121/24
24:網絡位的位數
網絡位 | 該IP地址位于哪個網段(局域網)內 |
主機位 | 這個網段(局域網)第幾臺主機 |
子網掩碼 | 用來區分IP地址的網絡位和主機位,搭配IP地址使用。 |
舉個例子:
255.255.255.0
11111111.11111111.11111111.00000000
子網掩碼是1的部分對應IP地址的網絡位
子網掩碼是0的部分對應IP地址的主機位
特殊的IP地址
網段號: | IP地址網絡位不變,主機位全為0,則為該IP地址的網段號 |
---|---|
廣播號: | IP地址網絡位不變,主機位全為1,則為該IP地址的廣播號 |
網關地址: | 192.168.1.1(局域網與廣域網的網關) |
舉個例子:
IP地址:192.168.1.3
子網掩碼:255.255.255.0
網段號:192.168.1.0(網段內的IP能直接通信)
IP地址:192.168.1.3
子網掩碼:255.255.255.0
網段號:192.168.1.255(向廣播號發送信息,所有局域網內IP都能收到此信息)
IP地址的劃分
在此之前,我們先來區分兩個概念:
為了節省ip地址,把ip分為兩種:
公有IP:由電信公司直接分配,并需要付費的IP地址, 可以直接訪問internet
私有IP:不能直接訪問internet的ip地址,由路由器分配,進入廣域網時自動轉為公有IP
(1)A類地址:
用于管理大規模網絡
范圍 | 1.0.0.0 - 126.255.255.255 |
子網掩碼 | 255.0.0.0 |
可以分配的IP地址數 | 126*2^24 |
私有IP地址 | 10.0.0.0 - 10.255.255.255 |
(2)B類地址:
管理大中規模網絡
范圍 | 128.0.0.0 - 191.255.255.255 |
子網掩碼 | 255.255.0.0 |
可以分配的IP地址數 | 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 |
可以分配的IP地址數 | 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 |
五、 網絡端口號
? ? 端口號:為16位的整形數據(unsigned short)(范圍是:0-65535)
端口號功能:標記同一主機上的不同網絡進程
分類
1)任何TCP/IP實現所提供的服務都用1-1023之間的端口號。
http? | ?80 |
---|---|
FTP | ?20/21 |
TFPT | 69 |
HTTPS | 443 |
2)端口號從1024-49151是被注冊的端口號,被IANA指定為特殊服務使用。
MQTT:1883/8883
3)從49152-65535是動態或私有端口號。
六、網絡配置
1. ?ping ?ip地址/域名
????????????????查看當前主機和IP/域名所對應的這臺主機網絡是否聯通
2. ifconfig?
????????????????在Linux查看當前主機的IP地址
????????ipconfig
????????????????在Windows上查看當前主機的IP地址
?3. 網絡配置
?1)虛擬機--》設置--》網絡適配器---》橋接模式
?2)編輯--》虛擬網絡編輯器--》更改設置--》VMnet0---》橋接至--》當前PC正在上網的網卡上--》應用--》確定
3)修改網絡配置文件
?????????????????在終端輸入命令:sudo vim /etc/network/interfaces
auto lo
iface lo inet loopbackauto ens33
iface ens33 inet dhcp
?4)重啟網絡服務
????????????????sudo /etc/init.d/networking restart
?5) 測試
????????????????ping www.baidu.com
七、網絡協議——UDP
UDP:(傳輸層)用戶數據報協議(User Datagram Protocol)
? 1)網絡編程模型
B/S模型:browser/server(瀏覽器/服務器) |
---|
?1. 客戶端是通用的客戶端(瀏覽器) |
2. 一般只做服務器開發 |
?3. 客戶端要加載的數據均來自服務器 |
? ?C/S模型:client/server(客戶端/服務端) |
---|
?1. 客戶端是一個專用的客戶端 |
2. 服務器和客戶端都需開發 |
3. 客戶端可保存資源,本地加載,無需所有數據都請求服務器 |
?2)UDP編程流程
我們先來厘清一個概念:
套接字:文件描述符;網絡通信時,應用層可操作的端口。
socket函數:
? ? ? ?#include <sys/types.h> ? ? ? ? ?/* See NOTES */
#include <sys/socket.h>? ? ? ?int socket(int domain, int type, int protocol);
功能:創建通信的套接字
參數:
domain:網絡層使用什么協議族
AF_INET:IPv4
AF_INET6:IPv6
type:規定傳輸層的協議
SOCK_DGRAM : UDP協議
SOCK_STREAM:TCP協議
SOCK_RAW :原始套接字
protocol :0 按照默認協議方式創建
返回值:
成功:套接字
失敗:-1
sendto函數
? ? ? ?ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
功能:向網絡套接字發送數據
參數:
sockfd:套接字
buf: 要發送的數據的首地址
len:要發送的字節數
flags: 0:按照默認方式發送
dest_addr:接收方的地址信息(IP+端口號)
addrlen:接收方地址的大小
返回值:
成功:實際發送的字節數
失敗:-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 */};/* Internet address. */
struct in_addr {uint32_t ? ? ? s_addr; ? ? /* address in network byte order */};
其中:
port in network byte order代表基于網絡字節序的端口號;
網絡字節序:大端? ?(network)
主機字節序:小端? ?(host)
為了切換這兩者,我們可以使用函數:
uint32_t htonl(uint32_t hostlong); ? ? ? ? ?主機轉網絡
uint16_t htons(uint16_t hostshort); ? ? ? ? 主機轉網絡
uint32_t ntohl(uint32_t netlong); ? ? ? ? ? 網絡轉主機
uint16_t ntohs(uint16_t netshort); ? ? ? ? ?網絡轉主機
我們通常傳遞的ip地址為一個字符串,為了使其切換成二進制IP地址的形式,也要再調用一次函數:
in_addr_t inet_addr(const char *cp);
功能:
將字符串IP地址轉換成二進制IP地址形式?char *inet_ntoa(struct in_addr in);
功能:
將二進制ip轉換成字符串
bind函數:
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
功能:綁定自己的IP地址和端口號
參數:
sockfd:套接字
addr:需要綁定的地址
addrlen:地址大小
返回值:
成功:0
失敗:-1
recvfrom函數:
功能:從套接字上接收數據
參數:
sockfd:套接字
buf:存放接收數據的內存首地址
len:希望接收的字節數
flags:0 :按照默認方式接收(阻塞)
src_addr:發送方的地址信息
addrlen:發送發地址的指針
功能:
成功:實際接收到的字節數
失敗:-1
客戶端編程:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/types.h> /* See NOTES */
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, const char *argv[])
{//socket()//sendto()//recvfrom()//close()int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket error");return -1;}//定義的接收方(服務端)的地址變量struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000); //接收方的端口號seraddr.sin_addr.s_addr = inet_addr("192.168.0.179"); //接收方所在主機的IP地址char buff[1024] = {0};while (1){fgets(buff, sizeof(buff), stdin);ssize_t cnt = sendto(sockfd, buff, 0, 0, (struct sockaddr *)&seraddr, sizeof(seraddr));if (cnt < 0){perror("sendto error");return -1;}// printf("cnt = %ld\n", cnt);memset(buff, 0, sizeof(buff));recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);printf("ser-->cli : %s\n", buff);}//close(sockfd);return 0;
}
服務端編程:
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h> /* superset of previous */
#include <sys/types.h> /* See NOTES */
#include <arpa/inet.h>
#include <unistd.h>int main(int argc, const char *argv[])
{//socket()//bind()//recvfrom()//sendto()//close()int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket error");return -1;}struct sockaddr_in cliaddr;socklen_t clilen = sizeof(cliaddr);//服務端自己的地址信息變量struct sockaddr_in seraddr;seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50000);seraddr.sin_addr.s_addr = inet_addr("192.168.0.179");int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if (ret < 0){perror("bind error");return -1;}char buff[1024] = {0};while (1){memset(buff, 0, sizeof(buff));ssize_t cnt = recvfrom(sockfd, buff, sizeof(buff), 0, (struct sockaddr *)&cliaddr, &clilen);if (cnt < 0){perror("recvfrom error");return -1;}else if (0 == cnt){printf("cnt = %ld\n", cnt);break;}printf("[%s : %d][%ld] %s\n", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port),cnt, buff);fgets(buff, sizeof(buff), stdin);//strcat(buff, "--->ok");sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&cliaddr, clilen);}close(sockfd);return 0;
}
以上就是今天和大家分享的內容!!!!感謝你的閱讀!!!!!