UDP编程及特点

目录

1.UDP编程流程

2.recvfrom()、sento()

3.代码演示

3.udp特点


1.UDP编程流程

socket()用来创建套接字,使用 udp 协议时,选择数据报服务 SOCK_DGRAM。sendto()用来发送数据,由于 UDP 是无连接的,每次发送数据都需要指定对端的地址(IP和端口)。recvfrom()接收数据,每次都需要传给该方法一个地址结构来存放发送端的地址。recvfrom()可以接收所有客户端发送给当前应用程序的数据,并不是只能接收某一个客户端的数据。 

2.recvfrom()、sento()

UDP 数据读写:

recvfrom()读取 sockfd 上的数据, buff 和 len 参数分别指定读缓冲区的位置和大小

ssize_t recvfrom(int sockfd, void *buff, size_t len, int flags.struct sockaddr* src_addr,socklen_t* addrlen);
  • src_addr 记录发送端的 socket 地址
  • addrlen 指定该地址的长度

sendto()往 socket 上写入数据, buff 和 len 参数分别指定写缓冲区的位置和数据长度

ssize_t sendto(int sockfd, void *buff, size_t len, int flags,struct sockaddr* dest_addr,socklen_t addrlen);
  • dest_addr 指定接收数据端的 socket 地址
  • addrlen 指定该地址的长度

3.代码演示

服务器代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main()
{
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	assert(sockfd!=-1);
	
    struct sockaddr_in saddr,caddr;
	memset(&saddr,0,sizeof(saddr));
	saddr.sin_family=AF_INET;
	saddr.sin_port=htons(6000);
	saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

	int res=bind(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));
	assert(res!=-1);
	
	while(1)
	{
		int len=sizeof(caddr);
		char buff[128]={0};
		recvfrom(sockfd,buff,127,0,(struct sockaddr*)&caddr,&len);
		printf("buff=%s\n",buff);
		sendto(sockfd,"ok",2,0,(struct sockaddr*)&caddr,sizeof(caddr));
	}
	close(sockfd);
	exit(0);
}

客户端代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

int main()
{
	int sockfd=socket(AF_INET,SOCK_DGRAM,0);
	assert(sockfd!=-1);
	
    struct sockaddr_in saddr;
	memset(&saddr,0,sizeof(saddr));
	saddr.sin_family=AF_INET;
	saddr.sin_port=htons(6000);
	saddr.sin_addr.s_addr=inet_addr("127.0.0.1");

	while(1)
	{
		printf("input:\n");
		int len=sizeof(saddr);
		char buff[128]={0};
		fgets(buff,127,stdin);
		if(strncmp(buff,"end",3)==0)
		{
			break;
		}

		sendto(sockfd,buff,strlen(buff),0,(struct sockaddr*)&saddr,sizeof(saddr));
		memset(buff,0,128);
		recvfrom(sockfd,buff,127,0,(struct sockaddr*)&saddr,&len);
		printf("buff=%s\n",buff);
	}
	close(sockfd);
	exit(0);
}

 运行结果:

3.udp特点

无链接的,不可靠的,数据报服务

1)多个客户端可以同时给服务器发送数据(因为没有建立链接,也就是说服务器没有只和某一个客户端建立链接);

2)服务器关掉再打开是可以接收数据的;(因为没有建立链接)

如果在服务器关闭时发送信息,会阻塞,在服务器再次开机时不会收到这条消息。客户端因为上条消息阻塞,不能再向服务器发送消息。

 3)数据报接收的特点:

用户数据报协议UDP只在IP的数据报服务之上增加了很少一点的功能,这就是复用和分用的功能以及差错检测的功能.

(复用:多个用户使用一个IO资源发送消息;分用:多个用户使用一个IO资源接收消息)

UDP是面向报文的,发送方的UDP对应用程序交下来的报文,在添加首部后就向下交付给IP层.UDP对应用层交下来的报文,即不合并,也不拆分,而是保留这些报文的边界.

这就是说,应用层交给UDP多长的报文,UDP就照样发送,即一次发送一个报文,如下图所示.

 在接收方的UDP,对IP层交上来的UDP用户数据报,在去掉首部后就原封不动地交付给上层地应用进程也就是说,UDP一次交付一个完整的报文

因此,应用程序必须选择合适大小的报文.若报文太长,UDP把它交给IP层后,IP层在传送时可能要进行分片,这会降低IP层的效率.反之,若报文太短,UDP把它交给IP层后,会使IP数据报的首部的相对长度太大,这也降低了IP层的效率.

UDP 数据报服务特点:发送端应用程序每执行一次写操作,UDP 模块就将其封装成一个 UDP 数据报发送。接收端必须及时针对每一个 UDP 数据报执行读操作,否则就会丢包。并且,如果用户没有指定足够的应用程序缓冲区来读取 UDP 数据,则UDP 数据将被截断
也就是udp协议sendto和recvfrom的次数是相同的,不会出现沾包;

(TCP:传输控制协议)

对比TCP字节流服务特点:

UDP的其他特点:

(1)UDP没有拥塞控制,因此网络上出现的拥塞不会使源主机的发送速率降低,这对某些实时应用是很重要的.很多的实时应用(如IP电话,实时视频会议等)要求源主机以恒定的速率发送数据,并且允许在网络发生拥塞时丢失一些数据,但却不允许数据有太大的时延.UDP正好适合这种要求.

虽然某些实时应用需要使用没有拥塞控制的UDP,但当很多的源主机同时都向网络发送高速率的实时视频流时,网络就有可能发生拥塞,结果大家都无法正常接收。因此,不使用拥塞控制功能的 UDP有可能会引起网络产生严重的拥塞问题。

还有一些使用 UDP的实时应用,需要对 UDP的不可靠的传输进行适当的改进,以减少数据的丢失。在这种情况下,应用进程本身可以在不影响应用的实时性的前提下,增加一些提高可靠性的措施,如采用前向纠错或重传已丢失的报文。

(2)UDP支持一对一,一对多,多对一,多对多的交互通信

(3)UDP的首部开销小,只有8个字节,比TCP的20个字节的首部短。

总结UDP主要特点
UDP 是无连接的,即发送数据之前不需要建立连接

UDP 尽最大努力交付,不保证可靠交付,不支持拥塞控制

UDP 面向报文,没有拥塞控制,很适合多媒体通信的要求

UDP 支持一对一,一对多,多对一和多对多的交互通信

UDP 首部开销小,只有8个字节

  • 33
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值