UDP通信

1、UDP

/*
udp传输层协议,和tcp是一样的
特点:
	面向无连接的,不安全的,报式传输协议
	1.无连接:ldp通信的时候不需要connect
		1) 通信不需要建立连接
		2) 如果想给对方发送数据,只需要指定对方的IP和端口
	2. udp会丢包
		1) 数据丢失了就没有了,没有数据校验机制
		2) udp不会丢失一部分数据,丢就是全丢,不丢就是一点不不丢
	3.报式:
		发送端发送多少数据,接牧端接收多少数据|
*/

2、UDP通信流程

udp通信过程中,服务器和客户端做的操作几乎是一样的
在这里插入图片描述

  1. 服务器端
// 1. 创建一个通信的套接字   AF_INET使用IPv4 
int cfd = socket(AF_INET,SOCK_DGRAM,0); //通信使用udp
// 2.通信的套接字和本地的IP和端口绑定
// 绑定的目的:程序启动之后不主动发送数据,先接收数据,就需要绑定端口
// 如果不手动绑定端口,就会自动绑定端口,主动发送数据,可以自动绑定端口
struct sockaddr_in addr ;
bind(cfd, (struct sockaddr* )&addr, sizeof(addr) );
//  3.通信
接收数据:recvfrom( ) ;
发送数据:sendto();
// 4. 关闭通信的文件描述符
close(); 
  1. 客户端
// 1. 创建一个通信的套接字  
int cfd = socket(AF_INET,SOCK_DGRAM,0); //通信使用udp
// 2.通信的套接字和本地的IP和端口绑定
// 绑定的目的:程序启动之后不主动发送数据,先接收数据,就需要绑定端口
// 如果不手动绑定端口,就会自动绑定端口
struct sockaddr_in addr ;
bind(cfd, (struct sockaddr* )&addr, sizeof(addr) );
//  3.通信
接收数据:recvfrom( ) ;
发送数据:sendto();
// 4. 关闭通信的文件描述符
close();
  1. 操作函数
//接收数据
int accept(int sockfd, struct sockaddr *addr, socklen_t *addrlen);

//接收和发送数据的函数默认是阻塞的
//接收数据
ssize_t recvfrom( int sockfd, void *buf, size_t len, int flags,
					struct sockaddr *src_addr, socklen_t *addrlen) ;
参数∶
	- sockfd:通信的文件描述符
	- buf:指向一块有效内存地址,存储接收的数据
	- len:参数buf指向的内存大小
	- flags:使用默认属性,指定为0即可
	- src_addr:传出参数,保存发送端的地址信息(IP和端口)->大端(网络字节序)
		- 对发送端的地址不感兴趣,可以指定为NULL
	- addrlen:传入传出参数,类似于accept()最后一个参数
		- src_addr为NULL,该参数也指定为NULL即可
返回值:
	>0:接收的字节数
	-1:失败
	
//发送数据函数
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
				const struct sockaddr *dest_addr, socklen_t addrlen);
参数:
	- sockfd:通信的文件描述符
	- buf:指向一块有效内存地址,内存中存储了待发送的数据
	- len:参数buf指向的内存中待发送的数据长度
	- flags:使用默认属性,指定为0即可
	- dest_addr:传入参数,保存接收端的地址信息(IP和端口)->大端(网络字节序)
	- addrlen:传入参数,dest_addr参数指向的内存大小
返回值:
	>0: 发送的字节数
	-1:失败
  • 通信流程总结:
    • 服务器
// 1.创建通信的套接字
int fd = socket(af_inet, sock_dgram, 0);
// 1.5 如果服务器只接受数据,需要绑定端口
bind();
// 2.通信
recvfrom();
sendto();
// 3.关闭套接宇
close():
* 客户端
// 1.创建通信的套接字
int fd = socket(af_inet, sock_dgram, 0) ;
// 1.5 如果客户端是主动发送发送数据,绑定端口可以不写(随机绑定)
// bind();
// 2.通信
recvfrom();
sendto();
// 3.关闭套接字
close():

