Как клиент в Matlab может отправлять двоичные данные на сервер в C? - PullRequest
0 голосов
/ 20 декабря 2018

Я хочу отправить данные от клиента, написанного на 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

Вот код, написанный на 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); 
} 

Получаю следующий результат на сервере.

doa: 0.000000   0.000000    1408
doa: 0.000000   0.000000    56

Каждая напечатанная строка имеет три значения.Первые два - полученные данные, которые не должны быть равны нулю.Последнее число - это количество байтов, полученных функцией read() на сервере.Сумма байтов, полученных сервером в двух строках (две операции read()), равна 1464, то есть числу байтов, отправленных клиентом за одну операцию fwrite().

Правильный вывод будет одной строкой, подобной следующей:

doa: 25.000000  45.000000   1464

Два ненулевых значения данных, полученных при передаче 1464 байтов.Я также проверил код клиента.Клиент отправляет (записывает) 1464 байт с помощью операции fwrite() в Matlab.

1 Ответ

0 голосов
/ 21 декабря 2018

Это нормально для вызова 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);
}

Что касается того, почему ваши выходные данные печатают 0 вместо ожидаемых значений: это может быть из-за вашего спецификатора формата printf.Ваш компилятор может потребовать "% lf" для печати значений типа double, а не "% f".Традиционно, "% lf" требовался для двойных чисел, которые являются 64-разрядными значениями, а не 32-разрядными значениями с плавающей запятой.Однако компиляторы C99 и более поздние могут размыть эту строку - см. этот связанный вопрос переполнения стека .

...