Проблемы со связью через сокет между Windows и Linux - PullRequest
0 голосов
/ 04 февраля 2019

Я пытаюсь связаться через сокет между Windows (клиент) и Linux (сервер).Я могу начать общение, но когда я отправляю данные, возникают проблемы.Основная проблема заключается в том, что я пытаюсь отправить 2 двойных данных и 1 длинный, но когда я читаю их на сервере (Linux), я не могу прочитать правильное значение.Если я отправлю, например, double1 = 1.5, я получу 0.0000 на сервере.Затем, если я отправляю double1 = 550.0, я получаю на сервере -12382718421 ... (мусор)

Я пытался использовать htonl, ntohl и т. Д. Это не работает, я пытался изменить порядок байтовкадр, который я отправляю с клиента, то есть, посылаю B0 ... B7 вместо B7 ... B0 ... Это не работает.Я искал информацию об этом, но ничего не могу найти, кроме того, что возможна связь через сокет между различными операционными системами, поэтому я знаю, что есть решение.

Мои вопросы:

1 - htonl и nthol работают только с целыми числами?Могу ли я использовать эти преобразования для данных с плавающей запятой?

2 - Каков порядок байтов кадра в Linux и Windows?

3 - Я знаю, что функция sendto () возвращает числобайты, которые отправляются.То, что я посылаю, это 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes.Но функция возвращает 24 байт, как это может быть?Это из-за заголовков протокола UDP или это дополнительная информация, которая включает в себя Windows?

Спасибо всем.

PD1: Программирование сокетов правильно.

PD2: МеждуLinux-Linux У меня нет проблем, и я могу правильно отправлять данные.

Ответы [ 2 ]

0 голосов
/ 04 февраля 2019

htonl и nthol работают только с целыми числами?Могу ли я использовать эти преобразования для данных с плавающей запятой

Для управления с плавающей запятой вы можете, например, использовать объединение для преобразования с плавающей запятой вuint32_t и наоборот, или используйте приведение указателя float к указателю uint32_t и наоборот, конечно же, не разыгрывайте float до uint32_t и наоборот

Но вы, кажется, работаете double вместо float , в этом случае вам нужно использовать htobe64 / htole64/ be64toh / le64toh (endian.h), если они не определены в Windows, решите порядок или байты в вашем пакете и определите преобразование самостоятельно

Каков порядок байтовфрейм в Linux и Windows

Порядок зависит только от процессора, а не от ОС

Я знаю, что функция sendto () возвращает количество байтовкоторые отправляются.То, что я посылаю, это 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes.Но функция возвращает 24 байт, как это может быть?Это происходит из-за заголовков протокола UDP или это дополнительная информация, которая включает в себя Windows?

У вас есть доступ только к полезной нагрузке , все заголовки / нижние колонтитулы / и т. Д. Скрыты для вас

Возможно, вы отправляете struct , а не создаете пакет для отправки, в этом случае компиляторы просто не следуют одному и тому же заполнению, или размер long равен 32b на одном и 64b надругой?

Не отправлять struct , копировать числа в векторе байтов, управляющих порядком байтов, и извлекать их таким же образом


ДляНапример, если все выполняется вручную, unsigned long считывается / записывается на 8 байтах, чтобы обеспечить совместимость, даже если на одном хосте 64b, а на другом меньше:

#include <string.h>

void encDec32(char * a, char * b)
{
  const int e = 1;

  if (*((char *) &e)) {
    memcpy(a, b, 4);
  }
  else {
    a[0] = b[3];
    a[1] = b[2];
    a[2] = b[1];
    a[3] = b[0];
  }
}

void encDec64(char * a, char * b)
{
  const int e = 1;

  if (*((char *) &e)) {
    memcpy(a, b, 8);
  }
  else {
    a[0] = b[7];
    a[1] = b[6];
    a[2] = b[5];
    a[3] = b[4];
    a[4] = b[3];
    a[5] = b[2];
    a[6] = b[1];
    a[7] = b[0];
  }
}

void encodeU32(char ** buffer, uint32_t v)
{
  encDec32(*buffer, (char *) &v);
  *buffer += 4;
}

void encodeU64(char ** buffer, uint64_t v)
{
  encDec64(*buffer, (char *) &v);
  *buffer += 8;
}

