UDP網(wǎng)絡編程
1.UDP協(xié)議簡介
UDP協(xié)議采用無連接的方式,不管發(fā)送的數(shù)據(jù)包是否到達目的主機,數(shù)據(jù)包是否出錯。收到數(shù)據(jù)包的主機也不會告訴發(fā)送方是否正確收到了數(shù)據(jù),它的可靠性是由上層協(xié)議來保障的。
UDP 是User Datagram Protocol的簡稱, 中文名是用戶數(shù)據(jù)報協(xié)議,是OSI(Open System Interconnection,開放式系統(tǒng)互聯(lián)) 參考模型中一種無連接的傳輸層協(xié)議,提供面向事務的簡單不可靠信息傳送服務,IETF RFC 768 [1] 是UDP的正式規(guī)范。UDP在IP報文的協(xié)議號是17。
UDP是無連接的服務。在無連接服務的情況下,兩個實體之間的通信不需先建立好一個連接,因此其下層的有關資源不需要事先進行預定保留。這些資源將在數(shù)據(jù)傳輸時動態(tài)地進行分配。無連接服務的另一特征就是它不需要通信的兩個實體同時是活躍的(即處于激活態(tài))。當發(fā)送端的實體正在進行發(fā)送時,它才必須是活躍的。優(yōu)點是靈活方便和比較迅速,但不能防止報文的丟失、重復或失序,特別適合于傳送少量零星的報文。
UDP報文沒有可靠性保證、順序保證和流量控制字段等,可靠性較差。但是正因為UDP協(xié)議的控制選項較少,在數(shù)據(jù)傳輸過程中延遲小、數(shù)據(jù)傳輸效率高,適合對可靠性要求不高的應用程序,或者可以保障可靠性的應用程序,如DNS、TFTP、SNMP等。
? UDP和TCP協(xié)議的主要區(qū)別是兩者在如何實現(xiàn)信息的可靠傳遞方面不同。TCP協(xié)議中包含了專門的傳遞保證機制,當數(shù)據(jù)接收方收到發(fā)送方傳來的信息時,會自動向發(fā)送方發(fā)出確認消息;發(fā)送方只有在接收到該確認消息之后才繼續(xù)傳送其它信息,否則將一直等待直到收到確認信息為止。與TCP不同,UDP協(xié)議并不提供數(shù)據(jù)傳送的保證機制。如果在從發(fā)送方到接收方的傳遞過程中出現(xiàn)數(shù)據(jù)包的丟失,協(xié)議本身并不能做出任何檢測或提示。因此,通常人們把UDP協(xié)議稱為不可靠的傳輸協(xié)議。
2.UDP通訊流程
一般在UDP通訊中我們不太區(qū)分服務端和客戶端,由于UDP通訊不需要建立連接,因此UDP通訊中主要稱為發(fā)送方和接收方。
- 發(fā)送方創(chuàng)建過程:
1.創(chuàng)建網(wǎng)絡套接字socket
2.發(fā)送數(shù)據(jù)sendto
- 接收方創(chuàng)建過程:
1.創(chuàng)建網(wǎng)絡套接字socket
2.綁定端口號
3.接收數(shù)據(jù)recvfrom
2.1 函數(shù)接口
#include
#include
發(fā)送數(shù)據(jù)
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
形參: sockfd --套接字,socket函數(shù)返回值
???buf – 要發(fā)送是內(nèi)容
???len --要發(fā)送的數(shù)據(jù)長度
???flags --一般填0即可
???dest_addr、addrlen —和connect后兩個參數(shù)類似
???dest_addr —對方網(wǎng)絡結構體信息
??? addrlen --dest_addr結構體大小
返回值: 成功返回發(fā)送字節(jié)數(shù),失敗返回-1
接收數(shù)據(jù)
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
形參: sockfd --套接字,socket函數(shù)返回值
??? buf – 讀取內(nèi)容存放地址
??? len --要讀取的數(shù)據(jù)長度
??? flags --一般填0即可
??? src_addr、addrlen —和accept后兩個參數(shù)類似
??? src_addr —保存發(fā)送者的IP和端口號
??? addrlen —src_addr結構體大小
返回值: 成功返回讀取到的字節(jié)數(shù),失敗返回-1;
- 發(fā)送方示例
#include /* See NOTES */
#include
#include
#include
#include /* superset of previous */
#include
#include
#include
int main(int argc,char *argv[])
{
if(argc!=3)
{
printf("格式:./a.out <端口號> \n");
return 0;
}
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)
{
printf("創(chuàng)建網(wǎng)絡套接字失敗\n");
return 0;
}
struct sockaddr_in s_addr=
{
.sin_family=AF_INET,
.sin_port=htons(atoi(argv[1])),
.sin_addr.s_addr=inet_addr(argv[2]),//本地所有IP
};
char buff[]="UDP發(fā)送數(shù)據(jù)測試!";
ssize_t size;
while(1)
{
size=sendto(sockfd,buff,sizeof(buff),0,( const struct sockaddr * )&s_addr,sizeof(s_addr));
printf("發(fā)送數(shù)據(jù)成功size=%ld\n",size);
sleep(1);
}
}
地址>
- 接收方示例
#include
#include /* See NOTES */
#include
#include
#include /* superset of previous */
#include
#include
#include
int main(int argc,char *argv[])
{
if(argc!=2)
{
printf("./a.out <端口號>\n");
return 0;
}
/*1.創(chuàng)建網(wǎng)絡套接字*/
int sockfd=socket(AF_INET,SOCK_DGRAM, 0);
if(sockfd==-1)
{
printf("創(chuàng)建UDP網(wǎng)絡套接字失敗\n");
return 0;
}
/*2.綁定端口號*/
struct sockaddr_in addr=
{
.sin_family=AF_INET,
.sin_port=htons(atoi(argv[1])),//發(fā)送的端口號
.sin_addr.s_addr=INADDR_ANY,//本地所有IP
};
if(bind(sockfd,(const struct sockaddr *)&addr,sizeof(struct sockaddr)))
{
printf("綁定端口號失敗\n");
return 0;
}
/*開始接收數(shù)據(jù)*/
char buff[256];
struct sockaddr_in c_addr;
socklen_t addrlen=sizeof(struct sockaddr_in);
ssize_t size;
while(1)
{
size=recvfrom(sockfd,buff,sizeof(buff)-1,0,(struct sockaddr *)&c_addr,&addrlen);
if(size<=0)
{
printf("接收數(shù)據(jù)失敗\n");
continue;
}
buff[size]='\0';
printf("[%s:%d] %s,len=%ld byte\n",inet_ntoa(c_addr.sin_addr),ntohs(c_addr.sin_port),buff,size);
}
close(sockfd);
}
2.2 設置UDP廣播特性
??默認情況下UDP通訊是不支持廣播特性,需要廣播特性則需要設置UDP套接字屬性。
//設置該套接字為廣播類型,
int nb = 0;
nb = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));
if(nb == -1)
{
printf("設置廣播類型錯誤.\n");
}
- 廣播發(fā)送方示例
#include /* See NOTES */
#include
#include
#include
#include /* superset of previous */
#include
#include
#include
int main(int argc,char *argv[])
{
if(argc!=3)
{
printf("格式:./a.out <端口號> \n");
return 0;
}
int sockfd=socket(AF_INET,SOCK_DGRAM,0);
if(sockfd==-1)
{
printf("創(chuàng)建網(wǎng)絡套接字失敗\n");
return 0;
}
//設置該套接字為廣播類型,
const int opt = 1;
int nb = 0;
nb = setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&opt, sizeof(opt));
if(nb == -1)
{
printf("設置廣播類型錯誤.\n");
}
struct sockaddr_in s_addr=
{
.sin_family=AF_INET,
.sin_port=htons(atoi(argv[1])),
.sin_addr.s_addr=inet_addr(argv[2]),//本地所有IP
};
char buff[]="UDP send data test,hello,world!";
ssize_t size;
while(1)
{
size=sendto(sockfd,buff,sizeof(buff),0,( const struct sockaddr * )&s_addr,sizeof(s_addr));
printf("發(fā)送數(shù)據(jù)成功size=%ld\n",size);
sleep(1);
}
}
地址>
審核編輯 黃昊宇
-
廣播
+關注
關注
1文章
305瀏覽量
23047 -
編程
+關注
關注
88文章
3614瀏覽量
93685 -
UDP
+關注
關注
0文章
325瀏覽量
33931
發(fā)布評論請先 登錄
相關推薦
評論