Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Сети > Передача структуры через сокет


Автор: Agentx86 10.12.2006, 20:39
Помогите передать и принять структуру по сети. Что надо передавать в полях данные и размер?

struct Contr {short mouse_x;            
    short mouse_y;            
    BYTE action;};         
Contr con;
send(s,(char*)&con,sizeof(Contr),0);

Автор: ptr 11.12.2006, 08:14
Цитата(Agentx86 @  10.12.2006,  23:39 Найти цитируемый пост)
Что надо передавать в полях данные и размер?

Все зависит от того как устроена программа.

Цитата(Agentx86 @  10.12.2006,  23:39 Найти цитируемый пост)
Помогите передать и принять структуру по сети.

В чём проблема то?

Автор: Agentx86 11.12.2006, 16:10
Все решил сам. Всем спасибо.

Автор: ptr 11.12.2006, 18:02
Ну тогда пометь тему как решённую.

Автор: witex 11.12.2006, 21:07
А ещё лудше покажи, как решил? мне тож интересно!

Автор: drZmeu 4.1.2007, 20:50
Да показывай. Всем интересно ;)    smile 

Автор: ptr 6.1.2007, 19:02
Господа вы меня пугаете smile .

Автор: drZmeu 6.1.2007, 19:21
 smile
Да ладно тебе ptr просто никогда не сталкивались =)))
Мне чёт кажется вот так :
struct Contr {short mouse_x;            
    short mouse_y;            
    BYTE action;};         
Contr con;
send(s,con,sizeof(con),0);
или так:
send(s,con,strlen(con),0);
 smile 
 Ну незнаю я =))) Хотя скоро пригодится =)

Автор: witex 6.1.2007, 23:29
send(s,(constr char*)&con,sizeof(Contr),0); банально! я посмотрел ещё тогда в мсдн и в купил! там же чётко написанно какой тип данных передаётся! тема старая, решённая! если автор забыл поставить галочку о том что тема решена! ненадо её поднимать! 
drZmeu , не трогой темы тарые!

Автор: Sergio 29.1.2007, 23:59
Народ помогите и мне передать структуру. Вот что я написал:

Код

struct _paket {
      char msg[50] = {"Hello world!"};
      int user = 10;
  };

_paket paket;

Потом:
Код

 send(mySocket,(char*)&paket,sizeof(paket),0); 

Какая-то ошибка smile 
И еще вопрос: как принимать структуру? Что чему присваивать?

Автор: drZmeu 26.3.2007, 23:20
Я очень извеняюсь что поднимаю старую тему!
С отправкой структуры всё понятно!
А вот с приёмом вобшем у мну такойже вопрос как и у Serqio !
И еще вопрос: как принимать структуру? Что чему присваивать?
Код

struct Contr{
char szSendSt[1024];
BYTE szByteSt;
};

К примеру я отправил такую структуру на сервер! Как сервер должен разбирать принятые данные???

Тоесть у сервера есть похожая структура:
Код

struct Bound{
    char szRecvSt[1024];
    BYTE szByteSt;
};


Как мне присвоить текст в szRecvSt и байт в szByteSt ,,,???,,, smile 
Ещё раз извеняюсь за поднятие старой темы. написал тут чтоб не создавать новую !

Автор: Dray 26.3.2007, 23:32
Не надо её отправлять целеком! Если в структуре есть сложные элементы, такие как строки, то отправлять её надо по частям, и принимать так же. А если у вас там указатели, сами ведь понимаете такое:
Код
send(s,con,sizeof(con),0);

НЕ ПРОКАТИТ!

Автор: drZmeu 27.3.2007, 09:35
>Не надо её отправлять целеком! Если в структуре есть сложные элементы, такие как строки, то >отправлять её надо по частям, и принимать так же. А если у вас там указатели, сами ведь >понимаете такое:код C++
>1:
>        send(s,con,sizeof(con),0);
>
>
>
>
>НЕ ПРОКАТИТ!

Ну я почемуто так и думал! Неудобно =\
Вопрост тогда зачем передавать структуру полностью
аля:
Код

send(s,(constr char*)&con,sizeof(Contr),0);

Если её незя принять и разсортировать??? smile 

