Форум программистов, компьютерный форум, киберфорум
C++: Сети
Войти
Регистрация
Восстановить пароль
 
 
Рейтинг 5.00/12: Рейтинг темы: голосов - 12, средняя оценка - 5.00
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
1

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

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

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


Как эффективно бегать по структурам (Допускается массив структур) что бы не зная их количества не выбегать за пределы.
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
10.03.2012, 17:25
Ответы с готовыми решениями:

Struct sockaddr vs. struct sockaddr_in
Вопрос,связанный с переносимостью кода на другие платформы. Читаю эту книжку...

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

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

Правка реестра силами C++
Нужно по нажатию кнопки внести данные в реестр, но происходит кокая то проблема с преобразованием...

28
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 17:35 2
Цитата Сообщение от Gus Посмотреть сообщение
Доброго времени суток.
Как переслать структуру по сокету, читал различные форумы, но статей я так и не нашел.
Сериализовать, отправить (примеров полно, даже на этом форуме), принять, десериализовать

Цитата Сообщение от Gus Посмотреть сообщение
Как пересылаются данные.
и как заполняются структуры на сервере или клиенте в зависимости кто отправляет.
посылаются, если силами socket, то send, принимаются recv. Про "заполняются" не понял.

Цитата Сообщение от Gus Посмотреть сообщение
Как эффективно бегать по структурам (Допускается массив структур) что бы не зная их количества не выбегать за пределы.
что значит "эффективно бегать по структурам"?
0
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 17:44  [ТС] 3
villu, то есть, у нас есть исходный образец массива, допустим на клиенской стороне программно структура заполняется отправляется.
Сервер принимает и соответственно заполняет свой образец структуры?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 17:51 4
аа..
ну тогда примерно так и надо делать. Только надо заполнять этот массив не чистыми структурами, а сериализованными (см выше). Далее послать на другую сторону.
В зависимости от того, какой транспортный протокол ты используешь (tcp или udp), можно выбрать способ отправки (описать прикладной протокол). а в качестве массива можно, например vector использовать.
0
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 17:54  [ТС] 5
C++
1
2
3
4
5
6
7
8
9
10
11
#pragma (push,1)
struct SEND{
       int IDfrom;
       int IDto;
       int SIZE;
       char cmd[15];
       char param[50];
       char param2[50];
       char buff[4096];
};
#pragma (pop)
вот приблизительно такая структура кроме потока должна отправлятся от клиента к серверу и обратно
Все написанно, осталось понять как энто работает и писать
0
153 / 110 / 0
Регистрация: 08.02.2012
Сообщений: 202
10.03.2012, 17:56 6
тут почитай. Примеры есть
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 18:03 7
Все написанно, осталось понять как энто работает и писать
ну клиент-сервер понимаешь как написать?
0
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 18:13  [ТС] 8
Цитата Сообщение от villu Посмотреть сообщение
ну клиент-сервер понимаешь как написать?
Уже написан)
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 18:15 9
отлично. протокол какой (tcp/udp/какой-то еще)?
0
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 18:31  [ТС] 10
TCP SOCK_STREAM
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 18:55 11
ну вот...есть 2 пути:
1: Пересылать структуру "как есть" по указателю, но помни, что TCP может доставлять данные не теми порциями, которыми они были отправлены. обсуждалось тут
вариант такой отправки не очень хороший. Однажды можешь встретить машину, на которой байты идут в обратной порядке.(вики)
2: Для того, чтоб этого избежать нужна сериализация. Проще говоря тебе необходимо из твоей структуры получить блок данных, которые однозначно "превратятся" в твою структуру на любой машине с любым порядком байт, а в идеале даже с другим размером типа int.

Прием опять же зависит от способа отправки. Если вариант 1 то просто получай данные, накапливай до sizeof(SEND) и обрабатывай.

Если вариант 2, то размер реально передаваемых данных может измениться. Как в плюс, так и в минус. И примем/накапливание в этом случае будет зависеть от способа сериализации.

