Pergunta

Eu tenho um programa de cliente e servidor, onde quero enviar uma estrutura inteira do cliente e, em seguida, produzir o "ID" do membro da estrutura no servidor.

Eu fiz toda a conexão etc e já consegui enviar uma string através de:

send(socket, string, string_size, 0);

Então, é possível enviar uma estrutura em vez de uma string através de send ()? Posso apenas substituir meu buffer no servidor para ser uma estrutura vazia do mesmo tipo e ir?

Foi útil?

Solução

Bem ... enviar estruturas através da rede é meio difícil se você estiver fazendo isso corretamente.

Carl está certo - você pode enviar uma estrutura através de uma rede dizendo:

send(socket, (char*)my_struct, sizeof(my_struct), 0);

Mas aqui está a coisa:

  • sizeof (my_struct) pode mudar entre o cliente e o servidor. Os compiladores geralmente fazem uma quantidade de preenchimento e alinhamento; portanto, a menos que você defina o alinhamento explicitamente (talvez usando um pacote #Pragma ()), esse tamanho pode ser diferente.
  • O outro problema tende a ser uma ordem de bytes. Algumas máquinas são grandes e outras são pouco endianas, portanto o arranjo dos bytes pode ser diferente. Na realidade, a menos que seu servidor ou cliente esteja em execução em hardware não-Intel (o que provavelmente não é o caso), esse problema existe mais em teoria do que na prática.

Portanto, a solução que as pessoas geralmente propõem é ter uma rotina que serialize a estrutura. Ou seja, ele envia o membro do Struct One Data por vez, garantindo que o cliente e o servidor enviem apenas () e recv () o número exato especificado de bytes que você codifica em seu programa.

Outras dicas

As máquinas de cliente e servidor são "iguais"? O que você está propondo só funcionará se os compiladores C em cada extremidade estabelecerem a estrutura na memória exatamente a mesma. Existem muitas razões pelas quais esse pode não ser o caso. Por exemplo, os Macines do cliente e do servidor podem ter arquiteturas diferentes, a maneira como eles representam números na memória (Big-Endian, Little-Endian) podem diferir. Mesmo que as máquinas dos clientes e a máquina do servidor tenham a mesma arquitetura, dois compiladores C diferentes podem ter políticas diferentes para como eles estabelecem estruturas na memória (por exemplo, preenchimento entre os campos para alinhar o INTS nos limites do Word). Mesmo o mesmo Conmpiler com sinalizadores diferentes pode fornecer resultados diferentes.

Pragmaticamente, acho que seu cliente e servidor são o mesmo tipo de máquina e, portanto, o que você está propondo funcionará, mas você precisa estar ciente de que, como regra geral , ou por que as pessoas usam alguma representação geral, como o XML.

Você pode, se o cliente e o servidor estabeleceram a estrutura exatamente da mesma maneira, o que significa que os campos têm o mesmo tamanho, com o mesmo preenchimento. Por exemplo, se você tem um long Na sua estrutura, isso pode ser de 32 bits em uma máquina e 64 bits, por outro lado, caso em que a estrutura não será recebida corretamente.

No seu caso, se o cliente e o servidor sempre estarão em implementações C muito semelhantes (por exemplo, se esse for apenas um código que você está usando para aprender alguns conceitos básicos ou se por algum outro motivo você sabe que seu código será apenas Sempre tiver que executar sua versão atual do OSX), provavelmente você pode se safar. Lembre-se de que seu código não funcionará necessariamente corretamente em outras plataformas e que há mais trabalho a fazer antes de ser adequado para uso na maioria das situações do mundo real.

Para a maioria dos aplicativos cliente-servidor, isso significa que a resposta é que você não pode fazê-lo em geral. O que você realmente faz é definir a mensagem em termos do número de bytes enviados, que ordem, o que eles significam e assim por diante. Em cada extremidade, você faz algo específico da plataforma para garantir que a estrutura que você está usando possui exatamente o layout necessário. Mesmo assim, você pode ter que trocar de byte se estiver enviando membros inteiros da Struct Little-Endian e, em seguida, deseja que seu código seja executado em uma máquina Big-Endian. Os formatos de intercâmbio de dados como os buffers de protocolo XML, JSON e Google existem para que você não precise fazer isso complicado.

Editar: Lembre -se também, é claro, que alguns membros da estrutura nunca podem ser enviados sobre o fio. Por exemplo, se sua estrutura tiver um ponteiro, o endereço refere -se à memória na máquina de envio e é inútil na extremidade de recebimento. Desculpas se isso já é óbvio para você, mas certamente não é óbvio para todos quando estão apenas começando com c].

Você pode, mas precisa estar ciente de duas coisas importantes.

  1. Os programas em ambas as extremidades têm que ser Abi compatível. Eles geralmente são se as duas extremidades são executadas na mesma arquitetura do processador, o mesmo sistema operacional, compilado com o mesmo compilador e sinalizadores do compilador.
  2. TCP é um fluxo. Você precisa ter certeza de que está enviando toda a estrutura. Veja a documentação para a chamada send () - ele retorna o NR de bytes enviados - que pode ser menor do que você disse. O mesmo no lado do receptor. Só porque você enviou a estrutura com 1 chamada, não significa que você a receberá com 1 chamada RECV. Faça com que faça várias chamadas de RECV para obter todas as peças.

Sim, estruturas do mesmo tipo são do mesmo tamanho. Se você acertar seu ponteiro, está pronto para ir.

Em geral, é uma má idéia fazer isso, mesmo que seu cliente e seu servidor apareçam para estabelecer a estrutura na memória da mesma maneira.

Mesmo se você não pretende passar estruturas de dados mais complexas (que envolvam ponteiros) de um lado para o outro, recomendo que você serialize seus dados antes de enviá -los pela rede.

Envie os dados como arquivo de texto e decodifique -o depois de recebê -los. Esta é a melhor maneira se você deseja que seus dados sejam enviados !!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top