Автор: Greeen 27.3.2007, 11:11
Цитата(drZmeu @  27.3.2007,  09:35 Найти цитируемый пост)
Если её незя принять и разсортировать???

Почему незя, можно. У тебя 1 Кб + 1 байт передаются. Вполне нормальный размер чтобы передавать его целиком. Потом получаешь (recv) и приводишь буфер к твоему типу.

Автор: ptr 28.3.2007, 15:08
Прежде чем что-либо (структуру, класс ...) передавать по сети, нужно вначале это что-то сериализовать.

Автор: drZmeu 28.3.2007, 20:40
А можно примерчик  smile 
А то у меня уже мозги закипают  smile 

Автор: leniviy 5.6.2007, 12:33
У меня вопрос. Может ли команда recv разбить принимаемую структуру на несколько частей. Например, я точно знаю, что сервер мне послал 10 байт. Может ли первый вызов recv вернуть меньше 10? Я пока от неуверенности , пользую эту функцию
Код

    int recvExactly(SOCKET s, char* buf, int len, int flags)
    {
        int result;
        char* buf1 = buf;
        while(buf1-buf < len)
        {
            result = ::recv(s, buf1, len, flags);
            if ((result==SOCKET_ERROR)||(result==0)) return result;
            buf1 += result;
            len -= result;
        }
        return (int)(buf1-buf);
    }

Автор: ptr 6.6.2007, 15:05
Да, recv возвращает только то, что пришло на данный момент. Поэтому количество байт может быть не больше того, что было затребовано.

P.S. если хочешь задать какой-нибудь вопрос, то лучше для этого создавать новую тему. Тем более что вопрос никак не связан с текущей темой.

Автор: intel 13.9.2007, 17:22
После тово как получил структуру по сокету и запихал её в буфер, хочу привести тот самый буфер к типу структуры, 
но компилятор кричит "так не пойдёт". Не пойму где я там касяк спорол

Вот кусок кода:
Код

char buf[256];

int rc = recv(s,buf,sizeof(buf),0);

if( rc <= 0 )
    cout<<"recv error"<<endl;

else
    cout<<((Data)buf).x;

А вот мой тип (подключаю в голове):
Код

class Data {
    public:
        int x;
        int y;
};

Спасибо

Автор: leniviy 14.9.2007, 08:52
((Data*)&buf)->x

Автор: intel 14.9.2007, 13:16
Спасибо leniviy, всё получилось

Автор: intel 17.9.2007, 20:25
Вот ещё небольшая проблемка.

по сокету отправляю структуру в сторону клиента, но тот ничего не получает, хотя блок else  выполняется. 
В структуре int и указатель на char. 

Вообщем вот кусок от server'а:
Код

Message myMessage;
myMessage.messageType   = REGISTER;
myMessage._message      = "hallo\0";

int rs = send(client[i],(const char*)&myMessage,sizeof(myMessage),0);


А вот от клиента:
Код

char buf[256];

if( rr <= 0 )
    cout<<"recv error"<<endl;

else {
    cout<<"recv OK"<<endl;
    buf[rr] = '\0';
    cout<<((Message*)&buf)->_message;
}

Ну и моя структура до кучи:
Код

struct Message {
    char *_message;
    int messageType;
};

Вот что выходит на консоль (у клента):
Код

Connect OK
Recv OK


Сдаётся мне там чтото с char'ом не то...

Автор: dumb 17.9.2007, 23:23
Цитата(intel @  17.9.2007,  21:25 Найти цитируемый пост)
Сдаётся мне там чтото с char'ом не то...
правильно сдается - ты пересылаешь указатель на строку, а не саму строку.

структура должна быть примерно такого вида:
Код

#pragma pack(push,1)
struct Message {
    int messageType;
    int messageLen;
    char _message[0];
};
#pragma pack(pop)
...
// пример подготовки и отсылки
char s[] = "hallo";
int len=strlen(s);
Message *msg = (Message*)new char[sizeof(Message)+len+1];
msg->messageType = 0;
msg->messageLen = len;
strcpy(msg->_message, s)
send(client[i],(const char*)msg, sizeof(Message)+len+1,0);
delete[] (char*)msg;
...


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

