Форум программистов, компьютерный форум, киберфорум
C/С++ под Linux
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.75/16: Рейтинг темы: голосов - 16, средняя оценка - 4.75
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10

В массив записать разнородные данные для передачи этого пакета по сети

25.04.2011, 09:30. Показов 3340. Ответов 16
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.
Стоит задача следующего плана.. Есть некий массив, который будет передан по сети через сокет. В этот массив необходимо записать разнородные данные, а именно 1 значение u_int8_t и 2 значения int64_t. Листинг моей попытки реализации (без передачи через сокет):
C
1
2
3
4
5
6
7
8
9
10
// includes..
u_int8_t * newMem = (u_int8_t *)malloc( 17 );
 
u_int8_t * code = 0;
int64_t * count1 = 1024*1024*10;
int64_t * count2 = 1024*1024*10;
 
newMem[0] = code;
((int64_t *)newMem)[1] = count1;
((int64_t *)newMem)[9] = count2;
Так как для передачи через сокет необходим однобайтовый тип, newMem я объявил как u_int8_t. А вот как запихнуть в него 8ми-байтные integer - до меня не доходит. Подскажите, пожалуйста, как реализовать, если есть идеи.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
25.04.2011, 09:30
Ответы с готовыми решениями:

Замер времени передачи пакета по сети
Добрый вечер. Подскажите, пожалуйста,как можно измерить время выполнения запроса.С помощью сокетов передаётся сообщение серверу.С сервера...

Формирование пакета данных для передачи по UART
...доброго времени суток, уважаемые форумчане! Возник вопрос: имеется ли в CodeVisionAVR 1.25 для ATmega8 тип данных эквмвалентный...

Отправка пакета URB для ИЗОХРОННОЙ передачи в коде драйвера
Приветствую всех кодокопателей! Ниже приведен код отправки URB для драйвера шины USBD.sys . Вся загвоздка в том , что не хрена не...

16
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
25.04.2011, 09:42
Цитата Сообщение от olzan Посмотреть сообщение
Так как для передачи через сокет необходим однобайтовый тип
Это не верно.
Единственное о чем вам стоит волноваться при передаче таких структур по сети это порядок байт.
0
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10
25.04.2011, 09:50  [ТС]
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Это не верно.
Единственное о чем вам стоит волноваться при передаче таких структур по сети это порядок байт.
М. Хорошо. Попробую уточнить - как мне передать 3 переменные разного типа одним махом? Этот блок (1+8+8 байт) может повториться достаточно большое количество раз, и каждую переменную передавать как минимум неудобно, но еще и затратно.
Хотелось бы все-таки записать все в один массив. Вопрос в том - как?
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
25.04.2011, 10:02
C
1
2
3
4
5
6
7
8
struct foo {
    int a;
    float b;
    double c;
};
 
struct foo bar[10];
send(, bar, sizeof(bar), 0);
0
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10
25.04.2011, 11:25  [ТС]
Похоже, Ваш вариант не сработает - структура программы не позволяет. Либо я неправ ) Дело в том, что коду в первом посте предшествует примерно следующее:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
    struct packet
    {
        u_int8_t version;
        u_int8_t command;
        u_int16_t length;
        u_int32_t error;
        void * data;
    };
 
        struct packet pack;
 
        memset(newMem, 0, 5+17*pack->length);
        memcpy(newMem, pack->data, 5);
Получается, мне нужно просто дописать к имеющимся 5 байтам информации несколько блоков по 17 байт, указанных выше. Если использовать дополнительную структуру, будет как-то так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    struct rcv_traf
    {
        u_int8_t kind;
        int64_t in;
        int64_t out;
    };
 
        struct rcv_traf traf[pack->length];
        for (int i=0; i<pack->length; i++)
        {
                traf[i].kind = code;
                traf[i].in = count1;
                traf[i].out = count2;
        }
        memcpy(&newMem[size_ipcount], &traf, sizeof(traf));
В конце процедуры идет присвоение pack->data = newMem; и структура передается в сокет.

