Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 07:56
Оценка:
имеется структура :

struct {
unsigned long id;
unsigned long size;
unsigned long type;
char name[32];
char addr[16];
unsigned long p;
} data;

которую надо отослать серверу, а сервер, соответственно, должен ее получить, изменить полученные данные и отправить их обратно.
Re: Как переслать структуру с помощью сокетов
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 06.04.05 08:43
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>имеется структура :

LX>которую надо отослать серверу, а сервер, соответственно, должен ее получить, изменить полученные данные и отправить их обратно.

#pragma pack(push,1)

struct {
  unsigned long id;
  unsigned long size;
  unsigned long type;
    char name[32];
    char addr[16];
  unsigned long p;
} data;

#pragma pack(pop)


// гарантированная отправка всего буфера
int sendall( SOCKET sock, const char * buff, int nBytes )
{
   int nLeft = nBytes;
   int idx = 0;
   while (nLeft > 0)
   {
      int ret = send( sock, &buff[idx], nLeft, 0);
      if (ret == SOCKET_ERROR)
      {
         return SOCKET_ERROR;
      }
      nLeft -= ret;
      idx += ret;
   }

   return nBytes;
}


// обнулили
ZeroMemory( &data, sizeof(data ) );

// заполнили data
// ...

// установили связь

// отправили 
if( SOCKET_ERROR == sendall( _socket, ( const char* )&data, sizeof( data ) ) )
{
// Облом
}


если данные могут пересылаться разные, а не только data, то придется к эту структуру предварять заголовком — тип данных, размер пакета.

Ну и прием соответственно — recv в буфер, потом смотришь, что принял не меньше sizeof(data), если если меньше, снова на recv, когда придет все — memcpy в data на этой стороне.
Re[2]: Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 11:23
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, LeXa-XL, Вы писали:


LX>>имеется структура :

LX>>которую надо отослать серверу, а сервер, соответственно, должен ее получить, изменить полученные данные и отправить их обратно.

OE>
OE>#pragma pack(push,1)
OE>
OE>struct {
OE>  unsigned long id;
OE>  unsigned long size;
OE>  unsigned long type;
OE>    char name[32];
OE>    char addr[16];
OE>  unsigned long p;
OE>} data;

OE>#pragma pack(pop)
OE>

OE>// гарантированная отправка всего буфера
OE>int sendall( SOCKET sock, const char * buff, int nBytes )
OE>{
OE>   int nLeft = nBytes;
OE>   int idx = 0;
OE>   while (nLeft > 0)
OE>   {
OE>      int ret = send( sock, &buff[idx], nLeft, 0);
OE>      if (ret == SOCKET_ERROR)
OE>      {
OE>         return SOCKET_ERROR;
OE>      }
OE>      nLeft -= ret;
OE>      idx += ret;
OE>   }

OE>   return nBytes;
OE>}
OE>


OE>
OE>// обнулили
OE>ZeroMemory( &data, sizeof(data ) );

OE>// заполнили data
OE>// ...

OE>// установили связь

OE>// отправили 
OE>if( SOCKET_ERROR == sendall( _socket, ( const char* )&data, sizeof( data ) ) )
OE>{
OE>// Облом
OE>}
OE>


можно немного по подробнее о :
#pragma pack(push,1)
struct {
unsigned long id;
unsigned long size;
unsigned long type;
char name[32];
char addr[16];
unsigned long p;
} data;
#pragma pack(pop)

не совсем понятно как данная структура преобразуется в const char *buff
что делает #pragma pack(push,1)?
а если много подобных, но разных структур, то между push и pop надо просто добавить описание этих структур?


OE>если данные могут пересылаться разные, а не только data, то придется к эту структуру предварять заголовком — тип данных, размер пакета.


OE>Ну и прием соответственно — recv в буфер, потом смотришь, что принял не меньше sizeof(data), если если меньше, снова на recv, когда придет все — memcpy в data на этой стороне.


Я так понимаю, если есть много типов структур data1, data2, data3 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?
Re[3]: Как переслать структуру с помощью сокетов
От: Stoune  
Дата: 06.04.05 12:59
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>можно немного по подробнее о :

LX>#pragma pack(push,1)
LX>struct {
LX> unsigned long id;
LX> unsigned long size;
LX> unsigned long type;
LX> char name[32];
LX> char addr[16];
LX> unsigned long p;
LX>} data;
LX>#pragma pack(pop)

LX>не совсем понятно как данная структура преобразуется в const char *buff

LX>что делает #pragma pack(push,1)?
Даная прагма делает выравнивание даных побайтовое, поэтому ты смело можеш преобразовать к char *, прагма делать текущим выравнивание на границу одного байта, то есть каждое поле идёт строго одно за другим, а старое значение выравнивания, обычно 4 заталкивает в стек, прагма поп просто возвращает старое значение выравнивания. И обнулить память не забудь, а то иногда можно получить непредсказуемые результаты.

