Matlab中的客户端如何将二进制数据发送到C中的服务器?

Mas*_*oud 5 c matlab tcp

我想将数据从用Matlab编写的客户端发送到用C编写的服务器。在服务器中读取时,并不是一次读取操作中接收到所有数据,而是分为两次连续读取。

Matlab 代码包含 TCP 服务器的代码,该服务器接收一些数据,然后进行一些处理,然后作为客户端通过 TCP 套接字将处理的输出写入(发送)到 C 中的服务器。

这是用 Matlab 编写的客户端代码。

% A TCP server object defined for getting raw data and processing
% it. The object is called 'TCPServer'. It is not related to the 
% problem. 

% TCP client for sending the data to the C server
TCPClient = tcpip('192.168.1.2', 8080, 'NetworkRole', 'client');
set(TCPClient,'OutputBufferSize', 1464); 
% 1464 is total number of bytes of the struct to be sent
% to the C server.

set(TCPClient,'Timeout', 10);
fopen(TCPClient);

 while (1)
     while(1)       % Waits for incoming CSI data
         nBytes = get(TCPServer,'BytesAvailable');
         if nBytes >= bufferLen
             disp('Data received');
             break;
         end
     end

     data = fread(TCPServer,nBytes,'uint8');
     flushinput(TCPServer);

     % Does some processing and generate 'spec' and 'doas'
     % arrays to be sent to the C server

     message = [typecast(spec, 'uint8') typecast(doas, 'uint8')];
     fwrite(TCPClient, message); 
 end
Run Code Online (Sandbox Code Playgroud)

下面是用 C 编写的代码,用于在 Matlab 中服务器接收来自客户端的数据。

#define SA struct sockaddr

struct doa_struct {
    double spec[181], doa[2];
};

// Function that reads received data
void func(int sockfd) 
{ 
    struct doa_struct *doa_data;
    unsigned char buff[1464];
    int num_bytes;
    // infinite loop receiving data
    for (;;) { 
        bzero(buff, 1464); 

        // read the data from client and copy it in buffer 
        num_bytes = read(sockfd, buff, 1464);
        // Get the buffer which contains the client contents 
        doa_data = (struct doa_struct *) buff; 
        printf("doa: %f\t%f\t%d\n", doa_data->doa[0], doa_data->doa[1], num_bytes);
    }
} 

// Driver function 
int main()
{ 
    int sockfd, connfd, len;
    struct sockaddr_in servaddr, cli; 

    // socket create and verification
    sockfd = socket(AF_INET, SOCK_STREAM, 0); 
    if (sockfd == -1) { 
        printf("socket creation failed...\n"); 
        exit(0); 
    } 
    else
        printf("Socket successfully created..\n"); 
    bzero(&servaddr, sizeof(servaddr)); 

    // assign IP, PORT 
    servaddr.sin_family = AF_INET; 
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(8080); 

    // Binding newly created socket to given IP and verification
    if ((bind(sockfd, (SA*)&servaddr, sizeof(servaddr))) != 0) {
        printf("socket bind failed...\n");
        exit(0);
    }
    else
        printf("Socket successfully binded..\n");

    // Now server is ready to listen and verification
    if ((listen(sockfd, 5)) != 0) {
        printf("Listen failed...\n");
        exit(0);
    }
    else
        printf("Server listening..\n");
    len = sizeof(cli);

    // Accept the data packet from client and verification
    connfd = accept(sockfd, (SA*)&cli, &len);
    if (connfd < 0) {
        printf("server acccept failed...\n");
        exit(0); 
    } 
    else
        printf("server acccept the client...\n");

    // Function for chatting between client and server
    func(connfd);

    // After chatting close the socket
    close(sockfd); 
} 
Run Code Online (Sandbox Code Playgroud)

我在服务器上收到以下结果。

doa: 0.000000   0.000000    1408
doa: 0.000000   0.000000    56
Run Code Online (Sandbox Code Playgroud)

打印的每一行都有三个值。前两个是接收到的数据,不应为零。read()最后一个数字是服务器中函数接收的字节数。服务器在两行(两次read()操作)中接收到的字节数1464之和是客户端在一次操作中发送的字节数fwrite()

正确的输出将是如下一行:

doa: 25.000000  45.000000   1464
Run Code Online (Sandbox Code Playgroud)

通过字节传输接收到的两个非零数据值1464。我还检查了客户端代码。客户端1464通过Matlab中的操作发送(写入)字节fwrite()

小智 4

read() 调用仅返回您期望的一些数据是完全正常的。发生这种情况是因为在较低级别,网络堆栈将整个数据流分解为多个固定大小的数据包,以便通过线路传输。从 read(2) 手册页中:

返回值...如果该数字小于请求的字节数,则不是错误;例如,这可能会发生,因为现在实际可用的字节数较少(可能是因为我们接近文件结尾,或者因为我们正在从管道或终端读取),或者因为 read() 被信号。

接收网络数据时,您需要不断调用 read() 直到收到预期的字节数。例如,这样的东西(未经测试的代码):

void func(int sockfd) 
{ 
    struct doa_struct *doa_data;
    int expected_bytes = 1464;
    unsigned char buff[expected_bytes];
    int num_bytes;

    // Read a message
    bzero(buff, 1464);
    int bytes_read = 0;
    while (bytes_read < expected_bytes) {

        // read data into buff until we've read all the expected bytes
        // NOTE: if the Matlab side sends a malformed message, this could
        // hang in this loop forever...for real-world use, you'd need to
        // account for those types of scenarios.
        num_bytes = read(sockfd, buff + bytes_read, expected_bytes - bytes_read);
        if (num_bytes <= 0) {
            // handle error cases...
            return;
        }
        bytes_read += num_bytes;
    }

    // Get the buffer which contains the client contents 
    doa_data = (struct doa_struct *) buff; 
    printf("doa: %f\t%f\t%d\n", doa_data->doa[0], doa_data->doa[1], num_bytes);
}
Run Code Online (Sandbox Code Playgroud)

至于为什么你的输出打印 0 而不是预期值:这可能是因为你的 printf 格式说明符。您的编译器可能需要“%lf”来打印双精度数,而不是“%f”。传统上,双精度数需要“%lf”,双精度数是 64 位值而不是 32 位浮点值。然而,C99 和更高版本的编译器可能会模糊这条界线 - 请参阅此相关的堆栈溢出问题