Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.77/22: Рейтинг темы: голосов - 22, средняя оценка - 4.77
 Аватар для Gus
26 / 37 / 10
Регистрация: 17.02.2009
Сообщений: 364

Пересылка struct силами Socket'ов

10.03.2012, 17:25. Показов 4789. Ответов 28
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Доброго времени суток.
Как переслать структуру по сокету, читал различные форумы, но статей я так и не нашел.
Как пересылаются данные.
и как заполняются структуры на сервере или клиенте в зависимости кто отправляет.


Как эффективно бегать по структурам (Допускается массив структур) что бы не зная их количества не выбегать за пределы.
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
10.03.2012, 17:25
Ответы с готовыми решениями:

Struct sockaddr vs. struct sockaddr_in
Вопрос,связанный с переносимостью кода на другие платформы. Читаю эту книжку http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html...

Как открыть struct в struct
Здравствуйте, есть код, мне нужно узнать как можно открыть struct в struct, к примеру чтобы заполнить public string Osnv_Glagol; ...

typedef struct Foo или struct Foo
В чём разница между: typedef struct { int a; }Foo; и struct Foo { int a; }

28
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
11.03.2012, 10:54
Студворк — интернет-сервис помощи студентам
можешь как и с приемом.
Например так:
C++
1
2
3
4
5
6
7
template <typename StructT>
int UserOnline::SendStruct(const StructT &Struct4Send)
{
    return send(UserSocket, 
                reinterpret_cast<const char *>(&Struct4Send),
                sizeof(Struct4Send),0);
}
Если посылка предполагает работу только с твоей структурой, то пиши прямо:
C++
1
2
3
4
5
6
int UserOnline::SendStruct(const SEND &Struct4Send)
{
    return send(UserSocket, 
                reinterpret_cast<const char *>(&Struct4Send),
                sizeof(Struct4Send),0);
}
0
 Аватар для Gus
26 / 37 / 10
Регистрация: 17.02.2009
Сообщений: 364
11.03.2012, 11:18  [ТС]
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
        if(strcmp(buff,"SENDSTRUCT")==0)
        {
        sizestruct=sizeof(SendStruct);
        char data[sizestruct];
        char *p=&data[0];
        while(sizestruct)
        {
        cout <<"RECV STRUCT"<<endl;
        int rcved=recv(Usermem->UserSocket,p,sizestruct,0);
        if(rcved==-1){cout<<"System failed"<<endl; break;}
        if(rcved==0){cout<<"Connection terminated"<<endl;break;}
        p+=rcved;
        sizestruct-=rcved;
        }
        memcpy(SendStruct,data,sizeof(SendStruct));
        }
Тут где то прячется коварная ошибка сегментации...
p.s Я использую перед отправкой структуры команду SENDSTRUCT то есть присылаю команду на сервер
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
11.03.2012, 11:32
C++
1
if(strcmp(buff,"SENDSTRUCT")==0)
Как отправляешь эту строку? Учитывается ли ноль в конце строки при отправке?

Добавлено через 9 минут
Кста еще по поводу кода:
C++
1
2
3
4
5
6
7
8
9
10
11
        while(sizestruct)
        {
        cout <<"RECV STRUCT"<<endl;
        int rcved=recv(Usermem->UserSocket,p,sizestruct,0);
        if(rcved==-1){cout<<"System failed"<<endl; break;}
        if(rcved==0){cout<<"Connection terminated"<<endl;break;}
        p+=rcved;
        sizestruct-=rcved;
        }
        memcpy(SendStruct,data,sizeof(SendStruct));
        }
он не совсем безопасен ...
например если у тебя возник сбой при получении (recv вернул -1, 0) то структура забьется мусором
вариант исправить:
C++
1
if(0 == sizestruct ) memcpy(SendStruct,data,sizeof(SendStruct));
потому как лучше не изменять состояние структуры, чем вносить некорректные данные.