void encodeFloat(char ** buffer, float v)
{
  encDec32(*buffer, (char *) &v);
  *buffer += 4;
}

void encodeDouble(char ** buffer, double v)
{
  encDec64(*buffer, (char *) &v);
  *buffer += 8;
}

void encodeUlong(char ** buffer, unsigned long v)
{
  /* force on 8 bytes to be compatible with CPU 32 and 64 */
  encodeU64(buffer, (uint64_t) v);
}

uint32_t decodeU32(char ** buffer)
{
  uint32_t v;

  encDec32((char *) &v, *buffer);
  *buffer += 4;
  return v;
}

uint64_t decodeU64(char ** buffer)
{
  uint64_t v;

  encDec64((char *) &v, *buffer);
  *buffer += 8;
  return v;
}

float decodeFloat(char ** buffer)
{
  float v;

  encDec32((char *) &v, *buffer);
  *buffer += 4;
  return v;
}

float decodeDouble(char ** buffer)
{
  double v;

  encDec64((char *) &v, *buffer);
  *buffer += 8;
  return v;
}

unsigned long decodeUlong(char ** buffer)
{
  /* force on 8 bytes to be compatible with CPU 32 and 64 */
  return (unsigned long) decodeU64(buffer);
}

/* for a struct */

typedef struct S {
  unsigned long u; /* may be on 32 or 64 and not the same size on Linuw and Windows */
  double d1;
  double d2;
} S;

/* b is the block to send, it must be enough long */
/* return the number of bytes to send in a block through UDP */
size_t encodeS(char * b, S * s)
{
  char * b0 = b;

  encodeUlong(&b, s->u);
  encodeDouble(&b, s->d1);
  encodeDouble(&b, s->d2);

  return b - b0;
}

/* b is the block read through UDP */
void decodeS(char * b, S * s)
{
  s->u = decodeUlong(&b);
  s->d1 = decodeDouble(&b);
  s->d2 = decodeDouble(&b);
}
0 голосов
/ 04 февраля 2019

1 - htonl и ntohl работают только с целыми числами?Могу ли я использовать эти преобразования для данных с плавающей запятой?

Эти функции определены только для целых чисел.Вам нужно знать формат, в котором каждая платформа хранит двойные числа (включая порядковый номер), чтобы решить, нужно ли вам переупорядочивать байты или выполнять какое-либо другое преобразование.

2 - Каков порядок байтоврамка в linux и windows?

Вопрос не имеет смысла.Вы решили, что поместить в этот пакет, поэтому порядок следования байтов будет таким, какой вы отправили.

Традиционно форматы проводов часто бывают с прямым порядком байтов, но многие современные форматы имеют порядок байтов, потому что большинство пиров будутиспользовать x86.

В вашем конкретном случае тот факт, что вы получаете в Linux, менее важен, чем архитектура, в которой работает Linux.Вы не упомянули об этом, но предполагая, что x86_64, порядковый номер и формат double, вероятно, такие же, как и для вашего отправляющего кода.Вам, вероятно, следует использовать типы фиксированного размера из <stdint.h>, например uint64_t вместо unsigned long (при условии, что это именно то, что вы хотели).Такие типы, как long, могут быть разных размеров в разных ABI даже на одной платформе.

3 - я знаю, что функция sendto () возвращает количество отправляемых байтов.То, что я посылаю, это 20Bytes -> (2 * 8Bytes (double) + 1 * 4Bytes (ulong)) = 20Bytes.Но функция возвращает 24 байт, как это может быть?Это связано с заголовками протокола UDP или это дополнительная информация, которая включает в себя Windows?

Показать ваш код.Возвращаемое значение из sendto не должно быть больше, чем аргумент длины, который вы передали, поэтому, возможно, это значение не то, что вы думали.

Дополнительная длина определенно не является заголовками IP или UDP, которыев любом случае длиннее 4 байтов.


Я пытался использовать htonl, ntohl и т. д. Это не работает

Хватит вращаться, пытаясь использовать различные преобразования вНадеюсь, что все работает.

Напечатайте шестнадцатеричный дамп вашего буфера перед отправкой.Распечатайте шестнадцатеричный дамп вашего буфера после получения.Заполните структуру, которую вы ожидали увидеть в приемнике и шестнадцатеричный дамп , что , чтобы вы могли увидеть разницу.

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