LX>а если много подобных, но разных структур, то между push и pop надо просто добавить описание этих структур?

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


LX>Я так понимаю, если есть много типов структур data1, data2, data3 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?


Если передаются разные структуры или/и разной длины то да, если же все одинаковые то не обязательно.
Re[4]: Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 13:08
Оценка:
Здравствуйте, Stoune,

а нельзя ли просто преобразовать структуру в void* а затем в char*, т.е. (char*)(void*)(struct data), где

data имеет следующую структуру:

struct {
unsigned long id;
unsigned long size;
unsigned long type;
char name[32];
char addr[16];
unsigned long p;
} data;


возможно ли вариант с #pragma push & pop перенести под линукс?
Re: Как переслать структуру с помощью сокетов
От: UrDefine Россия  
Дата: 06.04.05 13:19
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>имеется структура :


LX>struct {

LX> unsigned long id;
LX> unsigned long size;
LX> unsigned long type;
LX> char name[32];
LX> char addr[16];
LX> unsigned long p;
LX>} data;

LX>которую надо отослать серверу, а сервер, соответственно, должен ее получить, изменить полученные данные и отправить их обратно.


Если интересно, как это можно закодировать, то лучше взглянуть на примеры MSDN.

IMHO, если взглянуть на эту проблему более широко, то проблема не в пересылке структур, а в проектировании протокола связи.

Могу перечислить ряд проблем которые нужно будет решать, разрабатывая собственный протокол:

1. Выбор базисного протокола. Чаще всего TCP/IP или UDP.
2. Если используется UDP, то обеспечение гаранированной отправки и получения.
3. Обработка разрывов связи
4. Безопасность. Часто нужно шифровать данные, рулить доступом.
5. Совместимость. Если система клиент серверная, то нужно отслеживать совместимость клиента и сервера, иначе старый клиент может послать что-нибудь не то новому серверу.

Короче говоря проблем очень много, если подходить к этому глобально.
IMHO лучше не изобретать велосипед, а использовать одну из существующих технологий:
DCOM, SOAP, CORBA и тому подобные.
Каждый человек стоит столько, сколько стоит то, о чем он хлопочет.(с) Народная мудрость.
Re[2]: Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 13:30
Оценка:
Здравствуйте, UrDefine, Вы писали:

UD>Здравствуйте, LeXa-XL, Вы писали:


LX>>имеется структура :


LX>>struct {

LX>> unsigned long id;
LX>> unsigned long size;
LX>> unsigned long type;
LX>> char name[32];
LX>> char addr[16];
LX>> unsigned long p;
LX>>} data;

LX>>которую надо отослать серверу, а сервер, соответственно, должен ее получить, изменить полученные данные и отправить их обратно.


UD>Если интересно, как это можно закодировать, то лучше взглянуть на примеры MSDN.


собственно в данный момент этим и занимаюсь...

UD>IMHO, если взглянуть на эту проблему более широко, то проблема не в пересылке структур, а в проектировании протокола связи.


фактически так оно и есть

UD>Могу перечислить ряд проблем которые нужно будет решать, разрабатывая собственный протокол:


UD>1. Выбор базисного протокола. Чаще всего TCP/IP или UDP.

UD>2. Если используется UDP, то обеспечение гаранированной отправки и получения.
UD>3. Обработка разрывов связи
UD>4. Безопасность. Часто нужно шифровать данные, рулить доступом.
UD>5. Совместимость. Если система клиент серверная, то нужно отслеживать совместимость клиента и сервера, иначе старый клиент может послать что-нибудь не то новому серверу.

согласен

UD>Короче говоря проблем очень много, если подходить к этому глобально.

UD>IMHO лучше не изобретать велосипед, а использовать одну из существующих технологий:
UD>DCOM, SOAP, CORBA и тому подобные.

к сожалению нужен свой...
Re[3]: Как переслать структуру с помощью сокетов
От: UrDefine Россия  
Дата: 06.04.05 14:28
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>Здравствуйте, UrDefine, Вы писали:


UD>>Здравствуйте, LeXa-XL, Вы писали:


LX>>>имеется структура :


LX>>>struct {

LX>>> unsigned long id;
LX>>> unsigned long size;
LX>>> unsigned long type;
LX>>> char name[32];
LX>>> char addr[16];
LX>>> unsigned long p;
LX>>>} data;

LX>>>которую надо отослать серверу, а сервер, соответственно, должен ее получить, изменить полученные данные и отправить их обратно.


UD>>Если интересно, как это можно закодировать, то лучше взглянуть на примеры MSDN.


LX>собственно в данный момент этим и занимаюсь...


