Linux下的網絡編程
1. 目的
實現不同主機之間進程的通信。
2. 問題
- 主機之間在物理層面必須互聯互通。
- 進程之間在軟件層面必須互聯互通。
- IP地址:計算機的軟件地址,用于標識計算機設備。
- MAC地址:計算機的硬件地址(固定)。
- 網絡的端口號:標記同一主機上的不同網絡進程。
3. 網絡協議
網絡通信標準。
- OSI七層模型(理論模型):開放系統互連模型,是不同體系結構設備間網絡通信的通信標準。
- 應用層:要傳輸的數據,如文件傳輸、電子郵件。
- 表示層:數據加密解密操作、壓縮解壓縮操作。
- 會話層:建立數據傳輸通道。
- 傳輸層:傳輸的方式,如UDP、TCP、端口號。
- 網絡層:實現數據路由,如路由器、IP。
- 數據鏈路層:封裝成幀、點對點通信(局域網內通信)、差錯檢測,如交換機。
- 物理層:定義物理設備標準、電氣特性,如網線、光纖等傳輸介質,比特流(bit 0/1)。
- TCP/IP模型(應用模型):
- 五層:
- 應用層:
- HTTP:超文本(數據類型較多)傳輸協議。
- HTTPS:超文本傳輸協議(SSL加密算法)。
- FTP:文件傳輸協議(TCP傳輸)。
- TFTP:簡單文件傳輸協議(UDP傳輸)。
- MQTT:消息隊列遙測傳輸協議(廣泛應用于物聯網協議傳輸)。
- DNS:域名解析服務(將一個域名轉換為IP地址)。
- 傳輸層:
- TCP:傳輸控制協議(構建路徑)。
- UDP:用戶數據報協議(傳輸時不構建路徑,找效率高的,可能導致亂序;不安全,可能會導致丟包)。
- 網絡層:
- IP協議:
- IPv4。
- IPv6。
- IP協議:
- 數據鏈路層:
- ARP:地址解析協議(IP地址和MAC地址之間的轉換)。
- 物理層。
- 應用層:
- 四層:
- 應用層。
- 傳輸層。
- 網絡層。
- 網絡接口層。
- 五層:
4. IP協議
網絡層協議。
- IPv4:32位(用ipconfig在Windows終端上查看)。
- IPv6:128位。
- IP地址 = 網絡位 + 主機位,和子網掩碼搭配使用,子網掩碼全為1的是網絡位,全為0的是主機位。
- 示例:192.168.0.121/24(24表示網絡位的位數)。
- 網絡位:標識該IP地址所在的網段(局域網)。
- 主機位:標識該網段中的具體主機。
- 網段號:如192.168.1.0(網絡位保留,主機位為0)。
- 廣播號:如192.168.1.255(網絡位不變,主機位全為1)。
- 網關地址:如192.168.1.1(網絡位保留,主機位為1)。
- IP地址劃分:
- A類地址:
- 范圍:1.0.0.0 - 126.255.255.255。
- 子網掩碼:255.0.0.0。
- 主機數量:2^24(大規模網絡)。
- 私有IP地址:10.0.0.0 - 10.255.255.255。
- 回環地址:127.0.0.0。
- B類地址:
- 范圍:128.0.0.0 - 191.255.255.255。
- 子網掩碼:255.255.0.0。
- 主機數量:2^16(管理大中規模網絡)。
- 私有IP地址:172.16.0.0 - 172.31.255.255。
- C類地址:
- 范圍:192.0.0.0 - 223.255.255.255。
- 子網掩碼:255.255.255.0。
- 主機數量:2^8(管理中小規模網絡)。
- 私有IP地址:192.168.0.0 - 192.168.255.255。
- D類地址:
- 范圍:224.0.0.0 - 239.255.255.255(組播和廣播使用)。
- E類地址:
- 范圍:240.0.0.0 - 255.255.255.254(用于實驗)。
- A類地址:
- 共用IP:由電信公司直接分配,需要付費的IP地址,可以直接訪問Internet。
- 私有IP:不能直接訪問Internet的IP地址,由路由器轉為共用IP。
- 這樣可以節省IP地址。
5. 網絡端口號
端口號:16位的整型數據(unsigned short),范圍0 - 65535。
端口號功能:標記同一主機上的不同網絡進程。
分類:
- 任何TCP/IP實現所提供的服務都用1 - 1023之間的端口號。
- HTTP:80。
- FTP:20/21。
- TFTP:69。
- HTTPS:443。
- MQTT:1883/8883。
- 端口號從1024 - 49151是被注冊的端口號,被IANA指定為特殊(如MQTT:1883/8883)。
- 從49152 - 65535是動態或私有端口號。
- 數據包封裝與解封過程
6. 網絡配置
ping ip地址/域名
:查看當前主機和IP/域名所對應的網絡是否聯通,例如ping www.baidu.com
。ifconfig
:- Linux上查看IP地址。
- Windows上使用
ipconfig
。
- 網絡配置步驟:
- 虛擬機->設置->網絡適配器->橋接模式。
- 編輯->虛擬網絡編輯器->更改設置->VMnet0->橋接至->當前上網的網卡->應用。
- 修改網絡配置文件:
sudo vim /etc/network/interfaces
auto lo iface lo inet loopback auto ens33 iface ens33 inet dhcp
- 重啟網絡服務:
sudo /etc/init.d/networking restart
- 測試:
ping www.baidu.com
7. 網絡層-UDP
在傳輸層(用戶數據報協議User Datagram Protocol)。
- 網絡編程模型:
- B/S模型:browser(瀏覽器)/server(服務器)。
- 客戶端是一個通用的客戶端(瀏覽器)。
- 一般只做服務器開發。
- 客戶端要加載的數據均來自服務器。
- C/S模型:client(客戶端)/server(服務端)。
- 客戶端是一個專用的客戶端。
- 服務器和客戶端都需開發。
- 客戶端保存資源,本地加載,無需所有數據都請求服務器。
- B/S模型:browser(瀏覽器)/server(服務器)。
- 編程:
- 客戶端:
socket()
:創建通信的套接字(文件描述符,網絡通信時應用層可操作的端口)。sendto()
:發送數據。recvfrom()
:接受數據。close()
:關閉套接字。
- 服務端:
socket()
:創建通信的套接字。bind()
:綁定服務器的IP和端口。sendto()
:發送數據。recvfrom()
:接受數據。close()
:關閉套接字。
- 客戶端:
- 相關函數:
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
:接收方地址的大小。
- 返回值:成功返回實際發送的字節數。
? ? ? ? 3.
uint32_t htonl(uint32_t hostlong); 主機轉網絡
uint16_t htons(uint16_t hostshort); 主機轉網絡
uint32_t ntohl(uint32_t netlong); 網絡轉主機
uint16_t ntohs(uint16_t netshort); 網絡轉主機
? ? ? ? 4.
in_addr_t inet_addr(const char *cp);
功能:將字符串IP地址轉換成二進制IP地址形式char *inet_ntoa(struct in_addr in);
功能:將二進制ip轉換成字符串
? ? ? ? 5.
網絡字節序:大端 network
主機字節序:小端 50000 host
????????8.代碼
? ? ? ? ? ? ? ? UDP相關編程
客戶端
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>int main(int argc, char const *argv[])
{int sockfd = socket(AF_INET, SOCK_DGRAM, 0);//man 7 ip/創建套接字(網絡類型;UDP;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地址// while(1)// {// ssize_t cnt = sendto(sockfd, "1111", 13, 0, (struct sockaddr *)&seraddr, sizeof(seraddr));//發送// }char buff[1024] = {0};while(1){fgets(buff,sizeof(buff),stdin);ssize_t cnt = sendto(sockfd, buff, strlen(buff), 0, (struct sockaddr *)&seraddr, sizeof(seraddr));//發送if(cnt < 0){perror("sendto error");return -1;}printf("cnt = %ld\n", cnt);}close(sockfd);//關閉return 0;
}
服務端
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <unistd.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>int main(int argc, char const *argv[])
{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.192");int ret = bind(sockfd, (struct sockaddr *)&seraddr, sizeof(seraddr));if(ret < 0){perror("bind error");return -1;}char buff[1024] = {0};while(1){ssize_t cnt = recvfrom(sockfd, buff, sizeof(buff), 0, NULL, NULL);if(cnt < 0){perror("recvfrom error");return -1;}printf("cnt = %ld, buff = %s\n", cnt, buff);memset(buff, 0, sizeof(buff));}close(sockfd);return 0;
}