Я посылаю структуру C через сокет, но не могу понять это правильно, всегда пропускаю несколько байтов - PullRequest
1 голос
/ 27 декабря 2011

Обновление: я добавляю while, чтобы получить оставшиеся данные, проблема решена.спасибо, ребята.

while(res != rcvread->size + 4) {/* do not get full data */
    tmp = recv(connfd, (void *)rcvread + res, rcvread->size + 4 - res, 0);
    if(tmp == -1)
        printf("error:%s\n",(char *)strerror(errno));
    res+=tmp;
}

Я хочу отправить структуру mfsio через сокет, возвращаемое значение write равно 37772, но когда я получил его из другой программы, возвращаемое значение read равно 32768, это действительно странно.

Определение этой структуры здесь

struct mfsio{
    size_t size;
    char buf[];
};

Код отправки здесь

struct mfsio *sndread;
sndread = malloc(sizeof(struct mfsio) + rcvcmd->size);
res = pread(fd, &(sndread->buf), rcvcmd->size, rcvcmd->offset);
sndread->size = res;
res = write(connfd, sndread, sizeof(struct mfsio) + res);

Код получения здесь

struct mfsio *rcvread;
rcvread = malloc(sizeof(struct mfsio) + size);
res = 0;    
res = read(connfd, rcvread, sizeof(struct mfsio) + size);

size равно rcvcmd->size, а рез pread - 32678, рез write - 32772. но рез read - 32678.

Как такое могло случиться?Я что-то здесь не так делаю?

Если нет ввода от write, функция read будет просто ожидать некоторые данные и просто зависать там

Если я используюцикл, чтобы избежать такой проблемы, как я могу, наконец, получить всю структуру данных, я имею в виду, если я буду читать цикл, я получу оставшиеся байты из сокета, но как я могу объединить эти клипы, которые я получу?

Ответы [ 4 ]

8 голосов
/ 27 декабря 2011

Вам необходимо выполнять чтение и запись в цикле, пока все ожидаемые данные не будут прочитаны / записаны.Для чтения вы должны читать, пока он не вернет 0, указывая, что больше ничего не доступно.Или -1, указывающий на ошибку.

Ваша последняя проблема заключается в том, что вы используете арифметику указателя со своим указателем структуры:

tmp = recv(connfd, rcvread + res, rcvread->size + 4 - res, 0);

В C, когда вы выполняете арифметику указателя, вы не работаетебайт, но вы работаете с размером объекта (например, rvcread).Вы должны определить char *, который является байтовым местоположением, в которое вы будете читать, а затем обновить его, когда вы читаете данные.

0 голосов
/ 02 января 2012

Флаг MSG_WAITALL на recv() также может представлять интерес, так как он в основном делает для вас целое

 while (!allDataReceived) {
   receiveMoreData();
 }

.

Однако другие ответы намекают вамто, что вам следует отправить заголовок с надписью «это количество байтов» - это то, что вы тоже должны слушать.

0 голосов
/ 27 декабря 2011

Ответ Фрэнсиса Аптона кажется правильным, вам, безусловно, следует следовать его совету.
Но у меня есть другое предположение, может быть, это проблема.
Вы не показываете, как вы получаете значение размера в приемнике. Разумный способ сделать это - прочитать 4 байта из сокета в размер. Таким образом, если вы это сделали, вы уже прочитали 4 байта и получите меньше на 4 байта при следующем чтении.

0 голосов
/ 27 декабря 2011

read и write работают с байтовыми потоками. Нет никакой гарантии, что read прочитает столько байтов, сколько пишет write. Либо используйте sendmsg, либо поместите в поток размеры записей или разделители записей.

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