跳过正文

VxWorks下UDP网络编程

UDP VxWorks Socket
目录
app - 这篇文章属于一个选集。
§ 11: 本文

VxWorks 是一种广泛应用于嵌入式系统的高性能实时操作系统,其网络编程能力依托于强大的网络协议栈,支持 TCP/IP、UDP 等标准协议。VxWorks 的网络编程接口与 POSIX socket API 高度兼容,开发者可以使用熟悉的 socket()、bind()、sendto()、recvfrom() 等函数实现通信。同时,结合 VxWorks 的实时特性,网络任务可以通过多任务机制(如 taskSpawn)高效运行,满足低延迟和高可靠性的需求。VxWorks 提供 sockLib 和 inetLib 等库来支持网络功能,适用于工业控制、航空航天等领域中的网络应用开发。开发者需注意系统网络配置(如 IP 地址和路由)以及资源管理,以充分发挥其在嵌入式环境下的优势。

本文简介介绍VxWorks系统下如何进行UDP Socket编程。

UDP概述
#

UDP 允许应用程序在不建立连接的情况下发送封装的 IP 数据包。作为 OSI 参考模型中的一种无连接传输层协议,UDP 主要用于对数据包到达顺序要求不高的传输中,数据包传输顺序的检查和排序由应用层负责。它提供了一种面向事务的、简单的、不可靠的消息传递服务。本质上,UDP 是 IP 协议与上层协议之间的接口。它使用端口使多个应用程序能够在同一设备上运行。UDP 提供无连接通信,不保证传输数据包的可靠性,适用于少量数据一次性传输的场景,其传输可靠性由应用层负责。

UDP socket 通信过程相较于 TCP 更为简单,因为它是一种无连接的协议,不需要建立连接或维护状态。以下是 UDP socket 通信的基本过程,用简洁的语言描述:

  1. 创建 Socket

发送端和接收端分别创建一个 UDP socket。可以用编程语言(如 C、Python、Java 等)中的 socket 函数实现,例如指定协议类型为 UDP。

  1. 绑定地址和端口(接收端)

接收端需要将 socket 绑定到一个特定的 IP 地址和端口号,以便监听来自发送端的数据。这是通过 bind() 操作完成的。发送端通常不需要绑定,除非需要指定特定的源端口。

  1. 发送数据(发送端)

发送端通过 socket 使用 sendto() 函数将数据包发送到目标 IP 地址和端口号。数据包包含目标地址信息,因此不需要事先建立连接。

  1. 接收数据(接收端)

接收端通过 socket 使用 recvfrom() 函数监听并接收数据包。接收到的数据包括发送端的地址信息,接收端可以根据需要处理这些数据。

  1. 重复或关闭

发送端和接收端可以根据需求反复发送和接收数据。因为 UDP 是无连接的,不需要显式关闭连接,但用完后可以通过 close() 释放 socket 资源。

特点和注意事项:
#

  • 无连接:发送前无需握手,数据直接发出。
  • 不可靠:不保证数据到达,也不保证顺序,丢包或乱序由应用层处理。
  • 轻量快速:没有连接管理和重传机制,适合实时性要求高的场景(如视频流、DNS 查询)。

在 VxWorks 下编写 UDP socket 程序需要使用 VxWorks 提供的网络编程接口,它与 POSIX socket API 类似,但需要注意操作系统的实时特性以及任务管理。以下是一个简单的 VxWorks UDP 通信程序示例,包括发送端和接收端的基本实现。我们将假设这是一个单任务程序,分别展示发送和接收的逻辑。

示例代码
#

在 VxWorks 下实现 UDP 发送和接收

#include <vxWorks.h>
#include <sockLib.h>
#include <inetLib.h>
#include <stdio.h>
#include <string.h>
#include <taskLib.h>

#define SERVER_PORT 12345          /* 接收端端口号 */
#define SERVER_IP "192.168.1.100"  /* 接收端 IP 地址 */
#define BUFFER_SIZE 1024           /* 缓冲区大小 */