и еще ... а что такое SendStruct? указатель? если да, то sizeof(SendStruct) не верно.
и тут бага
C++
1
sizestruct=sizeof(SendStruct);
sizestruct у тебя будет только размер указателя. и соответственно примешь ты только 4, 8 байт -> дальше будут сбои.

если структура. то надо так:
C++
1
memcpy(&SendStruct,data,sizeof(SendStruct));
0
 Аватар для Gus
26 / 37 / 10
Регистрация: 17.02.2009
Сообщений: 364
11.03.2012, 11:52  [ТС]
всмысле ноль в конце строки ? у мну SendStruct указатель на структуру
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
11.03.2012, 12:08
в том смысле, что strcmp читает до нуля строки, либо до первого несовпадения.
пользуй strncmp.
+ еще вопрос в том, как ты принял эту строку. А не принял ли ты вместе со строкой часть структуры? это тоже может стать причиной дальнейшего незапланированного поведения.
C++
1
 у мну SendStruct указатель на структуру
отсюда вытекает бага
sizeof(SendStruct) - не размер структуры, а размер указателя.
->
C++
1
2
        sizestruct=sizeof(SendStruct); // размер указателя
        char data[sizestruct]; // буфер под размер указателя (4, 8 байт)
->
C++
1
int rcved=recv(Usermem->UserSocket,p,sizestruct,0);
Читаешь только размер указателя
->
C++
1
memcpy(SendStruct,data,sizeof(SendStruct));
копируешь только размер указателя, структура не заполняется.

Исправить - sizestruct=sizeof(SEND); // имя структуры, либо сделать SendStruct не указателем (например, если ты этот указатель передаешь в функцию, то передавать не указателем, а ссылкой), а копировать так:
C++
1
memcpy(&SendStruct,data,sizeof(SendStruct)); // так.
1
 Аватар для Gus
26 / 37 / 10
Регистрация: 17.02.2009
Сообщений: 364
11.03.2012, 12:13  [ТС]
так что я сделал:
C++
1
2
3
4
5
6
        sizestruct=sizeof(SEND); //Где SEND Структура а SendStruct указатель на нее
        char data[sizestruct];
        memcpy(SendStruct,data,sizeof(SEND));
                cout <<"QUIT FROM CYCLE"<<endl;
        cout <<SendStruct->cmd <<' ' <<SendStruct->param << ' ' <<SendStruct->param2<<endl;
        }
Итог: Не выходит сообщение QUIT FROM CYCLE
В начале цикла приема я поставил cout с текстом RECV STRUCT видимо он за 2 цикла выкачивает. Но почему не идет дальше, а на все входящие комманды реагирует (сервер многопоточный)

