С++ массивы отправки winsock

Я пытаюсь отправить массивы по сети с помощью winsock2. Я читал, что Microsoft отключила отправку необработанных указателей, но вы все равно можете отправлять неотредактированные двоичные данные, приведя указатель к char*:

send(rsock, (char*)&counter, len, 0);

Однако проблема заключается в том, чтобы поместить данные обратно в массив, когда они достигают клиента. здесь pass — это двоичные данные. Вот как я делаю целые, логические и двойные числа.

    recv(sock, pass, sizeof(int), 0);
    refresh =  (int((void*)&pass));
    recv(sock, pass, sizeof(bool[4800][254]), 0);
    **key = (bool)&pass;
    recv(sock, pass, sizeof(double[4800][254]), 0);
    **mil = (double)&pass;

Целые числа не являются массивами, а bool и double хранятся в двумерных массивах. Теперь компилятор говорит, что этот код работает для int и bool, но для двойных он говорит: «'приведение типа': невозможно преобразовать из 'char **' в 'двойное'», «недопустимое преобразование типа», хотя я пытаюсь поместить необработанный данные в нем. Я сделал что-то не так? Есть ли другой обходной путь для отправки массивов? Заранее спасибо.

РЕДАКТИРОВАТЬ: кроме того, я до сих пор не пробовал код с другим ПК, поэтому я очень сомневаюсь, что преобразование для целых и логических значений выполнено правильно.


person Alex    schedule 07.08.2014    source источник
comment
Где, черт возьми, вы «читали, что Microsoft отключила отправку необработанных указателей»? Вы можете отправить все, что угодно. Другой вопрос, значит ли это что-нибудь для получателя.   -  person user207421    schedule 07.08.2014
comment
Я не помню, по какому именно вопросу я это читал, но это было о переполнении стека - и, кстати, send(rsock, &counter, len, 0); с двойным не компилируется , я должен использовать send(rsock, (char)&counter, len, 0);*. После символа также есть символ умножения, но формат веб-сайта его не показывает.   -  person Alex    schedule 07.08.2014
comment
Вы невнимательно прочитали или забыли. На всем сайте нет совпадений для «Microsoft отключила отправку необработанных указателей», кроме этого вопроса. Ваша проблема связана с ошибками компиляции, а не с тем, что «Microsoft отключила отправку необработанных указателей».   -  person user207421    schedule 07.08.2014
comment
Хорошо, учитывая, что я неправильно помню, у вас есть какие-нибудь подсказки для проблемы с отправкой или проблемы с приведением? Спасибо.   -  person Alex    schedule 07.08.2014
comment
Проблем с отправкой нет. Есть проблема приведения, которая представляет собой просто программирование на C, и есть проблема с вашим кодом recv(): вы предполагаете, что он заполняет буфер. Это не предусмотрено контрактом. Вам нужно сохранить результат recv() в переменную и проверить его на -1, проверить на 0 и в противном случае использовать его как количество полученных байтов; если этого достаточно для следующего фрагмента кода, ОК, иначе цикл.   -  person user207421    schedule 07.08.2014


Ответы (2)


Microsoft ничего не запрещала отправлять. Дело в том, что отправка указателя будет просто бесполезна удаленному пиру. Указатель — это просто адрес памяти, и бесполезно знать адрес, если информации там нет.

Проблема, с которой вы, вероятно, сталкиваетесь, заключается в том, что этот массив слишком велик для буфера отправки, который по умолчанию может содержать только 64 КБ.

Обратите внимание на возвращаемые значения send() и recv(), чтобы узнать, сколько данных вы фактически прочитали/отправили в этой транзакции. Это не всегда будет тот размер, который вы указали функции, поскольку он часто разбивается на части размером менее 4 КБ. Вам придется управлять передачей этой информации по частям, чтобы заполнить весь ваш массив.

person Havenard    schedule 07.08.2014
comment
Вы правы, но проблема, о которой я говорю в этом вопросе, заключается не в том, что указатель не достигает клиента, я искал способ вернуть указатель обратно в массив, и увидел, что тот, который я пробовал, работает для bools, но не для двойников по неизвестной мне причине. - person Alex; 07.08.2014
comment
@Alex Проблема, которую вы видите, заключается в том, что вы считаете, что можете превращать указатели в данные. Это не так. Что вы делаете, так это отправляете данные (не указатель) через сокет, а затем получатель должен взять эти данные и воссоздать структуру(ы) данных на этой стороне. Представьте, что вы пытаетесь сохранить данные в файл, а затем в другой программе прочитаете файл и восстановите данные. Как бы Вы это сделали? Это тот же принцип. - person PaulMcKenzie; 07.08.2014

Я сделал что-то не так?

Что ж...

  • по умолчанию send и recv не гарантируют возврата только после отправки или получения всех предоставленного вами буфера; они могут вернуться, как только они поставят в очередь немного больше данных для отправки или после получения немного больше данных, которые вы, возможно, сможете обработать... предоставленный размер буфера - это просто верхний предел вашего запроса, а не минимум. Если вы хотите гарантировать, что recv не вернется до тех пор, пока не будет заполнен полный буфер, добавьте флаг MSG_WAITALL в качестве последнего параметра. Для send вы должны циклически отправлять дальнейшие части вашего выходного буфера.

  • проверьте свои коды возврата... send и recv сообщают вам об ошибках и имеют довольно маленькие числа, которые дают вам подсказки относительно причины и решения

  • "компилятор говорит, что этот код работает" - нет, это не так... он говорит, что ваш код запрашивает что-то, что он подготовлен для компиляции, полный приведений, которые он не предназначен для проверки, большинство из которых будут аварийно завершены во время выполнения

Тогда вот это:

recv(sock, pass, sizeof(int), 0);
refresh =  (int((void*)&pass));
recv(sock, pass, sizeof(bool[4800][254]), 0);
**key = (bool)&pass;
recv(sock, pass, sizeof(double[4800][254]), 0);
**mil = (double)&pass;

Я даже не собираюсь начинать говорить, что со всем этим не так... давайте просто поговорим о том, что может работать (может обсуждаться ниже):

template <typename T>
void get(int sock, T& t)
{
    if (recv(sock, (char*)&t, sizeof t, MSG_WAITALL) != sizeof t)
        throw std::runtime_error("error while reading data from socket");
}

int refresh;
get(refresh);

bool key[4800][254];
get(key);

double mil[4800][254];
get(mil);

Если ваши отправляющие и принимающие системы, компиляторы, флаги компилятора, исполняемые файлы и т. д. каким-либо образом различаются, это может не работать в любом случае:

  • до тех пор, пока компиляторы С++ 03 не должны были использовать какой-либо конкретный тип для хранения bool, поэтому кто знает, совпадут ли ваша отправляющая и принимающая стороны

  • системы с прямым и обратным порядком байтов имеют разный порядок байтов, который может нарушить наивные двоичные передачи, подобные этому

  • размер int может отличаться

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

person Tony Delroy    schedule 07.08.2014
comment
Я понимаю ваше разочарование, но это не должен был быть окончательный код, я бы проверил возврат, как только приведения сработали бы. В любом случае спасибо, буду следовать вашим советам. Ой. И вы уверены, что библиотека сериализации boost будет работать с сокетом? - person Alex; 07.08.2014
comment
@Alex: Пожалуйста. Повысьте сериализацию и сокеты - в существующих вопросах есть несколько ответов/ссылок - например. здесь. Ваше здоровье. - person Tony Delroy; 08.08.2014