Сериализацией, например, может быть банальное заворачивание в строку, это может быть просто строка с разделителями, либо XML, либо еще что читаемое (размер увеличится).

Либо запаковка данных.
Например вот эти массивы
C++
1
2
3
4
       char cmd[15];
       char param[50];
       char param2[50];
       char buff[4096];
не всегда заполнены так? если так, то зачем передавать незначительные байты?
1
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 19:16  [ТС] 12
то есть
C++
1
2
send(clientsocket,&structdata,&sizeof(structdata),0);
recv(serversocket,&structdata,5000,0);
приблизительно это будет выглядеть так ?
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 19:20 13
не совсем
C++
1
recv(serversocket,&structdata,5000,0);
этот кусок не верен.
Тебе может прийти половина структуры.

1 Накапливай данные,
2 Как получишь достаточно для структуры, копируй их в переменную, удаляй из хранилища, переходи на п1.
0
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 19:30  [ТС] 14
пример можно ? А то про накопление данных ничего подобного не видел)))
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 19:35 15
на c++ пишешь или чистом Си?
0
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 19:49  [ТС] 16
пласы
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
10.03.2012, 20:44 17
ok
Вариант 1 (код написал прямо тут, думаю смысл поймешь):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
void recv_block( SEND &out ) { // параметр - ссылка на структуру, можешь передавать указатель
    char data[sizeof(out)]; // блок данных, фиксированного размера 
    char *p = &data[0];    // указатель, который будет перемещаться по блоку
    int desired_len = sizeof(out); // установим количество нужных данных 
    while(desired_len) {             // и пока нам есть что послушать ..
        int rcved = recv(s, p, desired_len, 0); // принимаем данные. прочитает не больше desired_len
        if( rcved == -1) throw system_failed(); // системная ошибка, можешь обработать как-то по другому
        if( rcved ==  0) throw connection_close(); // соединение закрыто. опять же если не нравится exception можешь просто что-то другое сделать
        p += rcved; // передвигаем указатель
        desired_len -= rcved; // уменьшаем размер необходимого если desired_len == 0 то прочитали все, и в цикл больше не войдем
    } 
    memcpy(&out, data, sizeof(out)); // просто копируем данные в структуру
}
кстати этот вызов легко становится шаблоном:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
template <typename StructT>
void recv_block( StructT &out ) { // параметр - ссылка на структуру, можешь передавать указатель
    char data[sizeof(out)]; // блок данных, фиксированного размера 
    char *p = &data[0];    // указатель, который будет перемещаться по блоку
    int desired_len = sizeof(out); // установим количество нужных данных 
    while(desired_len) {             // и пока нам есть что послушать ..
        int rcved = recv(s, p, desired_len, 0); // принимаем данные. прочитает не больше desired_len
        if( rcved == -1) throw system_failed(); // системная ошибка, можешь обработать как-то по другому
        if( rcved ==  0) throw connection_close(); // соединение закрыто. опять же если не нравится exception можешь просто что-то другое сделать
        p += rcved; // передвигаем указатель
        desired_len -= rcved; // уменьшаем размер необходимого если desired_len == 0 то прочитали все, и в цикл больше не войдем
    } 
    memcpy(&out, data, sizeof(out)); // просто копируем данные в структуру
}
Второй способ...ууф .. я его писал уже ранее в другой теме, сейчас подниму, немного подправлю и покажу.