Т.е. задача такова: к имеющимся данным в массиве (добавленным через memcpy) дописать несколько значений другого типа.
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
25.04.2011, 11:55
Цитата Сообщение от olzan Посмотреть сообщение
Т.е. задача такова: к имеющимся данным в массиве (добавленным через memcpy) дописать несколько значений другого типа.
Я правильно понимаю, что конечная цель сформировать и отправить структуру произвольной длинны с фиксированным форматом заголовка?
0
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10
25.04.2011, 12:01  [ТС]
Цитата Сообщение от g_u_e_s_t Посмотреть сообщение
Я правильно понимаю, что конечная цель сформировать и отправить структуру произвольной длинны с фиксированным форматом заголовка?
Да, все верно. Длина собственно данных в структуре не определена заранее, и данные в ней могут быть разнородными. Поэтому пытаюсь выяснить достаточно прямой способ для их заполнения, чтобы использовать в аналогичных процедурах, но с другими выходными данными.
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
25.04.2011, 12:13
Проще всего ваш void *data заменить на char data[1]
C
1
2
3
4
5
6
7
8
struct some_data {...} *some_data;
 
struct packet some_packet = malloc(sizeof(struct packet) + sizeof(struct some_data) - 1);
/* кастуем раз */
some_data = (struct some_data)&some_packet->data;
some_data->foo = 123;
memcpy(some_data->bar, "bar", 3);
ну и тд
0
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10
25.04.2011, 13:42  [ТС]
Пример интересный.. Не затруднит ли Вас объяснить, как он работает? Я в чужом коде на Си довольно плохо разбираюсь, а делать тупой копипаст - последнее дело, как известно.
0
1259 / 650 / 44
Регистрация: 06.02.2011
Сообщений: 1,654
25.04.2011, 14:28
Вроде же все примитивно.
Вы хотите передавать такое:
заголовок
данные
Вот ваша структура являющаяся заголовком пакета данных некоего протокола:
C
1
2
3
4
5
6
7
8
    struct packet
    {
        u_int8_t version;
        u_int8_t command;
        u_int16_t length;
        u_int32_t error;
        void * data;
    };
Посмотрим на поле data. Очевидно вы хотите использовать его как указатель на начало собственно данных. Причем это не обычный в Си смысле указатель, а указатель от конца/начала/ну или любого оговоренного места заголовка пакета. Т.е. получается что это константа.
Я же вам предложил отказаться от этой избыточной константы.
char data[1]; был использован мной просто для удобства и наглядности адресации. На самом деле можно обойтись и без него, адресуясь по полю &error + sizeof(error)
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
26.04.2011, 05:55
Цитата Сообщение от olzan
Хотелось бы все-таки записать все в один массив. Вопрос в том - как?
вопрос в том, как это потом доставать обратно
wiki. сериализация
0
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10
26.04.2011, 14:56  [ТС]
Цитата Сообщение от accept Посмотреть сообщение
вопрос в том, как это потом доставать обратно
wiki. сериализация
Достает данные приложение-клиент на delphi (я пишу сервер на Си). С точки зрения меня, как разработчика, как клиент будет доставать данные - не важно. Важно, чтобы и сервер, и клиент общались по стандартизированному протоколу.

В общем-то, решил проблему. Моя ошибка заключалась в том, что я указывал индекс не так, как надо. Поясню:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 17 байт массива из элементов по 1 байт
u_int8_t * newMem = (u_int8_t *)malloc( 17 );
 
// 2 переменные, по 8 байт каждая
int64_t * count1 = 1024*1024*10;
int64_t * count2 = 1024*1024*10;
 
// заносим 1й элемент - все в порядке, т.к. типы данных одинаковые
u_int8_t * code = 0;
newMem[0] = code;
 
/* обращение к 1 и 9 элементам массива, состоящего из элементов по 8 байт!
   т.е. - ошибка */
((int64_t *)newMem)[1] = count1;
((int64_t *)newMem)[9] = count2;
Сейчас реализовано так:
C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
u_int8_t * newMem = (u_int8_t *)malloc( 17 );
u_int8_t * code = 0;
newMem[0] = code;
 
/* указатель на 1-байтный integer ссылается на 2й элемент массива, 
   состоящего из элементов по 1 байт */
int64_t * temp = &newMem[1];
 
int64_t * count1 = 1024*1024*10;
int64_t * count2 = 1024*1024*10;
 