Автор: intel 18.9.2007, 22:02
Спасибо dumb, скопировал твой предложенный вариант, заработало как по маслу, 
вот тока не въеду што значят #pragma pack(push,1) и #pragma pack(pop)? 
В гугле ничево не нарыл, поясни если не затруднит

Автор: Artemon 19.9.2007, 13:01
Все так весело передают структуры по сокетам, даже не задумываясь о выравнивании струкуры в памяти.

Только лишь dumb не стал этим принебрегать (на то он и эксперт).

#pragma pack(push,1) - отменяет выравнивание.

Автор: mrbrooks 20.9.2007, 15:14
Комрады если уж сыр - бор про передачу инфы через сокеты - то как насчет юзанья структуры WSANETWORKEVENTS. А именно что бы сохранить инфу от сервера на клиенте скажим хотя бы в файл. Кто нибудь посоветует что нибудь? Пжаста!

Автор: dumb 20.9.2007, 23:13
Цитата(mrbrooks @  20.9.2007,  16:14 Найти цитируемый пост)
как насчет юзанья структуры WSANETWORKEVENTS. А именно что бы сохранить инфу от сервера на клиенте скажим хотя бы в файл.
какая связь между словами в этих предложениях?

Автор: mrbrooks 21.9.2007, 08:17
Цитата(dumb @ 20.9.2007,  23:13)
какая связь между словами в этих предложениях?

TCP/IP

Автор: Skladnoy 21.9.2007, 13:43
Цитата(Artemon @  19.9.2007,  13:01 Найти цитируемый пост)
Все так весело передают структуры по сокетам, даже не задумываясь о выравнивании струкуры в памяти.

А еще int может иметь разный размер, разную endianness... Вообще говоря.

Автор: BasilL 12.12.2008, 23:10
Приветствую!
Не стал создавать новую тему - спрошу здесь

имеем структуру
Код

struct Message
    {
            AnsiString MsgType;
            AnsiString MsgIP;
            AnsiString MsgText;
    };
Message MsgRecv;
Message MsgSend;


передаем
Код

MsgSend.MsgType = "0004";
MsgSend.MsgIP = inet_ntoa(new_sa.sin_addr);
MsgSend.MsgText = MsgText_;
int length = MsgSend.MsgType.Length() + MsgSend.MsgIP.Length() + MsgSend.MsgText.Length() + 1;
if (SOCKET_ERROR == (send(clnt.socket, (const char*)&MsgSend, length, 0 ) ) )
{
// Error...
int error = WSAGetLastError();
ErrorMessage(error);      // ...
// ...
}


принимаем
Код

ret = recv(wParam, (char*)&MsgRecv, 1024, 0); // 1024 - макс. размер


все передается и принимаеться нормально. Но далее происходит вот что
Код

if (MsgRecv.MsgType == "0100")
{
// обработка
}

Как только выполнение программы приходит на строку с if ((MsgRecv.MsgType) == "0100") условие срабатывает... Хотя в принятом MsgRecv.MsgType = "0004"... Смотрю в отладчике - да, все принимается ок, MsgType = "0004". Программа переходит на строку с проверкой условия - и MsgType становится равно "0100".... Пробовал менять значения в условии - что бы ни поставил, всегда MsgType становится равным ему... Как будто в if-е не "==" стоит, а "="....
В чем может быть дело?

Автор: leniviy 13.12.2008, 01:09
имхо нельзя передавать борландовские строки через сокет. В дельфях это встроенный тип, в C++ скорее всего смарт поинтер, указатель на данные. А сами данные строки находятся в другой области памяти и не передаются.
Код

ret = recv(wParam, (char*)&MsgRecv, 1024, 0); // 1024 - макс. размер

здесь явное нарушение безопасности типов. Странно, что потом не выскакивает Access violation, но ничего, потом выскочит smile.

Хотите передать 3 строки за раз, придётся сначала перевести строки в char* , PChar или PAnsiChar
потом скопировать все 3 строки друг за другом в 1 блок памяти и передавать этот блок целиком.
С помощью "C" структур так сделать нельзя, потому что только последнее поле структуры может иметь вариабельный размер.

Я бы сделал по-другому, написал 2 функции:
sendMessage() и recvMessage() похожие на send() и recv() , только вместо аргументов buf и length аргумент типа Message.

