You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Winsock2与DLL的MATLAB UDP读取无数据问题排查

MATLAB调用UDP读取DLL返回全零问题排查与解决

问题描述

我正在尝试将MATLAB与基于Winsock2库的UDP数据读取C代码对接,把C代码编译为DLL后通过MATLAB的loadlibrary函数加载使用。C代码单独运行时能正常读取UDP数据,但通过MATLAB调用时返回结果全为零,已确认问题出在MATLAB端,附上相关代码文件,求问题原因及解决办法。

C代码

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <windows.h> // Include for Sleep function
#include "udpfunc2.h" 
#define BUFLEN 48
SOCKET s;
// Function to initialize UDP socket
int init_udp_socket() {
  WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) {
    printf("WSAStartup failed\n");
    return -1;
}
return 0;
}
// Function to create and bind UDP socket
int create_udp_socket() {
if ((s = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == INVALID_SOCKET) {
    printf("Socket creation failed\n");
    return -1;
}
return 0;
}
// Function to bind UDP socket to specified IP address and port
int bind_udp_socket(const char *ip_address, int port) {
struct sockaddr_in server;
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr(ip_address);
server.sin_port = htons(port);
if (bind(s, (struct sockaddr *)&server, sizeof(server)) == SOCKET_ERROR) {
    printf("Bind failed\n");
    return -1;
}
return 0;
}
// Function to set socket to non-blocking mode
int set_socket_nonblocking() {
unsigned long mode = 1; // 1 to enable non-blocking mode
if (ioctlsocket(s, FIONBIO, &mode) != 0) {
    printf("Failed to set socket to non-blocking mode\n");
    return -1;
}
return 0;
}
// Function to continuously read data through UDP as 12 single values (non-blocking)
void udp_read_continuous(float *data) {
struct sockaddr_in si_other;
int slen = sizeof(si_other);
int recv_len;
//zero out the memory buffer
memset(data,0,12 * sizeof(float));

recv_len = recvfrom(s, (char *)data, BUFLEN, 0, (struct sockaddr *)&si_other, &slen);
    
// Convert data from big-endian to host byte order
// Assuming each single value is a 32-bit float
for (int i = 0; i < 12; i++) {
    unsigned int val;
    memcpy(&val , &data[i], sizeof(float));
    val = ntohl(val);
    data[i] = *((float*)&val);
}
// Print received data
printf("Received data: ");
for (int i = 0; i < 12; i++) {
    printf("%.6f ", data[i]);
}
printf("\n");

}
// Function to close UDP socket
void close_udp_socket() {
closesocket(s);
WSACleanup();
}

头文件

#ifndef UDP_FUNC2_H
#define UDP_FUNC2_H
#include <winsock2.h>
#ifdef __cplusplus
extern "C" {
#endif
// Function prototypes
int init_udp_socket();
int create_udp_socket();
int bind_udp_socket(const char *ip_address, int port);
int set_socket_nonblocking();
void udp_read_continuous(float *data);
void close_udp_socket();
#ifdef __cplusplus
}
#endif
#endif // UDP_FUNC2_H

MATLAB脚本

clc;
clear;
if libisloaded('udpfunc2')
unloadlibrary('udpfunc2')
end
loadlibrary('udpfunc2.dll', 'udpfunc2.h');
% Define UDP parameters
ip_address = '127.0.0.1'; % Local IP address
localPort = 44444; % Example port number

% Initialize UDP socket
status = calllib('udpfunc2', 'init_udp_socket');
if status == 0
disp('UDP socket initialized successfully');
else
disp('Failed to initialize UDP socket');
return;
end
% Open UDP socket
status = calllib('udpfunc2', 'create_udp_socket');
if status == -1
disp('Failed to Open UDP Socket');
end
% Bind UDP Socket to Local Port and IP address
status = calllib('udpfunc2', 'bind_udp_socket', ip_address, localPort);
if status == 0
disp('UDP socket binded successfully');
else
disp('Failed to bind socket');
return;
end
% Set Socket to Non-Blocking
status = calllib('udpfunc2', 'set_socket_nonblocking');
if status == 0
disp('UDP socket set to Non-Blocking successfully');
else
disp('Failed to set socket to Non-Blocking');
return;
end
% Create a MATLAB struct to hold the 12 single values
dataPacket = zeros(1, 12, 'single');
% Read continuous UDP data
while true
calllib('udpfunc2', 'udp_read_continuous', dataPacket);
fprintf('%.6f\n', dataPacket(12));
end
% Close UDP socket
calllib('udpfunc2', 'close_udp_socket');
disp('UDP socket closed');
% Unload the DLL
unloadlibrary('udpfunc2');

问题原因

  1. MATLAB数组传递方式错误:MATLAB调用calllib时,直接传递数组会默认按值传递,即创建数组副本传给C函数。C函数修改的是副本内存,原MATLAB数组dataPacket不会被更新,因此MATLAB端始终读到初始的零值。
  2. 非阻塞Socket错误处理缺失:C代码中recvfrom在非阻塞模式下无数据时会返回SOCKET_ERROR,但代码未处理该情况,直接对清零后的缓冲区进行字节序转换并返回,导致MATLAB持续收到零值。

解决办法

1. 修改MATLAB传递方式为指针传递

使用libpointer创建指向MATLAB数组的指针,让C函数直接修改原数组内存:

clc;
clear;
if libisloaded('udpfunc2')
unloadlibrary('udpfunc2')
end
loadlibrary('udpfunc2.dll', 'udpfunc2.h');
% Define UDP parameters
ip_address = '127.0.0.1'; % Local IP address
localPort = 44444; % Example port number

% Initialize UDP socket
status = calllib('udpfunc2', 'init_udp_socket');
if status == 0
disp('UDP socket initialized successfully');
else
disp('Failed to initialize UDP socket');
return;
end
% Open UDP socket
status = calllib('udpfunc2', 'create_udp_socket');
if status == -1
disp('Failed to Open UDP Socket');
end
% Bind UDP Socket to Local Port and IP address
status = calllib('udpfunc2', 'bind_udp_socket', ip_address, localPort);
if status == 0
disp('UDP socket binded successfully');
else
disp('Failed to bind socket');
return;
end
% Set Socket to Non-Blocking
status = calllib('udpfunc2', 'set_socket_nonblocking');
if status == 0
disp('UDP socket set to Non-Blocking successfully');
else
disp('Failed to set socket to Non-Blocking');
return;
end
% Create array and corresponding pointer
dataPacket = zeros(1, 12, 'single');
p_data = libpointer('singlePtr', dataPacket);

% Read continuous UDP data
while true
    calllib('udpfunc2', 'udp_read_continuous', p_data);
    % Synchronize pointer value back to MATLAB array
    dataPacket = p_data.Value;
    fprintf('%.6f\n', dataPacket(12));
    % Add small delay to reduce CPU usage
    pause(0.01);
end
% Close UDP socket
calllib('udpfunc2', 'close_udp_socket');
disp('UDP socket closed');
% Unload the DLL
unloadlibrary('udpfunc2');

2. 完善C代码的非阻塞错误处理

在udp_read_continuous函数中,处理recvfrom的返回值,仅当成功接收完整数据时才进行字节序转换:

void udp_read_continuous(float *data) {
    struct sockaddr_in si_other;
    int slen = sizeof(si_other);
    int recv_len;
    // zero out the memory buffer
    memset(data,0,12 * sizeof(float));

    recv_len = recvfrom(s, (char *)data, BUFLEN, 0, (struct sockaddr *)&si_other, &slen);
    
    // Handle non-blocking socket no data case
    if (recv_len == SOCKET_ERROR) {
        int err = WSAGetLastError();
        if (err != WSAEWOULDBLOCK) {
            printf("recvfrom failed with error: %d\n", err);
        }
        // Return with zeroed buffer when no data
        return;
    }

    // Only process if complete data is received
    if (recv_len == BUFLEN) {
        // Convert data from big-endian to host byte order
        for (int i = 0; i < 12; i++) {
            unsigned int val;
            memcpy(&val , &data[i], sizeof(float));
            val = ntohl(val);
            data[i] = *((float*)&val);
        }
    } else {
        printf("Received incomplete data: %d bytes expected %d\n", recv_len, BUFLEN);
        return;
    }

    // Print received data
    printf("Received data: ");
    for (int i = 0; i < 12; i++) {
        printf("%.6f ", data[i]);
    }
    printf("\n");
}

3. 额外注意事项

  • 确保编译DLL的编译器与MATLAB位数一致(32位/64位),避免加载失败或调用异常。
  • 使用mex -setup配置MATLAB兼容的C编译器,确保loadlibrary能正确解析头文件。
  • 测试时可使用UDP工具(如NetAssist)向127.0.0.1:44444发送48字节的大端浮点数据,验证接收逻辑。

内容的提问来源于stack exchange,提问作者Tamim Akhtar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 03:42:03