// записываем данные, соответствующие массиву из 8-байтных элементов
temp[0] = count1;
temp[1] = count2;
Так что - всем спасибо за внимание и попытки помочь
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
26.04.2011, 15:21
olzan, в самом первом посте ты уже сделал всё, что тебе нужно (только в строках 4-6 нужно убрать звёздочки от указателей). Остаётся только передать этот массив (подать его в send или через что ты там передаёшь)

Могу указать на два момента:
1. Не все архитектуры позволяют невыравнненое обращение в память. Т.е. запись 8-байтного значениея по адресу НЕ выровненному на 8 байт не некоторых архитектурах невозможен. Для таких дел надо использовать упакованные структуры: Использование #pragma pack(push,1)... pack(pop)
2. Тут уже говорилось о порядке байтов. Если на одном конце сети сидит машина little-endian, а на другом - big-endian, тонужны дополнительные телодвижения. По поводу endian'а свежая тема тут: Преобразование типа byte в десятичный Были и ещё (и именно про передачу данных по сети), но навскидку уже и не помню, по каким ключевым словам искать можно
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
27.04.2011, 03:37
Цитата Сообщение от olzan
Достает данные приложение-клиент на delphi (я пишу сервер на Си). С точки зрения меня, как разработчика, как клиент будет доставать данные - не важно. Важно, чтобы и сервер, и клиент общались по стандартизированному протоколу.
это-то понятно, но как клиент узнает, какие там данные, какие у них размеры
он получает поток байтов, о котором должна прийти однозначная информация

C++
1
u_int16_t length;
число, записанное в такую переменную, можно читать слева-направо, а можно справа-налево

length = 10; может передаваться в виде 0x000a, а может в виде 0x0a00
(сохрани структуру в файл и посмотри в hex-редакторе)
на одном компе передавали 10, а на другом получили 2560
0
0 / 0 / 0
Регистрация: 25.04.2011
Сообщений: 10
27.04.2011, 05:27  [ТС]
Цитата Сообщение от accept Посмотреть сообщение
это-то понятно, но как клиент узнает, какие там данные, какие у них размеры
он получает поток байтов, о котором должна прийти однозначная информация
Протокол. В зависимости от заголовка, будет происходить соответствующий парсинг принятых байт. Не беспокойтесь )

Цитата Сообщение от accept Посмотреть сообщение
C++
1
u_int16_t length;
число, записанное в такую переменную, можно читать слева-направо, а можно справа-налево
Можно, не спорю. Но писать вслепую никто не собирается - у меня есть клиент, и я проверяю корректность данных. Проблем с порядком байт не возникает, спасибо за беспокойство )


Цитата Сообщение от Evg Посмотреть сообщение
olzan, в самом первом посте ты уже сделал всё, что тебе нужно (только в строках 4-6 нужно убрать звёздочки от указателей). Остаётся только передать этот массив (подать его в send или через что ты там передаёшь)

Могу указать на два момента:
1. Не все архитектуры позволяют невыравнненое обращение в память. Т.е. запись 8-байтного значениея по адресу НЕ выровненному на 8 байт не некоторых архитектурах невозможен. Для таких дел надо использовать упакованные структуры: Использование #pragma pack(push,1)... pack(pop)
2. Тут уже говорилось о порядке байтов. Если на одном конце сети сидит машина little-endian, а на другом - big-endian, тонужны дополнительные телодвижения. По поводу endian'а свежая тема тут: Преобразование типа byte в десятичный Были и ещё (и именно про передачу данных по сети), но навскидку уже и не помню, по каким ключевым словам искать можно
0. Я чуть выше описал, что было не так, и в чем заключалась моя ошибка.
1. Хорошо, спасибо.
2. Узловой и сетевой, да-да. Не беспокойтесь на этот счет.)
0
4866 / 3288 / 468
Регистрация: 10.12.2008
Сообщений: 10,570
28.04.2011, 04:30
Цитата Сообщение от olzan
А вот как запихнуть в него 8ми-байтные integer - до меня не доходит.
через memcpy(), но она будет писать в том эндианстве, которое на компе

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <cstring>
#include <iomanip>
 
using namespace std;
 
#define SIZE 100
 
