问题:如何使用 UDP 进行数据收发?再论 UDP 协议
- UDP 是无连接的(不可靠的,无应答消息,数据包无序号标识)
- UDP 是面向数据包的,
对应用层数据既不合并也不拆分
(保留数据包边界) - UDP 没有拥塞控制,网络出现的拥塞不会使源主机的发送速率降低
- UDP 支持一对一,一对多,多对一和多对多的交互通信
- UDP 消息头开销小,只有 8 个字节(TCP 消息头共 20 个字节)
文章图片
UDP 和 IP 的区别
UDP 是建立于 IP 之上的数据传输协议
- IP 负责将 UDP 数据包从源主机传输到目标主机
- UDP 则将应用层数据投递到目标 socket (端口号)
UDP 几乎完整 “继承” 了 IP 传输的特性
- 通讯两端无交互,无流控,无超时重发,不具备可靠性
#include "sys/socket.h"ssize_t send(int sock,// socket 文件描述符
void *buf,// 需要发送的数据
size_t nbytes,// 需要发送的数据量
int flags,// 发送选项
struct sockaddr *to,// 接收地址信息
socklen_t addrlen);
// to 参数长度ssize_t recvfrom(int sock,// socket 文件描述符
void *buf,// 保存接收数据的地址
size_t nbytes,// 可接收的最大数据量
int flags,// 接收选项
struct sockaddr *from, // 接收地址信息
socklen_t *addrlen);
// 指向保存 from 参数长度的变量地址
UDP 编程模式 【《Linux网络开发必学教程》15_UDP 数据收发实战】
文章图片
编程实验:UDP 数据收发
client.c
#include
#include
#include
#include
#include
#include
#include int main()
{
int sock = 0;
struct sockaddr_in addr = {0};
struct sockaddr_in remote = {0};
socklen_t len = 0;
char buf[128] = {0};
char input[32] = {0};
int r = 0;
sock = socket(PF_INET, SOCK_DGRAM, 0);
if (sock == -1) {
printf("socket error\n");
return -1;
}addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(7777);
if (bind(sock, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
printf("udp bind error\n");
return -1;
}remote.sin_family = AF_INET;
remote.sin_addr.s_addr = inet_addr("127.0.0.1");
remote.sin_port = htons(8888);
while (1) {
printf("Input: ");
scanf("%s", input);
len = sizeof(remote);
sendto(sock, input, strlen(input), 0, (struct sockaddr*)&remote, len);
r = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);
if (r > 0) {
buf[r] = 0;
printf("Recvfrom %s\n", buf);
} else {
break;
}
}close(sock);
return 0;
}
server.c
#include
#include
#include
#include
#include
#include
#include int main()
{
int server = 0;
struct sockaddr_in saddr = {0};
int client = 0;
struct sockaddr_in remote = {0};
socklen_t asize = 0;
int len = 0;
char buf[32] = {0};
int r = 0;
server = socket(PF_INET, SOCK_DGRAM, 0);
if (server == -1) {
printf("server socket error");
return -1;
}saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
saddr.sin_port = htons(8888);
if (bind(server, (struct sockaddr*)&saddr, sizeof(saddr)) == -1) {
printf("udp server bind error\n");
return -1;
}printf("udp server start sucess\n");
while (1) {
len = sizeof(remote);
r = recvfrom(server, buf, sizeof(buf), 0, (struct sockaddr*)&remote, &len);
buf[r] = 0;
printf("r = %d\n", r);
printf("buf = %s\n", buf);
printf("remote ip = %s\n", inet_ntoa(remote.sin_addr));
printf("remote port = %d\n", ntohs(remote.sin_port));
sendto(server, buf, r, 0, (struct sockaddr*)&remote, len);
}close(server);
return 0;
}
输出:
server:
udp server start sucess
r = 5
buf = hello
remote ip = 127.0.0.1
remote port = 7777---client:
Input: hello
Recvfrom hello
思考:如何进行一对多的 UDP 数据收发?
推荐阅读
- 《Linux网络开发必学教程》14_数据收发的扩展用法 (下)
- 《Linux网络开发必学教程》12_TCP通讯框架(服务端设计)
- 《Linux网络开发必学教程》11_TCP通讯框架(客户端设计)
- 《Linux网络开发必学教程》10_应用协议解析模块(下)
- 《Linux网络开发必学教程》9_应用协议解析模块(上)
- 《Linux网络开发必学教程》8_应用协议设计与实现
- 《Linux网络开发必学教程》2_服务端编程初体验