Linux關於socket(深入UDP與TCP區別)
阿新 • • 發佈:2018-12-28
socket之資料報套接字(UDP)
資料報套接字(SOCK_DGRAM) 資料報套接字定義了一種無連線的服務,資料通過相互獨立的報文進行傳輸,是無序的,並且不保證可靠,無差錯。使用資料報協議UDP協議。
socket之UDP實現
udp沒有伺服器和客戶端的概念,但是我們為了和前一篇文章《Linux關於socket(TCP實現C/S)》相結合,進行總結TCP和UDP的區別,我們用程式碼實現UDP的服務端和客戶端。
實現程式碼前,我們要知道UDP的寫入是用sendto,讀出使用recvfrom.而TCP讀的話可以用read,send,寫的話用recv,write
UDP不用實現TCP服務端的listen,accept,和客戶端的connect,它直接建立完就可以使用,所以程式碼比較簡潔。
以下是服務端程式碼
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> /* for struct sockaddr_in*/ #include <sys/errno.h> #include <signal.h> //關於伺服器udp的socket void error_exit(char *name) { perror(name); exit(-1); } int main(int argc,char *argv[]) { int sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd<0) { error_exit("create error"); } //繫結地址(ip和埠號) struct sockaddr_in svraddr; memset(&svraddr,0,sizeof(svraddr)); svraddr.sin_family=AF_INET; svraddr.sin_addr.s_addr=INADDR_ANY; //svraddr.sin_addr.s_addr=inet_addr("127.0.0.1");第二種寫法 svraddr.sin_port=htons(5555); int ret=bind(sockfd,(struct sockaddr*)&svraddr,sizeof(svraddr)); if(ret<0) { error_exit("bind error"); } char buf[1024]={0}; struct sockaddr_in removeaddr; int addrlen=sizeof(removeaddr); while(1) { memset(buf,0,1024); int rdsize= recvfrom(sockfd,buf,1024,0,(struct sockaddr*)&removeaddr,&addrlen); if(rdsize>0) { printf("read data %s\n",buf); } } return 0; }
以下是客服端程式碼:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/socket.h> #include <netinet/in.h> /* for struct sockaddr_in*/ #include <sys/errno.h> #include <signal.h> //關於客戶端udp的socket void error_exit(char *name) { perror(name); exit(-1); } int main(int argc,char *argv[]) { int sockfd=socket(AF_INET,SOCK_DGRAM,0); if(sockfd<0) { error_exit("create error"); } struct sockaddr_in svraddr; memset(&svraddr,0,sizeof(svraddr)); svraddr.sin_addr.s_addr=inet_addr("127.0.0.1"); svraddr.sin_port= htons(5555); svraddr.sin_family=AF_INET; int wdsize=sendto(sockfd,"helloworld",strlen("helloworld"),0,(struct sockaddr*)&svraddr,sizeof(svraddr)); wdsize=sendto(sockfd,"helloworld",strlen("helloworld"),0,(struct sockaddr*)&svraddr,sizeof(svraddr)); wdsize=sendto(sockfd,"helloworld",strlen("helloworld"),0,(struct sockaddr*)&svraddr,sizeof(svraddr)); printf("write size%d\n",wdsize); return 0; }
以上程式碼和上一篇關於TCP的實現方法差不多,實際更簡潔(UDP實現起來更簡單)
為了看出和TCP的區別,我們同樣寫入三次helloworld
以下是先執行伺服器,在等待中
執行客服端,寫入進去
切換到伺服器,讀到字串
通過讀到的字串,我們可以清晰看到helloworld是一次次讀出來,和TCP的連續讀出不一樣,這就是UDP的特點就是不粘包。
總結:
TCP 有連線,會粘包,資料不會丟失,流式套接字
UDP 無連線,不會粘包,資料會丟失,報文套接字