Linux应用 UDP网络编程

1、前言

1.1 定义

UDP 是一种无连接的传输协议,它不需要在通信之前建立连接,也不保证数据传输的可靠性。UDP 将数据打包成数据报进行传输,不进行数据分段和重组,因此传输效率较高。

1.2 应用场景

  • 实时性要求高的应用:由于 UDP 不保证数据传输的可靠性,适用于实时性要求高的应用,如音频/视频流的传输、在线游戏等。
  • 广播和多播通信:UDP 支持广播和多播通信,适用于需要向多个主机发送相同数据的场景。
  • 简单的数据传输:对于一些简单的数据传输场景,如 DNS 查询、SNMP 等,UDP 是一个较为合适的选择。

1.3 网络中的作用

在网络分层模型中,UDP 位于传输层,与 TCP 一起为应用层提供数据传输服务。

  • 为应用层提供无连接的数据传输服务:UDP 不需要建立连接,适用于一些实时性要求高、数据传输较简单的应用场景。
  • 提供数据报服务:UDP 将数据打包成数据报进行传输,不进行数据分段和重组,传输效率较高。
  • 支持广播和多播通信:UDP 支持向多个主机发送相同数据,适用于广播和多播通信场景。

2、常用接口

2.1 socket函数

创建一个套接字,用于后续的数据传输。

复制代码
int socket(int domain, int type, int protocol);

入参:

  • domain:指定协议族,通常为 AF_INET(IPv4)或 AF_INET6(IPv6)。
  • type:指定套接字类型,通常为 SOCK_DGRAM 表示 UDP 套接字。
  • protocol:指定协议,通常为 0 表示使用默认协议。

返回值:

  • 成功时返回套接字描述符,失败时返回 -1

2.2 blind函数

将套接字绑定到特定的IP地址和端口号。

复制代码
int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);

入参:

  • sockfd:套接字描述符,由socket()函数返回
  • addr:指向sockaddr结构体的指针,包含要绑定的IP地址和端口号信息
  • addrlensockaddr结构体的长度

返回值:

  • 成功时返回0,失败时返回-1

2.3 sendto函数

向指定地址发送数据。

复制代码
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);

入参:

  • sockfd:套接字描述符。
  • buf:指向要发送数据的缓冲区。
  • len:要发送数据的长度。
  • flags:发送标志,通常为 0
  • dest_addr:目标地址的结构体指针,可以是 struct sockaddr_instruct sockaddr_in6
  • addrlen:目标地址结构体的长度。

返回值:

  • 成功时返回发送的字节数,失败时返回 -1

2.4 recvfrom 函数

从指定的目标地址接收数据。

复制代码
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);

入参:

  • sockfd:套接字描述符
  • buf:指向接收数据的缓冲区
  • len:缓冲区长度
  • flags:接收控制标志,一般设为0
  • src_addr:指向发送方地址信息的sockaddr结构体指针
  • addrlen:发送方地址结构体的长度

返回值:

  • 成功时返回接收的字节数,失败时返回-1

3、编程测试

3.1 一般编程步骤

UDP 服务器端编程流程:

  • 创建套接字:调用socket()函数创建一个UDP套接字。

  • 绑定地址:调用bind()函数将服务器端地址绑定到套接字上。

  • 接收数据:循环调用recvfrom()函数接收客户端发送的数据。

  • 处理数据:对接收到的数据进行处理,可以根据需求进行相应的逻辑操作。

  • 发送响应:根据处理结果,调用sendto()函数向客户端发送响应数据。

  • 关闭套接字:通信结束后,调用close()函数关闭套接字。

UDP 客户端编程流程:

  • 创建套接字:调用socket()函数创建一个UDP套接字。

  • 准备数据:准备要发送的数据,并将目标服务器地址信息填入sockaddr结构体中。

  • 发送数据:调用sendto()函数向服务器发送数据。

  • 接收响应:调用recvfrom()函数接收服务器端的响应数据。

  • 处理响应:对接收到的响应数据进行处理,可以根据需求进行相应的逻辑操作。

  • 关闭套接字:通信结束后,调用close()函数关闭套接字。

3.2 服务器编程

编写服务器代码如下:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8888
#define BUF_SIZE 1024

int main() 
{
    int sockfd;
    struct sockaddr_in server_addr, client_addr;
    char buffer[BUF_SIZE];

    // 创建 UDP 套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    // 绑定服务器地址和端口
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = htons(PORT);
    bind(sockfd, (struct sockaddr*)&server_addr, sizeof(server_addr));

    printf("UDP Server listening on port %d...\n", PORT);

    socklen_t len = sizeof(client_addr);
    
    // 接收数据
    recvfrom(sockfd, buffer, BUF_SIZE, 0, (struct sockaddr*)&client_addr, &len);
    printf("Received from client: %s\n", buffer);

    // 回复客户端数据
    sendto(sockfd, "Message received", strlen("Message received"), 0, (struct sockaddr*)&client_addr, len);

    close(sockfd);
    return 0;
}

3.3 客户端编程

编写客户端代码如下:

复制代码
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>

#define PORT 8888
#define SERVER_IP "127.0.0.1"
#define BUF_SIZE 1024

int main() 
{
    int sockfd;
    struct sockaddr_in server_addr;
    char buffer[BUF_SIZE] = "msg from client";

    // 创建 UDP 套接字
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);

    // 设置服务器地址和端口
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP);
    server_addr.sin_port = htons(PORT);

    // 发送数据到服务器
    sendto(sockfd, buffer, strlen(buffer), 0, (struct sockaddr*)&server_addr, sizeof(server_addr));

    // 接收服务器回复的数据
    recvfrom(sockfd, buffer, BUF_SIZE, 0, NULL, NULL);
    printf("Server replied: %s\n", buffer);

    close(sockfd);
    return 0;
}

3.4 测试

开启两个终端进行测试,先开启服务器,再开启客户端,测试结果如下:

4、总结

本文讲解了UDP的定义以及应用场景,列出了编程中常用的接口,最后编写程序进行测试。

相关推荐
Championship.23.242 小时前
Linux 3.0 锁机制与故障排查详解
linux·运维·服务器
天疆说2 小时前
Zotero Connector 在 Edge 里找不到桌面 Zotero(Linux / Zotero 9.0.6 / Edge 150)
linux·前端·edge
风123456789~4 小时前
【Linux专栏】ls 排除某个文件
linux·运维·服务器
IpdataCloud4 小时前
担心IP暴露隐私?用安全IP查询工具自查,三步配置网络出口
网络·tcp/ip·安全·ip
xy34534 小时前
wireshark 如何捕获信息
网络·测试工具·渗透测试·wireshark
IT曙光4 小时前
ubuntu apt-get离线源制作
linux·ubuntu
其实防守也摸鱼5 小时前
运维--学习阶段问题解答(1)(自测)
linux·运维·服务器·数据库·学习·自动化·命令模式
懒鸟一枚5 小时前
深入理解 Linux 内存、Swap 交换分区与分页机制的关系
java·linux·数据库
玖玥拾6 小时前
C# 语言进阶(十五)C# 游戏服务端 MySQL 数据库
服务器·开发语言·网络·数据库·mysql·c#
Darkwanderor6 小时前
对Linux的进程控制的研究
linux·运维·c++