UD>>IMHO, если взглянуть на эту проблему более широко, то проблема не в пересылке структур, а в проектировании протокола связи.


LX>фактически так оно и есть


UD>>Могу перечислить ряд проблем которые нужно будет решать, разрабатывая собственный протокол:


UD>>1. Выбор базисного протокола. Чаще всего TCP/IP или UDP.

UD>>2. Если используется UDP, то обеспечение гаранированной отправки и получения.
UD>>3. Обработка разрывов связи
UD>>4. Безопасность. Часто нужно шифровать данные, рулить доступом.
UD>>5. Совместимость. Если система клиент серверная, то нужно отслеживать совместимость клиента и сервера, иначе старый клиент может послать что-нибудь не то новому серверу.

LX>согласен


UD>>Короче говоря проблем очень много, если подходить к этому глобально.

UD>>IMHO лучше не изобретать велосипед, а использовать одну из существующих технологий:
UD>>DCOM, SOAP, CORBA и тому подобные.

LX>к сожалению нужен свой...


Я в свое время много занимался подобными вещами. На мой взляд очень хорошо продуман
протокол FTP. Все общение просиходит в текстовом режиме по TCP/IP. Этот протокол обеспечивает гарантированную передачу. Если в течении заданного таймаута передать ничего не удалось, то соединение закрывается. Если нужно передавать какие-то данные, то для них создается отдельный сокет. По логам очень легко отследить правильность работы клиента и сервера.
Каждый человек стоит столько, сколько стоит то, о чем он хлопочет.(с) Народная мудрость.
Re[3]: Как переслать структуру с помощью сокетов
От: Odi$$ey Россия http://malgarr.blogspot.com/
Дата: 06.04.05 14:32
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>не совсем понятно как данная структура преобразуется в const char *buff


( const char* )&data

получаем адрес data и приводим к char*

LX>а если много подобных, но разных структур, то между push и pop надо просто добавить описание этих структур?


да

LX>Я так понимаю, если есть много типов структур data1, data2, data3 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?


да, заводишь структуру HEADER с двумя полями — type и len и наследуешь все DATA от нее, т.о. в начале принимаемого буфера с данными у тебя будет их тип и длина, ты смоможешь откусить от начала принятого буфера нужный кусок и скопировать его в нужную структуру.
В принципе достаточно только типа данных, для простых структур она определяет размер, длина будет необходима, если одна и таже структура может содержать массивы переменной длины.
Re[5]: Как переслать структуру с помощью сокетов
От: MaximE Великобритания  
Дата: 06.04.05 14:37
Оценка: +2
LeXa-XL wrote:

> возможно ли вариант с #pragma push & pop перенести под линукс?


Этот способ (с pragma pack) — худший из способов в плане переносимости. Да, он устранит padding между членами структуры, но для переносимости между платформами/компиляторами это лишь треть дела: еще необходимы гарантированные размеры и byte sex фундаментальных типов.

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

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[6]: Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 15:04
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>LeXa-XL wrote:


>> возможно ли вариант с #pragma push & pop перенести под линукс?


ME>Этот способ (с pragma pack) — худший из способов в плане переносимости. Да, он устранит padding между членами структуры, но для переносимости между платформами/компиляторами это лишь треть дела: еще необходимы гарантированные размеры и byte sex фундаментальных типов.


ME>В переносимом коде сереализуй свои структуры в какой либо текстовый или бинарный формат, чтобы принимающая сторона или версия твоей проги скомпилированная на другом компиляторе смогла их гарантированно прочитать.


ME>--

ME>Maxim Yegorushkin

т.е. фактически ты предлагаешь побайтно записать данные структуры struct data в отсылаемый через сокет буфер char*buf?

а как насчет варианта (char*)(void*)&data?
Re[4]: Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 15:06
Оценка:
Здравствуйте, Odi$$ey, Вы писали:

OE>Здравствуйте, LeXa-XL, Вы писали:


LX>>не совсем понятно как данная структура преобразуется в const char *buff


OE>
OE>( const char* )&data
OE>

OE>получаем адрес data и приводим к char*

LX>>а если много подобных, но разных структур, то между push и pop надо просто добавить описание этих структур?


OE>да


LX>>Я так понимаю, если есть много типов структур data1, data2, data3 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?


OE>да, заводишь структуру HEADER с двумя полями — type и len и наследуешь все DATA от нее, т.о. в начале принимаемого буфера с данными у тебя будет их тип и длина, ты смоможешь откусить от начала принятого буфера нужный кусок и скопировать его в нужную структуру.

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

мне кажется что
( const char* )&data
не будет компилироваться
щас попробую
Re[4]: Как переслать структуру с помощью сокетов
От: LeXa-XL  
Дата: 06.04.05 15:30
Оценка:
Здравствуйте, UrDefine, Вы писали:

