无连接的
,即发送数据之前不需要建立连接(发送数据结束时也没有连接可释放),减少了开销和发送数据之前的时延尽最大努力交付
,即不保证可靠交付,主机不需要维持复杂的连接状态表(如发短信,你无法确定对方是否收到)面向报文
的,发送方的 UDP 对应用程序交下来的报文,在添加首部后就向下交付 IP 层。UDP 对应用层交下来的报文,既不合并,也不拆分,而是保留这些报文的边界
没有拥塞控制
,网络出现的拥塞不会使源主机的发送速率降低。这对某些实时应用是很重要的首部开销小
,只有8个字节,比 TCP 的20个字节的首部要短源端口:在需要对方回信时1,不需要时可用全0
目标端口:这在终点交付报文时必须使用
长度:UDP 用户数据报的长度,其最小值是8(仅有首部)
校验和: 检测 UDP 用户数据报在传输中是否有错。有错就丢弃
UDP网络通信(类似发送/接收短信):
类比 |
作用 |
功能 |
函数 |
有手机 |
有网络通信协议UDP |
创建套接字文件 |
socket() |
有手机卡(号码) |
通信协议中需要有自己的网络信息 |
绑定(指定)本地当前进程的网络信息 |
bind() |
填写对方手机号,发送短信 |
使用协议发送数据 |
协议中添加对方信息发送数据(ip端口) |
sendto() |
接收短信 |
使用协议接收数据 |
根据解析的信息接收数据 |
recvfrom() |
关闭 |
不再进行通信 |
关闭通信 |
close() |
#include
#include
//创建套接字文件,为进程添加一个对应的网络通信协议(文件),返回值就是创建号的文件描述符(socket描述符就代表一套协议---套接字)
int socket(int domain, int type, int protocol);
参数1:
int domain:地址族,选用那种网络层协议地址
AF_INET------IPV4
AF_INET6------IPV6
参数2:
int type:套接字类型
SOCK_STREAM--------TCP
SOCK_DGRAM---------UDP
SOCK_RAW:原始套接字(没有传输层协议)
参数3:
int protocol:套接字协议
0:套接字默认协议
返回值:
int:整数---------文件描述符(套接字文件)
成功:返回套接字描述符 >= 0
失败:返回-1
#include
/* See NOTES */ #include
//绑定本地网络信息到套接字中
int bind(int sockfd, const struct sockaddr *addr,socklen_t addrlen);
参数1:
int sockfd:绑定本地网络信息到哪个套接字上(绑定到哪一套协议上)
参数2:
const struct sockaddr *addr:结构体地址,这个结构体中存储的本地网络信息(要绑定的网络信息ip、port)
struct sockaddr {//通用结构体,表示一个网络信息内容
sa_family_t sa_family;
char sa_data[14];
}
//IPV4 网络信息结构体
struct sockaddr_in {
sa_family_t sin_family;//地址族 AF_INET
in_port_t sin_port;//端口
struct in_addr sin_addr;//结构体变量--ip地址
};
/* Internet address. */
struct in_addr {
uint32_t s_addr;//ipv4地址
};
参数3:
socklen_t addrlen:整数,结构体大小(确定信息结构体的大小)
返回值:
成功:返回0
失败:返回-1
#include
#include
//使用UDP协议发送数据
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,const struct sockaddr *dest_addr, socklen_t addrlen);
参数1:
int sockfd:套接字对象,使用哪个套接字发送数据
参数2:
const void *buf:要发送的数据的内存首地址
参数3:
size_t len:发送的数据的大小
参数4:
int flags:标志
0:阻塞发送
参数5:
const struct sockaddr *dest_addr:发送的目标网络信息
参数6:
socklen_t addrlen:结构体大小
返回值:
成功:返回发送的字节数
失败:返回-1
#include
#include
//使用UDP协议接收数据
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,struct sockaddr *src_addr, socklen_t *addrlen);
参数1:
int sockfd:套接字,指定使用哪个套接字来接收(ip,port来进行检测)
参数2:
void *buf:接收的数据的存放的地址
参数3:
size_t len:指定能够接收存储的最大大小
参数4:
int flags:标志
0:阻塞接收
参数5:
struct sockaddr *src_addr:在接收数据时,存储发送方的ip和port,如果不需要写NULL
参数6:
socklen_t *addrlen:存储信息结构体的大小,不需要写NULL
返回值:
成功:返回收到的大小
失败:返回-1
int close(int fd)
//通过UDP协议,发送数据,接收数据
#include
#include
#include
#include
#include
#include
#include
int main()
{
//1、创建套接字,选择对应的网络通信协议组
int socketfd = socket(AF_INET,SOCK_DGRAM,0);//当前进程使用UDP IP 协议
/* if(socketfd < 0)
{
return -1;
}
*/
//2、绑定套接字,对套接字添加自己当前进行需要到本地网络信息
struct sockaddr_in addr;//有一个IPV4网络信息结构体
addr.sin_family = AF_INET;//地址族-----IPV4
addr.sin_port = htons(10000);//为当前进程添加的端口号为10000-------主机10000端字节序转换为网络字节序
addr.sin_addr.s_addr = inet_addr("192.168.124.63");
bind(socketfd,(struct sockaddr *)&addr,sizeof(addr));
char buf[20];
memset(buf,0,20);//清空buf
struct sockaddr_in dest_addr;//接收方网络信息结构体
dest_addr.sin_family = AF_INET;//地址族-----IPV4
dest_addr.sin_port = htons(2000);
dest_addr.sin_addr.s_addr = inet_addr("192.168.124.27");
while(1)
{
fgets(buf,20,stdin);
sendto(socketfd,buf,20,0,(struct sockaddr *)&dest_addr,sizeof(dest_addr));//发送
memset(buf,0,20);//清空buf
int num=recvfrom(socketfd,buf,20,0,NULL,NULL);
printf("recv size is %d\n",num);
printf("data is %s\n",buf);
}
return 0;
}
通信结果如下图所示: