Невозможно получить большой массив, используя сокеты в c - PullRequest
0 голосов
/ 24 июня 2018

Я отправляю целочисленный массив размера от одного малинового пи другому, используя POSIX-сокеты в C. Я пишу целочисленный массив размера 131072 от одного пи, возвращаемое значение из команды записи показывает, что все значения 131072 были записаны , ret = write(socket, &array, sizeof(array)) Использование одного и того же метода для приема ret = read(socket, &array, sizeof(array)) показывает, что все отправленные значения не были прочитаны, а число правильно прочитанных значений также не является постоянным, но варьируется от 10000 до 20000.

Я пытался использовать функцию чтения внутри цикла, где я читал целое число в каждой итерации цикла

for(int i =0; i<131072; i++){
ret = read(socket, &value, sizeof(value));
data[i] = value;}

Мне удалось получить все значения без ошибок и потерь.

Ответы [ 2 ]

0 голосов
/ 24 июня 2018

Возможно, вам понадобится код, подобный следующему:

multi-rw.h

#ifndef JLSS_ID_MULTI_RW_H
#define JLSS_ID_MULTI_RW_H

#include <sys/types.h>

extern ssize_t multi_read(int fd, char *buffer, size_t nbytes);
extern ssize_t multi_write(int fd, const char *buffer, size_t nbytes);

#endif

multi-rw.c

Немного прискорбно, что блок тестового кода должен предшествовать активным функциям, но это необходимо (и тестовый код необходим - по крайней мере, я считаю его чрезвычайно полезным и обнадеживающим). Я предполагаю, что это могло войти в отдельный заголовочный файл (multi-rw-test.h или около того), который был бы включен условно; было бы лучше для презентации на SO, но в противном случае это просто еще один файл, о котором нужно беспокоиться.

#include "multi-rw.h"
#include <unistd.h>

#ifdef TEST

#ifndef MAX_WRITE_SIZE
#define MAX_WRITE_SIZE 64
#endif
#ifndef MAX_READ_SIZE
#define MAX_READ_SIZE 64
#endif

static inline size_t min_size(size_t x, size_t y) { return (x < y) ? x : y; }

static inline ssize_t pseudo_read(int fd, char *buffer, size_t nbytes)
{
    return read(fd, buffer, min_size(MAX_READ_SIZE, nbytes));
}

static inline ssize_t pseudo_write(int fd, const char *buffer, size_t nbytes)
{
    return write(fd, buffer, min_size(MAX_READ_SIZE, nbytes));
}

#undef read
#undef write
#define read(fd, buffer, nbytes) pseudo_read(fd, buffer, nbytes)
#define write(fd, buffer, nbytes) pseudo_write(fd, buffer, nbytes)

#endif

ssize_t multi_read(int fd, char *buffer, size_t nbytes)
{
    ssize_t nb = 0;
    size_t nleft = nbytes;
    ssize_t tbytes = 0;
    while (nleft > 0 && (nb = read(fd, buffer, nleft)) > 0)
    {
        tbytes += nb;
        buffer += nb;
        nleft  -= nb;
    }
    if (tbytes == 0)
        tbytes = nb;
    return tbytes;
}

ssize_t multi_write(int fd, const char *buffer, size_t nbytes)
{
    ssize_t nb = 0;
    size_t nleft = nbytes;
    ssize_t tbytes = 0;
    while (nleft > 0 && (nb = write(fd, buffer, nleft)) > 0)
    {
        tbytes += nb;
        buffer += nb;
        nleft  -= nb;
    }
    if (tbytes == 0)
        tbytes = nb;
    return tbytes;
}

#ifdef TEST

#include "stderr.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    if (argc != 0)
        err_setarg0(argv[0]);

    char buffer[4096];
    ssize_t ibytes;

    while ((ibytes = multi_read(0, buffer, sizeof(buffer))) > 0)
    {
        ssize_t obytes;
        if ((obytes = multi_write(1, buffer, ibytes)) != ibytes)
            err_syserr("failed to write %lld bytes - only wrote %lld bytes\n",
                       (long long)ibytes, (long long)obytes);
    }
    if (ibytes < 0)
        err_syserr("I/O error reading standard input: ");

    return 0;
}
#endif

Испытательный жгут позволяет проверять чтение кода со стандартного ввода и запись на стандартный вывод. Вы можете настроить объем данных, читаемых с помощью (например) параметров командной строки компиляции -DMAX_WRITE_SIZE=132 и -DMAX_READ_SIZE=103. Вам необходимо протестировать его на файлах, меньших (а) 4096 байт и (б) меньших, чем максимальные размеры чтения и записи, а также на файлах, превышающих 4096 байт. Если вы достаточно мотивированы, вы можете обновить функции pseudo_read() и pseudo_write(), чтобы генерировать ошибки квази-случайным образом, чтобы увидеть, как код обрабатывает такие ошибки.

0 голосов
/ 24 июня 2018

Базовый протокол (возможно, TCP и IP) разбивает данные на пакеты, которые могут поступать в виде отдельных блоков данных в принимающем приложении.Теоретически, read() может получать каждый байт индивидуально (т.е. возвращать 1 каждый раз при вызове 2000 раз).Ваше приложение должно уметь работать с этим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...