2LeXa-XL — излишнее цитирование запрещено правилами форумов

UD>Я в свое время много занимался подобными вещами. На мой взляд очень хорошо продуман

UD>протокол FTP. Все общение просиходит в текстовом режиме по TCP/IP. Этот протокол обеспечивает гарантированную передачу. Если в течении заданного таймаута передать ничего не удалось, то соединение закрывается. Если нужно передавать какие-то данные, то для них создается отдельный сокет. По логам очень легко отследить правильность работы клиента и сервера.

т.е. стоит посмотреть работу FTP клиент-сервера ?
Re[7]: Как переслать структуру с помощью сокетов
От: MaximE Великобритания  
Дата: 06.04.05 15:38
Оценка:
LeXa-XL wrote:

> т.е. фактически ты предлагаешь побайтно записать данные структуры struct data в отсылаемый через сокет буфер char*buf?


Я предлагаю использовать какой-либо формат.

Есле тебе нужен бинарный, то можно взять XDR. XDR позаботится за тебя о правильном размере и порядке байтов фундаментальный типов. Для твоей структуры ф-ция сериализации будет выглядеть так:

bool_t xdr_data(XDR* x, data* d)
{
     char* p;
     xdr_u_long(x, &d->id);
     xdr_u_long(x, &d->size);
     xdr_u_long(x, &d->type);
     p = d->name;
     xdr_string(x, &p, sizeof(d->name));
     p = d->addr;
     xdr_string(x, &p, sizeof(d->addr));
     xdr_u_long(x, &d->p);
     return 1;
}


Объект XDR ты можешь взять готовый из библиотеки или создать собственный, который будет писать куда тебе нужно.

--
Maxim Yegorushkin
Posted via RSDN NNTP Server 1.9
Re[5]: Как переслать структуру с помощью сокетов
От: UrDefine Россия  
Дата: 07.04.05 11:17
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>Здравствуйте, UrDefine, Вы писали:




UD>>Я в свое время много занимался подобными вещами. На мой взляд очень хорошо продуман

UD>>протокол FTP. Все общение просиходит в текстовом режиме по TCP/IP. Этот протокол обеспечивает гарантированную передачу. Если в течении заданного таймаута передать ничего не удалось, то соединение закрывается. Если нужно передавать какие-то данные, то для них создается отдельный сокет. По логам очень легко отследить правильность работы клиента и сервера.

LX>т.е. стоит посмотреть работу FTP клиент-сервера ?

Очень позновательно. См. RFC 959
почитай здесь
Каждый человек стоит столько, сколько стоит то, о чем он хлопочет.(с) Народная мудрость.
Re[3]: Как переслать структуру с помощью сокетов
От: Olegator  
Дата: 07.04.05 12:23
Оценка:
Здравствуйте, LeXa-XL, Вы писали:

LX>не совсем понятно как данная структура преобразуется в const char *buff


data d;

// преобразуется не структура, а указатель на неё

// так
const char* cp = reinterpret_cast<char*>(&d);
// или так (ИМХО, более кузяво)
const char* vcp = static_cast<char*>(static_cast<void*>(&d));


LX>что делает #pragma pack(push,1)?


Это директива компилятору, указывающая в данном случае, что поля структуры data должны выравниваться по одному байту. Т.е. размер структуры будет равен сумме размеров её полей. В ином случае размер структуры был бы больше этой суммы (но за счёт этого доступ к членам осуществлялся бы быстрее).

LX>а если много подобных, но разных структур, то между push и pop надо просто добавить описание этих структур?


Ага.

LX>Я так понимаю, если есть много типов структур data1, data2, data3 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?


Да, таким образом ты создашь свой мини-протокол.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
Re[8]: Как переслать структуру с помощью сокетов
От: Stoune  
Дата: 10.04.05 20:36
Оценка:
Здравствуйте, MaximE, Вы писали:

ME>LeXa-XL wrote:


>> т.е. фактически ты предлагаешь побайтно записать данные структуры struct data в отсылаемый через сокет буфер char*buf?


ME>Я предлагаю использовать какой-либо формат.


ME>Есле тебе нужен бинарный, то можно взять XDR. XDR позаботится за тебя о правильном размере и порядке байтов фундаментальный типов. Для твоей структуры ф-ция сериализации будет выглядеть так:


ME>Объект XDR ты можешь взять готовый из библиотеки или создать собственный, который будет писать куда тебе нужно.


ME>--

ME>Maxim Yegorushkin

Вообще мне понравился подход ACE, в "Програмировании сетевых приложений на С++. Том 1" эти вопросы немного рассмотрены, реализацию некоторых вопросов, я у них подсматривал.
... << RSDN@Home 1.1.4 beta 4 rev. 303>>
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.