1、UDP
/*
udp传输层协议,和tcp是一样的
特点:
面向无连接的,不安全的,报式传输协议
1.无连接:ldp通信的时候不需要connect
1) 通信不需要建立连接
2) 如果想给对方发送数据,只需要指定对方的IP和端口
2. udp会丢包
1) 数据丢失了就没有了,没有数据校验机制
2) udp不会丢失一部分数据,丢就是全丢,不丢就是一点不不丢
3.报式:
发送端发送多少数据,接牧端接收多少数据|
*/
2、UDP通信流程
udp通信过程中,服务器和客户端做的操作几乎是一样的
- 服务器端
// 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. 创建一个通信的套接字
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();
- 操作函数
//接收数据
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
- 网络层
- 网络接口层