Добавлено через 2 минуты
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
30
31
32
33
34
    DWORD WINAPI ChebTCPServerSocket::ClientThread(LPVOID User)
    {
        int sizestruct;
        int temp;
        char buff[4096];
        UserOnline *Usermem;
        CharTools *CTools;
        SEND *SendStruct;
        Cheb21 *cheb21;
        FILE *file;
        Usermem=(UserOnline *)User;
        Usermem->SendText("HELLO");
        while(int bytes_recv=recv(Usermem->UserSocket,buff,4096,0)&&bytes_recv!=INVALID_SOCKET)
        {
        //Îáðàáîò÷èêè ñîîáùåíèé
        if(bytes_recv==-1){cout <<"Error system failed"<<endl; Usermem->SendText("FAIL");}
        if(strcmp(buff,"SENDSTRUCT")==0)
        {
        sizestruct=sizeof(SEND);
        char data[sizestruct];
        char *p=&data[0];
        while(sizestruct)
        {
        cout <<"RECV STRUCT"<<endl;
        int rcved=recv(Usermem->UserSocket,p,sizestruct,0);
        if(rcved==-1){cout<<"System failed"<<endl;}
        if(rcved==0){cout<<"Connection terminated"<<endl;memcpy(SendStruct,data,sizeof(SEND));}
        p+=rcved;
        sizestruct-=rcved;
        }
        memcpy(SendStruct,data,sizeof(SEND));
                cout <<"QUIT FROM CYCLE"<<endl;
        cout <<SendStruct->cmd <<' ' <<SendStruct->param << ' ' <<SendStruct->param2<<endl;
        }
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
11.03.2012, 12:24
вот тут начинаются проблемы:
C++
1
while(int bytes_recv=recv(Usermem->UserSocket,buff,4096,0)&&bytes_recv!=INVALID_SOCKET)
у тебя прием 4096 байт. тут может прийти строка + часть структуры, далее ты не сможешь полностью вычитать структуру, потому что она у тебя уже вычитана ранее. + ко всему у тебя будет идти прием структуры с середины.
Вот тут пришли к тому, что нужно описать прикладной протокол. если посылается команда перед основной структурой, то эта команда должно иметь четкие границы, которые ты корректно обработаешь. например, если команда - строка, то нужно чтоб она оканчивалась, например, нулем. -> тебе нужно вычитывать сначала все до нуля, потом уже структуру. либо, если команда - это фиксированный блок, то вычитывать сначала этот блок, а потом уже анализировать и получать данные дальше. Поэтому у тебя и не выходит сообщение QUIT FROM CYCLE потому что данные вычитаны и вызов recv ждет новых.
C++
1
SEND *SendStruct;
на что указывает этот указатель? где выделение памяти? -> вот тебе и ошибка сегментации. ты пишешь куда-то не туда.
вариант - сделать переменную НЕ указателем
C++
1
SEND SendStruct;
1
 Аватар для Gus
26 / 37 / 10
Регистрация: 17.02.2009
Сообщений: 364
11.03.2012, 12:37  [ТС]
Ведь можно же задержку сделать, например на отправителе поставить между
SendText и SendStruct Sleep(100) или побольше
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
11.03.2012, 13:30
Зачем?
Нужно просто принять строку
вариант:
(код прям тут писал, если что не так - говори)
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
std::string recv_string(std::vector<char> &tail) {
    size_t last_position = 0; // начало позиции проверки
    std::vector<char> tmp_block;
    do {
        std::vector<char> buf(1024); // вот тут идея размера в том, чтоб ты захватил команду и часть структуры, но не следующую команду, если такая идет. (1024 + 25; см ниже) - гарантированно меньше чем sizeof(SEND); но способ корявый :-/
        int recved = recv(sock, &buf[0], buf.size(), 0);
        if( recved <= 0 ) throw recv_error(); // ошибку обработали
        tmp_block.insert(tmp_block.end(), buf.begin(), buf.begin() + recved); // дописали
        bool found = false; // на самом деле можно без этого сделать
        for(;last_position != tmp_block.size(); ++last_position) { // проверяем со старой позиции, чтоб не гонять с начала
            if(tmp_block[last_position] == 0) { found = true; break; } // нашли, установили, вышли
        }
        if(last_position >= 25) throw std::length_error("Message is too long;"); // небольшая защита от задницы, которая может произойти. тут я ограничил размер команды 25 символами, но возможно у тебя другая идея.
        if (found) break; // вышли из цикла
    } while (true);
    std::string res(tmp_block.begin(), tmp_block.begin() + last_position); // копируем строку
    tail.assign(tmp_block.begin() + last_position + 1, tmp_block.end()); // копируем хвост.
    return res; вернули строку
};
На выходе у тебя строка + остаток блока, который можно потом скопировать в буфер, не забыв подвинуть размер и указатель.
пользовать:
C++
1
2
3
4
5
6
7
8
9
10
std::vector<char> tail_data;
std::string command = recv_string(tail_data);
if(0 == command.compare("SENDSTRUCT")) {
    assert(tail_data.size() <= sizeof(SEND)); // просто тест если вылетит тут то что-то пошло не так
    char data[sizeof(SEND)];
    std::copy(tail_data.begin(), tail_data.end(), data); // tail_data гарантированно войдет в блок
    p = data + tail_data.size();
    size_t struct_size = sizeof(SEND) - tail_data.size();
    while(struct_size) {.....} // как раньше
}
PS: такой способ получения строки очень не красивый и не совсем корректный и безопасный. Потому как есть ограничение на принимаемый буфер в вызове recv_string и далее обработка не рассчитана на то, что в хвосте придет кусок следующей команды.
Вариант решения -- снова коллектор, да который все это красиво разрулит. Код коллектора есть по теме выше, для приема строки нужно только немного переделать.


Ах да! теперь сервер должен отправлять строку с нулем в конце, иначе не будет работать.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
11.03.2012, 13:30
Помогаю со студенческими работами здесь

Правка реестра силами C++
Нужно по нажатию кнопки внести данные в реестр, но происходит кокая то проблема с преобразованием типов Unit1.cpp(38): E2034 Cannot...

Oтправить пакет силами WinPcap
Привет всем. Вот собственно вопрос: &quot;Как с помощью библиотеки WinPcap можно отправить пакет :00 01 00 00 00 01 00 00 00 01 00 81 00 08 00...

Поиск в Access своими силами
Private Sub Command89_Click() Dim rst As Recordset Dim strSearchName As String Set rst = Me.RecordsetClone ...

Авторизация на auto.ru силами Synapse
Добрый день, киберфорумчане. Помогите, пожалуйста, авторизироваться на сайте auto.ru силами Synapse на Delphi. Никак не могу...

Распознание речи силами HTML5
Здравствуйте! Нужно создать на сайте возможность распознания речи. Возможно ли это сделать силами HTML5? Если нет, можете поделиться...


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

Или воспользуйтесь поиском по форуму:
29
Ответ Создать тему
Новые блоги и статьи
Настройки VS Code
Loafer 13.04.2026
{ "cmake. configureOnOpen": false, "diffEditor. ignoreTrimWhitespace": true, "editor. guides. bracketPairs": "active", "extensions. ignoreRecommendations": true, . . .
Оптимизация кода на разграничение прав доступа к элементам формы
Maks 13.04.2026
Алгоритм из решения ниже реализован на нетиповом документе, разработанного в конфигурации КА2. Задачи, как таковой, поставлено не было, проделанное ниже исключительно моя инициатива. Было так:. . .
Контроль заполнения и очистка дат в зависимости от значения перечислений
Maks 12.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: реализовать контроль корректности заполнения дат назначения. . .
Архитектура слоя интернета для сервера-слоя.
Hrethgir 11.04.2026
В продолжение https:/ / www. cyberforum. ru/ blogs/ 223907/ 10860. html Знаешь что я подумал? Раз мы все источники пишем в голове ветки, то ничего не мешает добавить в голову такой источник, который сам. . .
Подстановка значения реквизита справочника в табличную часть документа
Maks 10.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа "ПланированиеПерсонала", разработанного в конфигурации КА2. Задача: при выборе сотрудника (справочник Сотрудники) в ТЧ документа. . .
Очистка реквизитов документа при копировании
Maks 09.04.2026
Алгоритм из решения ниже применим как для типовых, так и для нетиповых документов на самых различных конфигурациях. Задача: при копировании документа очищать определенные реквизиты и табличную. . .
модель ЗдравоСохранения 8. Подготовка к разному выполнению заданий
anaschu 08.04.2026
https:/ / github. com/ shumilovas/ med2. git main ветка * содержимое блока дэлэй из старой модели теперь внутри зайца новой модели 8ATzM_2aurI
Блокировка документа от изменений, если он открыт у другого пользователя
Maks 08.04.2026
Алгоритм из решения ниже реализован на примере нетипового документа, разработанного в конфигурации КА2. Задача: запретить редактирование документа, если он открыт у другого пользователя. / / . . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru