UDP簡單介紹
傳輸層主要應用的協議模型有兩種,一種是TCP協議,另外一種則是UDP協議。TCP協議在網絡通信中占主導地位,絕大多數的網絡通信借助TCP協議完成數據傳輸。但UDP也是網絡通信中不可或缺的重要通信手段。
相較於TCP而言,UDP通信的形式更像是發短信。不需要在數據傳輸之前建立、維護連接。只專心獲取數據就好。省去了三次握手的過程,通信速度可以大大提高,但與之伴隨的通信的穩定性和正確率便得不到保證。因此,我們稱UDP為“無連接的不可靠報文傳遞”。
那么與我們熟知的TCP相比,UDP有哪些優點和不足呢?由於無需創建連接,所以UDP開銷較小,數據傳輸速度快,實時性較強。多用於對實時性要求較高的通信場合,如視頻會議、電話會議等。但隨之也伴隨着數據傳輸不可靠,傳輸數據的正確率、傳輸順序和流量都得不到控制和保證。所以,通常情況下,使用UDP協議進行數據傳輸,為保證數據的正確性,我們需要在應用層添加輔助校驗協議來彌補UDP的不足,以達到數據可靠傳輸的目的。
如下圖所示,簡單的UDP的CS模型通信過程,由於UDP不需要維護連接,程序邏輯簡單了很多,但是UDP協議是不可靠的,保證通訊可靠性的機制需要在應用層實現。
代碼實現:
server.c
1 #include<stdio.h> 2 #include<unistd.h> 3 #include<stdlib.h> 4 #include<sys/socket.h> 5 #include<string.h> 6 #include<arpa/inet.h> 7 #include<ctype.h> 8 9 #define SERVER_PORT 8000 10 11 int main(int agrc,char* argv[]) 12 { 13 int sockfd; 14 struct sockaddr_in servaddr,clieaddr; 15 socklen_t clieaddr_len; 16 char buf[BUFSIZ]; 17 char str[INET_ADDRSTRLEN]; 18 int i,n; 19 20 sockfd=socket(AF_INET,SOCK_DGRAM,0); 21 bzero(&servaddr,sizeof(servaddr)); 22 servaddr.sin_family=AF_INET; 23 servaddr.sin_addr.s_addr=htonl(INADDR_ANY); 24 servaddr.sin_port=htons(SERVER_PORT); 25 26 bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); 27 28 printf("Acceptint Connections ...\n"); 29 while(1) 30 { 31 clieaddr_len=sizeof(clieaddr); 32 n=recvfrom(sockfd,buf,BUFSIZ,0,(struct sockaddr*)&clieaddr,&clieaddr_len); 33 if(n==-1) 34 { 35 perror("recvfrom error"); 36 } 37 printf("received from %s at PORT %d\n",inet_ntop(AF_INET,&clieaddr.sin_addr,str,sizeof(str)),ntohs(clieaddr.sin_port)); 38 for(i=0;i<n;i++) 39 { 40 buf[i]=toupper(buf[i]); 41 } 42 n=sendto(sockfd,buf,n,0,(struct sockaddr*)&clieaddr,sizeof(clieaddr)); 43 if(n==-1) 44 { 45 perror("sendto error"); 46 } 47 } 48 close(sockfd); 49 50 return 0; 51 }
client.c
1 #include<stdio.h> 2 #include<string.h> 3 #include<unistd.h> 4 #include<arpa/inet.h> 5 #include<ctype.h> 6 7 #define SERVER_PORT 8000 8 9 int main(int argc,char* argv[]) 10 { 11 struct sockaddr_in servaddr; 12 int sockfd,n; 13 char buf[BUFSIZ]; 14 15 sockfd = socket(AF_INET,SOCK_DGRAM,0); 16 17 bzero(&servaddr,sizeof(servaddr)); 18 servaddr.sin_family = AF_INET; 19 inet_pton(AF_INET,"0.0.0.0",&servaddr.sin_addr); 20 servaddr.sin_port = htons(SERVER_PORT); 21 22 bind(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr)); 23 24 while(fgets(buf,BUFSIZ,stdin)!= NULL) 25 { 26 n = sendto(sockfd,buf,strlen(buf),0,(struct sockaddr*)&servaddr,sizeof(servaddr)); 27 if(n == -1) 28 { 29 perror("sendto error"); 30 //printf("*********************\n"); 31 } 32 n = recvfrom(sockfd,buf,BUFSIZ,0,NULL,0);//NULL:不關心對端信息 33 if(n == -1) 34 { 35 perror("recvfrom error"); 36 } 37 write(STDOUT_FILENO,buf,n); 38 } 39 close(sockfd); 40 return 0; 41 }
測試結果:
1.首先啟動服務端程序
2.再啟動客戶端程序
3.在客戶端輸入一個字符串回車
4.在客戶端可以看到服務端轉換的大寫字符串回寫到客戶端屏幕
5.服務端可以看到客戶端連接的信息(IP和端口號)