int main()
{
    unsigned char buf[SIZE];
    char v = 4;
    long count1 = 1024 * 1024 * 10;
    long count2 = 1024 * 1024 * 10;
    int offset = 0;
    
    memcpy((unsigned char *) (buf + offset), &v, sizeof v);
    offset += sizeof v;
    memcpy((unsigned char *) (buf + offset), &count1, sizeof count1);
    offset += sizeof count1;
    memcpy((unsigned char *) (buf + offset), &count2, sizeof count2);
    offset += sizeof count2;
 
    for (int i = 0; i < offset; i++)
        cout << " " << hex << int(buf[i]);
    cout << endl;
    
    return 0;
}
Code
1
2
3
[guest@localhost tests]$ ./t
 4 0 0 a0 0 0 0 a0 0
[guest@localhost tests]$
отдельные нули - это 00
0
 Аватар для taras atavin
4226 / 1796 / 211
Регистрация: 24.11.2009
Сообщений: 27,562
28.04.2011, 06:50
Цитата Сообщение от olzan Посмотреть сообщение
Так как для передачи через сокет необходим однобайтовый тип,
Сокету нужен сырой тип а не однобайтный. Приведи весь блок к
C
1
void*
и всего делов.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
28.04.2011, 06:50
Помогаю со студенческими работами здесь

Записать данные из 2 TextBox в массив точек для poligon
Записать данные из 2 текстбоксов в массив точек для poligona подскажите как это реализовать пожалуйста

Нужно записать массив в файл, а потом из этого файла считать этот же массив
Помогите, пожалуйста, никогда с файлами делов не имела. Нужно записать массив в файл, а потом из этого файла считать этот же массив. ...

Записать массив строк в файл, а потом получить такой же массив из этого файла
Есть вот такой массив, который формируется из разных чтрок: string temp = {dateTimePicker1.Value.ToString(), gender, label6.Text}; ...

Просмотр передачи пакета
Здравствуйте! Подскажите пожалуйста есть ли программа, которая будет просматривать через какие маршрутизаторы и свичи у меня проходит...

Программа для передачи сообщений по сети
Нужен код который СКОПИРУЕТ мою программу в папку с виндой.(программа для передачи сообшений по сети)


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
17
Ответ Создать тему
Новые блоги и статьи
http://iceja.net/ математические сервисы
iceja 20.01.2026
Обновила свой сайт http:/ / iceja. net/ , приделала Fast Fourier Transform экстраполяцию сигналов. Однако предсказывает далеко не каждый сигнал (см ограничения http:/ / iceja. net/ fourier/ docs ). Также. . .
http://iceja.net/ сервер решения полиномов
iceja 18.01.2026
Выкатила http:/ / iceja. net/ сервер решения полиномов (находит действительные корни полиномов методом Штурма). На сайте документация по API, но скажу прямо VPS слабенький и 200 000 полиномов. . .
Расчёт переходных процессов в цепи постоянного тока
igorrr37 16.01.2026
/ * Дана цепь постоянного тока с R, L, C, k(ключ), U, E, J. Программа составляет систему уравнений по 1 и 2 законам Кирхгофа, решает её и находит переходные токи и напряжения на элементах схемы. . . .
Восстановить юзерскрипты Greasemonkey из бэкапа браузера
damix 15.01.2026
Если восстановить из бэкапа профиль Firefox после переустановки винды, то список юзерскриптов в Greasemonkey будет пустым. Но восстановить их можно так. Для этого понадобится консольная утилита. . .
Сукцессия микоризы: основная теория в виде двух уравнений.
anaschu 11.01.2026
https:/ / rutube. ru/ video/ 7a537f578d808e67a3c6fd818a44a5c4/
WordPad для Windows 11
Jel 10.01.2026
WordPad для Windows 11 — это приложение, которое восстанавливает классический текстовый редактор WordPad в операционной системе Windows 11. После того как Microsoft исключила WordPad из. . .
Classic Notepad for Windows 11
Jel 10.01.2026
Old Classic Notepad for Windows 11 Приложение для Windows 11, позволяющее пользователям вернуть классическую версию текстового редактора «Блокнот» из Windows 10. Программа предоставляет более. . .
Почему дизайн решает?
Neotwalker 09.01.2026
В современном мире, где конкуренция за внимание потребителя достигла пика, дизайн становится мощным инструментом для успеха бренда. Это не просто красивый внешний вид продукта или сайта — это. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru