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 无连接,不会粘包,数据会丢失,报文套接字