Здравствуйте, 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;
}
если данные могут пересылаться разные, а не только data, то придется к эту структуру предварять заголовком — тип данных, размер пакета.
Ну и прием соответственно — recv в буфер, потом смотришь, что принял не меньше sizeof(data), если если меньше, снова на recv, когда придет все — memcpy в data на этой стороне.
Здравствуйте, 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>
можно немного по подробнее о : #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 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?
Здравствуйте, 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 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?
Если передаются разные структуры или/и разной длины то да, если же все одинаковые то не обязательно.
Здравствуйте, 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 и тому подобные.
Каждый человек стоит столько, сколько стоит то, о чем он хлопочет.(с) Народная мудрость.
Здравствуйте, 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 и тому подобные.
Здравствуйте, 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. Этот протокол обеспечивает гарантированную передачу. Если в течении заданного таймаута передать ничего не удалось, то соединение закрывается. Если нужно передавать какие-то данные, то для них создается отдельный сокет. По логам очень легко отследить правильность работы клиента и сервера.
Каждый человек стоит столько, сколько стоит то, о чем он хлопочет.(с) Народная мудрость.
Здравствуйте, LeXa-XL, Вы писали:
LX>не совсем понятно как данная структура преобразуется в const char *buff
( const char* )&data
получаем адрес data и приводим к char*
LX>а если много подобных, но разных структур, то между push и pop надо просто добавить описание этих структур?
да
LX>Я так понимаю, если есть много типов структур data1, data2, data3 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?
да, заводишь структуру HEADER с двумя полями — type и len и наследуешь все DATA от нее, т.о. в начале принимаемого буфера с данными у тебя будет их тип и длина, ты смоможешь откусить от начала принятого буфера нужный кусок и скопировать его в нужную структуру.
В принципе достаточно только типа данных, для простых структур она определяет размер, длина будет необходима, если одна и таже структура может содержать массивы переменной длины.
LeXa-XL wrote:
> возможно ли вариант с #pragma push & pop перенести под линукс?
Этот способ (с pragma pack) — худший из способов в плане переносимости. Да, он устранит padding между членами структуры, но для переносимости между платформами/компиляторами это лишь треть дела: еще необходимы гарантированные размеры и byte sex фундаментальных типов.
В переносимом коде сереализуй свои структуры в какой либо текстовый или бинарный формат, чтобы принимающая сторона или версия твоей проги скомпилированная на другом компиляторе смогла их гарантированно прочитать.
Здравствуйте, MaximE, Вы писали:
ME>LeXa-XL wrote:
>> возможно ли вариант с #pragma push & pop перенести под линукс?
ME>Этот способ (с pragma pack) — худший из способов в плане переносимости. Да, он устранит padding между членами структуры, но для переносимости между платформами/компиляторами это лишь треть дела: еще необходимы гарантированные размеры и byte sex фундаментальных типов.
ME>В переносимом коде сереализуй свои структуры в какой либо текстовый или бинарный формат, чтобы принимающая сторона или версия твоей проги скомпилированная на другом компиляторе смогла их гарантированно прочитать.
ME>-- ME>Maxim Yegorushkin
т.е. фактически ты предлагаешь побайтно записать данные структуры struct data в отсылаемый через сокет буфер char*buf?
Здравствуйте, 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>В принципе достаточно только типа данных, для простых структур она определяет размер, длина будет необходима, если одна и таже структура может содержать массивы переменной длины.
UD>Я в свое время много занимался подобными вещами. На мой взляд очень хорошо продуман UD>протокол FTP. Все общение просиходит в текстовом режиме по TCP/IP. Этот протокол обеспечивает гарантированную передачу. Если в течении заданного таймаута передать ничего не удалось, то соединение закрывается. Если нужно передавать какие-то данные, то для них создается отдельный сокет. По логам очень легко отследить правильность работы клиента и сервера.
LeXa-XL wrote:
> т.е. фактически ты предлагаешь побайтно записать данные структуры struct data в отсылаемый через сокет буфер char*buf?
Я предлагаю использовать какой-либо формат.
Есле тебе нужен бинарный, то можно взять XDR. XDR позаботится за тебя о правильном размере и порядке байтов фундаментальный типов. Для твоей структуры ф-ция сериализации будет выглядеть так:
Здравствуйте, LeXa-XL, Вы писали:
LX>Здравствуйте, UrDefine, Вы писали:
UD>>Я в свое время много занимался подобными вещами. На мой взляд очень хорошо продуман UD>>протокол FTP. Все общение просиходит в текстовом режиме по TCP/IP. Этот протокол обеспечивает гарантированную передачу. Если в течении заданного таймаута передать ничего не удалось, то соединение закрывается. Если нужно передавать какие-то данные, то для них создается отдельный сокет. По логам очень легко отследить правильность работы клиента и сервера.
LX>т.е. стоит посмотреть работу FTP клиент-сервера ?
Очень позновательно. См. RFC 959 почитай здесь
Каждый человек стоит столько, сколько стоит то, о чем он хлопочет.(с) Народная мудрость.
Здравствуйте, 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 и т.д., то необходимо добавить в каждую из них дополнительную информацию о типе данных и размере всей структуры, чтобы принимающая сторона могла успешно их идентифицировать?
Здравствуйте, MaximE, Вы писали:
ME>LeXa-XL wrote:
>> т.е. фактически ты предлагаешь побайтно записать данные структуры struct data в отсылаемый через сокет буфер char*buf?
ME>Я предлагаю использовать какой-либо формат.
ME>Есле тебе нужен бинарный, то можно взять XDR. XDR позаботится за тебя о правильном размере и порядке байтов фундаментальный типов. Для твоей структуры ф-ция сериализации будет выглядеть так:
ME>Объект XDR ты можешь взять готовый из библиотеки или создать собственный, который будет писать куда тебе нужно.
ME>-- ME>Maxim Yegorushkin
Вообще мне понравился подход ACE, в "Програмировании сетевых приложений на С++. Том 1" эти вопросы немного рассмотрены, реализацию некоторых вопросов, я у них подсматривал.