Добавлено через 44 минуты
И так второй способ накопить и обработать структуры заранее известного размера
это класс из темы (https://www.cyberforum.ru/cpp-... ost2768798)
но более простой, потому что делает меньше работы.

Не по теме:

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


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
35
36
37
38
39
40
41
42
43
44
45
46
template <size_t StructSize>
class struct_collector {
    typedef std::vector<char>   container_type;
    static const size_t struct_size = StructSize;
    container_type  m_data;
public:
    virtual ~struct_collector() {}
public:
 
    void append( const void *data, size_t len ) { // сливаем очередную порцию данных
        const char * b = static_cast<const char *>(data);
        const char * e = b + len;
        append( b, e );
    }
 
    template <typename IterT> 
    void append( const IterT &begin, const IterT &end ) { // просто еще один вариант
        m_data.insert(m_data.end(), begin, end);
    }
    void analize() { process(); } // в первом варианте этот вызов стоял прямо в append (там push_data), что было не очень хорошо...Но если хочется - можешь вернуть.
private:
    void erase_begin( size_t length ) {
        m_data.erase( m_data.begin(), m_data.begin() + length );
    }
    void process() {  // основной цикл, вычитываем данные пока их достаточно для заполнения структуры размером struct_size, то есть твоей SEND.
        do {
            if( struct_size <= m_data.size() ) {
                container_type tmp(m_data.begin(), m_data.begin() + struct_size); // копируем
                erase_begin( struct_size ); // удаляем
                cb_complete(&tmp[0], tmp.size()); // вызываем колбек
            } else {
                break;
            }
        } while (true);
    }
 
    virtual void cb_complete ( const void *data, size_t len ) = 0; // абстрактный класс...потому как смысла от него не абстрактного мало.
 
public:
    size_t need() const {
        return struct_size - m_data.size();
    }
    size_t collected_units() const {
        return m_data.size() / struct_size;
    }
};
Использование:
C++
1
2
3
4
5
6
7
8
// для начала отнаследуемся 
class my_collector: public struct_collector<sizeof(SEND)>  { // размер структуры SEND
    void cb_complete ( const void *data, size_t len ) { // наш вариант обработки ... можешь, в принципе прямо в основной класс вставить.
        SEND recved_struct;
        memcpy(&recved_struct, data, len);
        //// получена структура, делай с ней, что хочешь
    }
};
теперь при приеме:
C++
1
2
3
4
5
6
7
8
my_collector collector;
.....
    int recved = recv(sock, data, 1024 * 8, 0); /// принимаем большой кусок данных; тут data - место  достаточное для того, чтоб поместить 8килобайт.
    if (recved > 0 ) collector.append(data, recved); // проверяем на ошибку или закрытое соединение, если нет, сливаем данные в коллектор
.....
    if(collector.collected_units() >= 100 ) // ok накопили 100 структур
       collector.analize(); /// 100 раз будет вызван cb_complete + останутся данные, которые еще составляют не полную структуру и collector можно использовать дальше. а collector.need() вернет тебе сколько еще недополучено до ближайшей полной структуры
.....
Кстати пока писал пришла еще одна идея ... колбек можно сделать таким
C++
1
 virtual bool cb_complete ( const void *data, size_t len ) = 0;
и поменять тут
C++
1
2
3
4
5
         if( struct_size <= m_data.size() ) {
                container_type tmp(m_data.begin(), m_data.begin() + struct_size); // копируем
                erase_begin( struct_size ); // удаляем
                if(!cb_complete(&tmp[0], tmp.size())) break; // вызываем колбек, если вернул false, то просто выходим из цикла
            } else {
Соответственно в наследнике тоже переписать.
Вполне возможно, что где-то будет полезно остановиться на обработке первых 10 структур, например, из 100.
1
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
10.03.2012, 23:32  [ТС] 18
C++
1
2
int UserOnline::SendStruct(void *Struct)
{return send(UserSocket,(const char*)Struct,sizeof(Struct),0);}
Это выражение вообще правильное с точки зрения программирования, где void * Указатель на структуру SEND
0
204 / 205 / 16
Регистрация: 06.08.2011
Сообщений: 600
Записей в блоге: 1
11.03.2012, 07:53 19
нет, у тебя получается sizeof(Struct) равен размеру указателя. 4 или 8 байт.
если передаешь void* то передавай размер рядом
C++
1
2
int UserOnline::SendStruct(void *Struct, size_t len)
{return send(UserSocket,(const char*)Struct,len,0);}
1
25 / 36 / 10
Регистрация: 17.02.2009
Сообщений: 364
11.03.2012, 10:30  [ТС] 20
а так воообще корректно передавать структуру?!

Добавлено через 28 секунд
через const char?
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
11.03.2012, 10:30

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

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

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

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


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

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.