3、UDP服务器代码

#include <stdio.h>
#include <stdlib.h>
#incIude <unistd.h>
#incIude <string.h>
#include <arpa/inet.h>
//服务器端启动之后不发送数据,先接收数据
//需要手动绑定端口
int main()
{
	// 1.创建通信的套接字
	int fd = socket(AF_INET,SOCK_DGRAM,0);
	if(fd == -1)
	{
	      perror(exit(0));
	      exit(0);
    }
	// 接收数据需要绑定固定的端口
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port= htons(8989);
	addr.sin_addr.s_addr = INADDR ANY;
	int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));
	if(ret == -1)
	{
		perror("bind");
		exit(0);
	}
	//通信
	char ip[24];
	char buf[1024];
	struct sockaddr_in cliaddr;
	int clilen = sizeof(cliaddr);
	while(1)
	{
		//接收数据
		int len= recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr,&clilen);
		if(len==-1)
		{
			break;
		}
		printf("client ip: %s, port: %d\n",
				inet_ntop(AF_INET, &cliaddr.sin_addr.s_addr, ip, sizeof(ip)), 
				ntohs(cliaddr.sin_port));
		printf("client say: %s\n", buf);
		//回复数据
		sendto(fd, buf, strlen(len)+1, 0, (struct sockaddr*) &cliaddr, clilen);
		close(fd);
		return 0;
	}

	return 0;
}

4、UDP客户端代码

#include <stdio.h>
#include <stdlib.h>
#incIude <unistd.h>
#incIude <string.h>
#include <arpa/inet.h>
//客户端启动之后主动发送数据
//自动随机绑定端口
int main()
{

	// 1.创建通信的套接字
	int fd = socket(AF_INET,SOCK_DGRAM,0);
	if(fd == -1)
	{
	      perror(exit(0));
	      exit(0);
    }
    #if 0
	// 接收数据需要绑定固定的端口
	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_port= htons(8989);
	addr.sin_addr.s_addr = INADDR ANY;
	int ret = bind(fd,(struct sockaddr*)&addr,sizeof(addr));
	if(ret == -1)
	{
		perror("bind");
		exit(0);
	}
	#endif
	//通信
	char ip[24];
	char buf[1024];
	struct sockaddr_in cliaddr;
	int clilen = sizeof(cliaddr);
	//服务器地址
	struct sockaddr_in seraddr;
	seraddr.sin_family = AF_INET;
	seraddr.sin_port = htons(8989);
	inet_pton(AF_INET, "192.168.233.121",&seraddr.sin_addr.s_sddr);
	while(1)
	{
		sprintf(buf, "hello, world, %d...\n",num++);
		//发送数据,发送给服务器
		sendto(fd, buf, strlen(buf)+1, 0, (struct sockaddr*) &seraddr, sizeof(seraddr));
		memset(buf,0,sizeof(buf));
		int len= recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr*)&cliaddr,&clilen);
		if(len==-1)
		{
			break;
		}
		printf("server say: %s\n", buf);
		close(fd);
		return 0;
	}

	return 0;
}

5、应用场景

  • 数据容易丢,用在对数据没有那么敏感的场景下。
    • 用户名密码->不行
    • 文件传输->不行
    • 语言通信->可以
    • 视频聊天,视频会议->可以。
    • 屏幕共享->可以
  • 效率高
    • 不需要建立连接
    • 数据校验机制
  • 一般用于局域网,数据丢包比较少,广域网,网络环境不好容易丢包
    • qq处理文件传输使用的是tcp,其他都是udp
    • 比较大的公司,有一个人力和财力,会在应用层对udp通信的数据包进行校验
      • 应用层->检验udp数据,让rdp类似于tcp,但是效率高
      • 传输层> udp
      • 网络层
      • 网络接口层
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

落雨碎江南 Lucinda

如果您喜欢这篇文章欢迎打赏支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值