внутри этих функций 3 раза (для MsgType,MsgIP и MsgText) вызываются соответственно sendString() и recvString()

в sendString()  в сокет сначала посылаете 4 байта (длину строки ) потом данные типа Pchar
в recvSring()  из сокета сначала читаете 4 байта (длину строки , len ) потом !в цикле! читаете в буфер типа PChar и не забывайте, что может понадобиться несколько вызовов recv, чтобы прочитать всю строку. Выставляете нолик в последнем байте буфера (buf[len]) и конвертируете PChar обратно в AnsiString

Автор: BasilL 13.12.2008, 10:00
leniviy,
т.е. если я правильно понял - возможен такой вариант решения: изменить структуру Message так, чтобы только последнее поле имело непостоянный размер, например так

Код

struct Message
{
BYTE MsgType;    // или WORD MsgType
u_long MsgIP;    //u_long S_addr;
AnsiString MsgText;
}


на крайняк, можно и последнее поле запихнуть в какойнить char[256]... но не хотелось бы

Верна идея? 

Автор: leniviy 13.12.2008, 11:16
Цитата(BasilL @ 13.12.2008,  10:00)
Код

struct Message
{
BYTE MsgType;    // или WORD MsgType
u_long MsgIP;    //u_long S_addr;
AnsiString MsgText;
}


Всё равно одновременное использование 
AnsiString как поля структуры + 
Код

send(clnt.socket, (const char*)&MsgSend, length, 0 )

не сработает.

можно так:
Код

struct Message
{
BYTE MsgType;    // или WORD MsgType
u_long MsgIP;    //u_long S_addr;
u_long MsgText_len;
char MsgText[];
}


но тогда надо и другие части проги менять: 

Код

Message *pMsgSend
Message *pMsgRecv;
...
AnsiString MsgText;
MsgText = ...
...
pMsgSend = (Message *)malloc(sizeof(Message)+length(MsgText));
pMsgSend->MsgIP = ...
pMsgSend->MsgType = ...
pMsgSend->MsgText_len = length(MsgText);
strncpy(pMsgSend->MsgText,PChar(MsgText),length(MsgText));
...
send(clnt.socket, (const char*)&pMsgSend, sizeof(Message)+pMsgSend->MsgText_len, 0 )



Сложно? Конечно. Потому лучше сделайте, как я посоветовал в пред. посте.
Оставьте структуру, как была, но напишите 2 функции для передачи/приёма такой структуры и 2 функции для передачи/приёма AnsiString

Автор: BasilL 13.12.2008, 12:22
leniviy, спс за советы... у самого есть еще пара мыслей - на выходных поковыряю ))

Автор: J0ker 13.12.2008, 17:05
Цитата(leniviy @  13.12.2008,  01:09 Найти цитируемый пост)
в C++ скорее всего смарт поинтер

скорее класс-оболочка над char массивом

Цитата(leniviy @  13.12.2008,  01:09 Найти цитируемый пост)
здесь явное нарушение безопасности типов

а как иначе вы предлагаете использовать recv?
другой вопрос в несоответствии кол-ва принимаемых данныы размерам структуры

Цитата(leniviy @  13.12.2008,  11:16 Найти цитируемый пост)
char MsgText[];

в C++ массивы нулевой длины не разрешены

Автор: leniviy 13.12.2008, 17:55
Цитата(J0ker @  13.12.2008,  17:05 Найти цитируемый пост)
в C++ массивы нулевой длины не разрешены 

У меня нет с++ билдера, я не мог проверить.
В VS просто выскакивает 
Код

Warning    1    warning C4200: nonstandard extension used : zero-sized array in struct/union...


Автор: J0ker 13.12.2008, 18:48
Цитата(leniviy @ 13.12.2008,  17:55)
Цитата(J0ker @  13.12.2008,  17:05 Найти цитируемый пост)
в C++ массивы нулевой длины не разрешены 

У меня нет с++ билдера, я не мог проверить.
В VS просто выскакивает 
Код

Warning    1    warning C4200: nonstandard extension used : zero-sized array in struct/union...

это не имеет отношения к конкретному компилятору
отступление от стандарта - потенциальный баг

Автор: Alca 19.12.2008, 13:19
http://www.codeguru.com/forum/showthread.php?t=306399

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)