1. 程式人生 > >Linux關於socket(深入UDP與TCP區別)

Linux關於socket(深入UDP與TCP區別)

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 無連線,不會粘包,資料會丟失,報文套接字