网络编程传输层——UDP通信
何為傳輸層?
????????在物理層、數據鏈路層、網絡層解決了主機和主機之間能夠發送接收數據,但是在計算機網絡中,主機的通信主體還是進程,而傳輸層則解決應用進程的通信,所謂傳輸層協議也是端對端協議。
傳輸層的協議主要有兩種:TCP協議和UDP協議
本章這次主要是針對的UDP協議,下一章才是針對TCP協議的具體理解。
????????在傳輸層需要了解到一個新的概念:端口號port(可以理解為你要從那個地方傳進去),設計了一個端口號來標識主機中的進行網絡通信的進程。
????????port:16bit整形(兩個字節)? ? ? ?
????????端口號只在本機上有作用,在不同主句中同一個程序執行,也可以用不同的端口號。
什么是UDP協議?
? ? ? ? UDP協議(用戶數據報協議)(非面向連接)
? ? ? ??1. 無連接,不需要提前把兩個程序關聯起來(想發給誰就發給誰)。
????????2. 面向報文的傳輸,應用程序要發送的數據,直接封裝在udp數據報中(直接放在udp協議內容 后),既不做拆分也不做合并,直接交給網絡層。
????????3. 不可靠,不保證數據一定能到達,盡最大努力交付。
?????????UDP協議就是在MAC幀的外面在加上一層傳輸協議,既加上UDP頭部,它的頭部由以下四部分組成。
源端口:自己主機的端口號
目標端口:要傳到那個主機的端口號
下面這張圖是一個傳輸模型
?
????????可以看出這是TCP/IP網絡模型,因為只有四層,從用戶層、傳輸層、網絡層、網絡接口層構成。
? ? ? ? 在操作系統當中,其實網絡協議是有寫好了的函數庫可以使用,只需要選擇對應的協議就行。
如何進行UDP協議進行通信?
1、首先我們需要了解udp怎樣進行通信的,下圖是udp通信流程
?清楚了流程,但肯定不懂得后面函數得意義吧,下面來進行函數的細講:
1、創建套接字(這里就是相當于創建一個包含網絡通信協議的套接字文件)
#include <sys/types.h> #include <sys/socket.h>int socket(int somain, int type, int protocol);參數1:選擇那種ip地址進行通信-----網絡層 AF_INET IPV4 參數2:選擇那種傳輸-----傳輸層 SOCK_STREAM TCP SOCK_DGRAM UDP SOCK_RAM 不使用 參數3:套接字協議 0 默認返回值 成功:返回套接字 失敗:返回-12、綁定套接字(也就是將自己的本地網絡信息綁定到網絡協議中)
#include <sys/types.h> /* See NOTES */ #include <sys/socket.h>int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen)參數1;利用函數int socket函數創建的套接字 參數2:自己的IPV4網絡信息struct sockaddr_in { sa_family_t sin_family; 地址族:AF_INET/*address family: AF_INET */ in_port_t sin_port;port端口號:當前進程的端口號 struct in_addr sin_addr;ip地址:本地網絡地址 /* internet address */ };struct in_addr { uint32_t s_addr;32位整數,ip地址 /* address in network byte order */ }; 參數3:結構體大小,直接sizeof(struct addr)3、這個函數就是發送數據與接收數據(發給誰,接收誰)
UDP發送數據ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);參數1:要通過套接字發送給誰 參數2:要發送數據的首地址 參數3:發送數據的大小 參數4:標志 0:阻塞等待,發送完成才結束 參數5:const struct sockaddr *dest_addr:結構體地址,要包含目標,接收方的地址、端口 參數6::結構體大小,目標網絡信息結構體的大小返回值 成功:返回發送的字節數 失敗:返回-1UDP接收數據ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);參數1:int sockfd:套接字,本地套接字攜帶了本地的網絡信息,進行匹配 參數2:void *buf:接收了數據存儲的地址 參數3:size_t len:最大接收多少個字節 參數4:int flags:標志 0:阻塞接收,函數一直等待接收了數據,完成接收才結束 參數5:struct sockaddr *src_addr:結構體地址,把發送方的ip、port存儲到這個結構 體,得到發送方的信息 如果不需要 填NULL 參數6:socklen_t *addrlen:把結構體大小也存儲到這個地址,得到發送方對應的信息大小 如果不需要 填NULL 返回值: 成功:返回接收到的字節數 失敗:返回-1????????在計算機存儲數據中,有大小端之分(大端(高存低地址,低存高地址)小端(高存高地址,低存低地址)),但是在網絡上傳輸時,統一成了大端模式。
? ? ? ? 在網絡上傳輸的方式是網絡字節序 ,而在機器上存儲的方式是主機字節序。
? ? ? ? 則我們需要在傳輸時將主機字節序轉網絡字節序 ,網絡字節序轉主機字節序。
實例:
? ? ? ? 發送端程序:
????????
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h>//當前進程發送數據到指定主機的指定進程中,然后接收對方的數據 int main() {//1、創建套接字------在進程中要使用網絡通信協議,得到套接字文件描述符int sockfd = socket(AF_INET,SOCK_DGRAM,0); //IPV4,UDP協議//2、綁定套接字,綁定套接字 中 協議中本地的網絡信息//把套接字,綁定本地網絡信息struct sockaddr_in srcaddr;//本地網絡信息---源信息srcaddr.sin_family = AF_INET;//ipv4 地址srcaddr.sin_port = htons(9999);//當前進程的端口號srcaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");//把主機地址轉為32位整數bind(sockfd,(struct sockaddr *)&srcaddr,sizeof(struct sockaddr_in));//3、發送數據//目標結構體struct sockaddr_in destaddr;//目標信息destaddr.sin_family = AF_INET;destaddr.sin_port = htons(8888);destaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");while(1){char buf[20],buf2[20];scanf("%s",buf);//輸入了數據sendto(sockfd,buf,20,0,(struct sockaddr *)&destaddr,sizeof(destaddr));發送recvfrom(sockfd,buf2,20,0,NULL,NULL);接收printf("%s\n",buf2);}close(sockfd); }????????接收數據程序、
#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <stdio.h> #include <unistd.h>//當前進程接收數據,然后發送給對方 int main() {//1、創建套接字------在進程中要使用網絡通信協議,得到套接字文件描述符int sockfd = socket(AF_INET,SOCK_DGRAM,0);//2、綁定套接字,綁定套接字 中 協議中本地的網絡信息//把套接字,綁定本地網絡信息struct sockaddr_in srcaddr;//本地網絡信息---源信息srcaddr.sin_family = AF_INET;//ipv4 地址srcaddr.sin_port = htons(8888);//當前進程的端口號srcaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");//把主機地址轉為32位整數bind(sockfd,(struct sockaddr *)&srcaddr,sizeof(struct sockaddr_in));//3、接收數據//目標結構體struct sockaddr_in destaddr;//目標信息destaddr.sin_family = AF_INET;destaddr.sin_port = htons(9999);destaddr.sin_addr.s_addr = inet_addr("xxx.xxx.xxx.xxx");char buf2[20];while(1){recvfrom(sockfd,buf2,20,0,NULL,NULL); //接收printf("%s\n",buf2);sendto(sockfd,buf2,20,0,(struct sockaddr *)&destaddr,sizeof(destaddr)); //發送獲取}close(sockfd); }? ? ? ? UDP協議采用的非面向連接(沒有連接),所以還是有很多問題的,無連接、不可靠、面向數據報的傳輸 。而且發送了也不知道發送到了沒,缺點之一。
總結
以上是生活随笔為你收集整理的网络编程传输层——UDP通信的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020幻影围棋 第三天围棋规则模块(一
- 下一篇: Django新增数据