/* UDP 发送任务 */
void udpSender(void)
{
    int sockfd;
    struct sockaddr_in serverAddr;
    char sendBuffer[BUFFER_SIZE] = "Hello from VxWorks UDP Sender!";

    /* 创建 UDP socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == ERROR)
    {
        printf("Failed to create sender socket\n");
        return;
    }

    /* 配置目标地址 */
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP);

    /* 发送数据 */
    while (1)
    {
        int bytesSent = sendto(sockfd, sendBuffer, strlen(sendBuffer), 0,
                               (struct sockaddr *)&serverAddr, sizeof(serverAddr));
        if (bytesSent == ERROR)
        {
            printf("Failed to send data\n");
            close(sockfd);
            return;
        }
        printf("Sent: %s\n", sendBuffer);
        taskDelay(60); /* 延迟 1 秒 (假设 sysClkRateGet() 为 60 ticks/sec) */
    }

    /* 关闭 socket(实际可能不会到达这里) */
    close(sockfd);
}

/* UDP 接收任务 */
void udpReceiver(void)
{
    int sockfd;
    struct sockaddr_in serverAddr, clientAddr;
    char recvBuffer[BUFFER_SIZE];
    int addrLen = sizeof(clientAddr);

    /* 创建 UDP socket */
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == ERROR)
    {
        printf("Failed to create receiver socket\n");
        return;
    }

    /* 配置本地地址并绑定 */
    memset(&serverAddr, 0, sizeof(serverAddr));
    serverAddr.sin_family = AF_INET;
    serverAddr.sin_port = htons(SERVER_PORT);
    serverAddr.sin_addr.s_addr = INADDR_ANY; /* 监听所有接口 */

    if (bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)) == ERROR)
    {
        printf("Bind failed\n");
        close(sockfd);
        return;
    }

    printf("UDP Receiver listening on port %d...\n", SERVER_PORT);

    /* 接收数据 */
    while (1)
    {
        int bytesReceived = recvfrom(sockfd, recvBuffer, BUFFER_SIZE - 1, 0,
                                     (struct sockaddr *)&clientAddr, &addrLen);
        if (bytesReceived == ERROR)
        {
            printf("Failed to receive data\n");
            close(sockfd);
            return;
        }

        recvBuffer[bytesReceived] = '\0'; /* 确保字符串结束 */
        printf("Received from %s:%d: %s\n",
               inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port), recvBuffer);
    }

    /* 关闭 socket(实际可能不会到达这里) */
    close(sockfd);
}

/* 主函数:启动发送和接收任务 */
void startUdpTasks(void)
{
    /* 启动接收任务 */
    if (taskSpawn("tUdpReceiver", 100, 0, 20000, (FUNCPTR)udpReceiver,
                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
    {
        printf("Failed to spawn udpReceiver task\n");
    }

    /* 启动发送任务 */
    if (taskSpawn("tUdpSender", 100, 0, 20000, (FUNCPTR)udpSender,
                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0) == ERROR)
    {
        printf("Failed to spawn udpSender task\n");
    }
}

代码说明
#

  1. 头文件:
  • sockLib.h 和 inetLib.h 是 VxWorks 提供的 socket 和网络函数库。
  • taskLib.h 用于任务管理。
  1. 发送端(udpSender):
  • 创建一个 UDP socket。
  • 配置目标地址(SERVER_IP 和 SERVER_PORT)。
  • 使用 sendto() 发送字符串,每秒发送一次(通过 taskDelay 实现)。
  1. 接收端(udpReceiver):
  • 创建一个 UDP socket 并绑定到指定端口(SERVER_PORT)。
  • 使用 recvfrom() 接收数据,并打印发送端的 IP 和端口信息。
  1. 主函数(startUdpTasks):
  • 使用 taskSpawn 创建两个任务分别运行发送和接收逻辑。
  • 任务优先级设为 100,栈大小为 20000 字节。

使用方法
#

  • 将代码加载到 VxWorks 目标系统中(通过 Workbench 或命令行)。
  • 在 VxWorks shell 中调用 startUdpTasks() 启动程序。
  • 确保网络配置正确(目标 IP 和端口可达)。

注意事项
#

  • 网络配置:VxWorks 的网络栈需要提前配置好(例如通过 ifconfig 设置 IP)。
  • 任务延迟:taskDelay(60) 假设系统时钟频率为 60 ticks/sec,需根据实际系统调整。
  • 错误处理:示例中错误处理较简单,实际应用中应更完善。
  • 单机测试:可以将 SERVER_IP 设为 “127.0.0.1” 在同一设备上测试。
app - 这篇文章属于一个选集。
§ 11: 本文

相关文章

基于VxWorks的视频采集系统的设计与实现
VxWorks BT848
VxWorks下Telnet客户端的C语言实现代码
VxWorks Telnet Client
基于ETX与VxWorks的嵌入式车辆导航系统的设计
VxWorks ETX