Ir ao conteúdo

Como usar Sockets em Visual C++?


Pulllga

Posts recomendados

Postado

Olá, sou o Pulllga,

Preciso implementar uma função de e-mail em um software feito em você++, mas não sei como usar os sockets!!!

Onde declaro eles?

Como declaro eles??

Como faço isso sem o componente, em tempo de execução???

Como façõ o link dele??

valeu T+ :D:D:D

Postado

Olá, será que ninguém poderá me ajudar???

Eu tenho todo o código base pronto, falta só colocar os sockets no lugar do winsock!!!

Help, alguém me ajude!!!

T+ :D:D:D

  • Membro VIP
Postado

Se estiver usando o C++/CLI os sockets podem ser instanciados em tempo de execução assim:


System::Net::Sockets::TcpClient ^ sck = gcnew System::Net::Sockets::TcpClient("localhost", 1234);
System::Net::Sockets::NetworkStream ^ io = sck->GetStream();
int i = io->ReadByte();
//Funções de ler e escrever Read(), ReadByte(), Write(), WriteByte()
sck->Close();

Muda a porta e o hostname para o mais adequado e depois é só seguir o protocolo.

ps: Por que não usa uma classe especifica para enviar e-mails?

Postado

Olá EduardoS,

Não quero usar nada especifico porque além do e-mail eu preciso utilizar os sockets para conectar a um dispositivo via rede e fazer shutdown remoto!!!

Brigadão, de tarde vou testar.

T+ :D:D:D

Postado

Olá EduardoS,

Beleza, consegui inicializar o socket, só tem um problema!!!

O sck é o socket em si correto? O io é exatamente o que???

Eu preciso ler strings, uso o Read(), mas o que que é um "unsigned char"? Não sei como preencher o requisitos do Read! Eu sei que os dois últimos são int, o offset deve ser onde começa a leitura, e o size é o tamanho, e o buffer é que tipo de variável?

Mais um detalhe, como faço verificação de erros com o socket? Porque se eu tentar criar ele em tempo de execução e não houver comunicação o programa fecha!

Eu tentei isso:


if(System::Net::Sockets::TcpClient ^ serSoc = gcnew System::Net::Sockets::TcpClient("192.168.1.254", 254)){
      System::Net::Sockets::NetworkStream ^ serDat = serSoc->GetStream();
      }

Mas também não funciona!!! Estou pesquisando sobre o read, mas não consigo achar nada claro o suficiente para sanar minhas dúvidas.

Alguém ai sabe algum site que contenha as descrições de cada função com sockets? Ou pelo menos com as principais funções

T+

Obrigado pela atenção... :D:D:D

  • Membro VIP
Postado

O "io" é o stream de dados, só uma classe com as funções para enviar (write) e receber (read) dados do socket.

A função Read() funciona assim:


array<Byte> ^ buffer = gcnew array<Byte>(20);
int i = io->Read(buffer, 0, 20);

Os dois ultimos você entendeu bem, o primeiro é um buffer que vai receber os dados, ele deve ser uma array gerenciada de bytes (do jeito que eu fiz ai em cima), o tamanho deve ser quantos bytes você quer ler por vez (no exemplo o 20 da primeira linha).

Quanto aos erros use o try...catch, um exemplo com tudo o citado acima:


System::Net::Sockets::TcpClient ^ sck;
try
{
     sck = gcnew System::Net::Sockets::TcpClient("localhost", 1234);
     System::Net::Sockets::NetworkStream ^ io = sck->GetStream();
     array<Byte> ^ buffer;
                     buffer = gcnew array<Byte>(20);
     int i = io->Read(buffer, 1, 20);
     //...
     sck->Close();
}
catch(Exception ^ ex)
{
     //seu tratamente de erros
}

Ah, as funções principais são essas, de interessante ainda tem as funções assincronas, mas que podem complicar bastante.

Postado

Olá,

Como envio dados???

Reparei que é mais ou menos parecido com o Read, uso o Write com o buffer, o mesmo tipo de buffer do Read, com indice e tamanho.

Mas como mando os dados pra dentro do buffer pra mandar pelo Write???

Eu preciso pegar o ascii de cada char da string???

Dessa forma, como se eu quisese enviar a palavra gato:


gato
1234

Copio o g em código ascii para o indice 1 do buffi, depois o a em ascii para o indice 2 do buffi e assim por diante.

Depois mando o buffi para o write com o indice 1 e o comprimento em 4.

É isso???

Só mais um detalhe, como converter para o código ascii???

valeu, T+ :D :D :D

  • Membro VIP
Postado

Você pode criar um buffer a partir de uma string assim:


buffer = System::Text::Encoding::ASCII->GetBytes(L"teste");

Use buffer.Length para saber o tamanho atual do buffer, talvez seja necessário chamar o método Flush() no IO para efetivamente enviar os bytes.

Postado

Olá EduardoS,

Você está sendo um professor pra mim!!!

Beleza, já consigo criar os objetos, as varíaveis, enviar e receber dados, mas como posso saber quando ler um dador???

O equipamento onde conecto é bem lento, ainda mais que existe um conversor serial/tcp-ip, ai ele demora para responder, eu precisaria ficar esperando o momento que ele envia os dados para capturá-los, no VB o Winsock tem o evento DataArrival, tem algo semelhante que eu possa fazer aqui???

Thank you, :D :D :D

  • Membro VIP
Postado

Se eu me lembro bem... A função ReadByte() no io vai esperar algum byte chegar no socket, e a BeginReadByte() vai chamar um callback quando isso ocorrer(parecido com um evento), a ultima é mais complicada de usar e nem sempre a mais indicada, depende da sua aplicação, pesquise sobre as funções assincronas na net, tem muita coisa.

Postado

Olá de novo, já estou me enchendo, coisa mais chata esse socket sem eventos!!!

Esse é o meu código:


1 try{
2  System::Net::Sockets::TcpClient ^ serSoc = gcnew System::Net::Sockets::TcpClient("192.168.1.254", 254);
3  System::Net::Sockets::NetworkStream ^ serDat = serSoc->GetStream();
4  buffWri= System::Text::Encoding::ASCII->GetBytes(L"log1" + Environment::NewLine);
5  serDat->Write(buffWri,1,0);
6  try{
7     serDat->Read(buffRea,1,0);
8     }
9  catch(Exception ^ex){
10    buffRea = System::Text::Encoding::ASCII->GetBytes(L"&&");
11    }
12    while(serDat->DataAvailable == false){
13       }
14    serDat->Read(buffRea,1,0);
15    }
16 catch(Exception ^e){
17 MessageBox::Show("Sem comunicação em Rede!!! " + e->Message);
18 }

serSoc = Socket;

serDat = Stream de Dados;

buffWri = Buffer de escrita (enviar);

buffRea = Buffer de leitura (receber);

Eu tento enviar o '"log1" + Environment::NewLine' mas não acontece nada, o dispositivo não recebe nenhum dado, o programa não dá erro e o programa não recebe nada!!!

O equipamento precisa receber o log1 seguido do código de nova linha ou enter, no VB eu usava o "socket.send("log1" + chr(13))" o que no você++ é equivalente a "socket->Write("log1" + Convert::ToChar(13))".

Também podia fazer assim "socket.send("log1" + vbCrLF)" e equivalente no você++ "socket->Write("log1" + Environment::NewLine)".

Mas não sei se há algo de errado, porque no momento que o equipamento recebesse esse comando ele deveria retornar uma frase pedindo senha, mas não retorna nada, sinal de que ou ele não recebeu o "log1" ou então não foi enviado no formato que ele reconhece!!!

Esqueci de falar, faltou isso dentro do while:


System::Windows::Forms::Application::DoEvents();

Senão ele entra em loop infinito e não executa o resto das funções!!!

Alguém sabe o que há de errado???

valeu T+ :wacko::wacko::wacko:

  • Membro VIP
Postado

Ha alguns erros no seu código, tente:


try{
2  System::Net::Sockets::TcpClient ^ serSoc = gcnew System::Net::Sockets::TcpClient("192.168.1.254", 254);
3  System::Net::Sockets::NetworkStream ^ serDat = serSoc->GetStream();
4  buffWri= System::Text::Encoding::ASCII->GetBytes(L"log1" + Environment::NewLine);
5  serDat->Write(buffWri,0,buffWri->Length);
12    while(serDat->DataAvailable == false){//
13       }//
14    serDat->Read(buffRea,0,n);//ver comentario abaixo
15    }
16 catch(Exception ^e){
17 MessageBox::Show("Sem comunicação em Rede!!! " + e->Message);
18 }

O método Read() vai esperar até que existam n bytes (o terceiro parâmetro) disponíveis para leitura e então grava-los no buffer, assim se você tentar ler um buffer com o tamanho da string que espera receber fica fácil de controlar depois, o while(serDat->DataAvailable == false) provavelmente não tera o resultado esperado.

Postado

Olá,

Entendi, mas o problema é que eu não sei quantos dados vou receber, as vezes podem variar para mais e para menos!!!

E como a transmissão dos dados é feita entre no-break e pc, o cabo de rede sai de trás do no-break e passa por perto dele até chegar no ponto, nesse meio tempo, os dados podem sofrer interferência eletro-magnética ou de rádio frequência (EMI - RF), e com isso, entre os dados aparece "sujeira", caracteres aleatórios, as vezes poucos e as vezes muitos!!!

Então, se eu tentar ler um número x de dados, pode acontecer de haver mais ou menos do que o especificado, o que geraria erros, ou caracteres a mais devido EMI/RF, por isso o software recebe todos os dados, mesmo os caracteres a mais e depois filtra tudo!!!

Eu resolvi então fazer um laço while e pegar caracter por caracter, pego um, trato e concateno, pego outro, trato e concateno até esvaziar o stream.

Mas a condição do while deveria ser do tipo "while(qtd_de_dados_do_buffer > 0)", ai eu pego um e depois outro e outro até o buffer do stream ficar vazio.

Mas estou com uma cruel dúvida!!!

O stream sempre está vazio! Será que é porque o Write não enviou? Será que é porque o Read não tem nada para ler? Como posso testar o socket para saber se recebeu algum dado?

As formas de verificação que me passou não deram certo.

falou, T+ :D :D :D

  • Membro VIP
Postado

O buffer do socket tem um comportamento meio maluco mesmo, não confie nele.

Para ler um número indeterminado de bytes recomendo que você use o ReadByte()


int i;
String ^s = L"";
while((i = io->ReadByte()) != -1)
{
    Char c = (Char) i;
    s += c;
    //tudo o que foi lido até agora esta na variavel s, coloque a rotina aqui para comparar com algo esperado.
}

  • 2 semanas depois...
Postado

Olá, incrementei o código:


buffWri = System::Text::Encoding::ASCII->GetBytes(L"");
buffRea->Empty;
buffTmp = System::Text::Encoding::ASCII->GetBytes(L"");
try{
   System::Net::Sockets::TcpClient ^ serSoc = gcnew System::Net::Sockets::TcpClient("192.168.1.254", 254);
   System::Net::Sockets::NetworkStream ^ serDat = serSoc->GetStream();
   buffWri= System::Text::Encoding::ASCII->GetBytes(L"log1" + Convert::ToChar(13));
   serDat->Write(buffWri,0,buffWri->Length);
   serDat = serSoc->GetStream();
   try{
      while(serSoc->Available != 0){
         while((i = serDat->ReadByte()) > 0){
            Char c = (Char) i;
            buffRea += c;
            }
         if(buffRea->Contains("senha:")){
            buffWri = System::Text::Encoding::ASCII->GetBytes(L"password" + Convert::ToChar(13));
            serDat->Write(buffWri,0,buffWri->Length);
            }
         }
      }
   catch(Exception ^ex){
      //buffRea = "&&";
      //MessageBox::Show("Buffer Vazio!!! " + ex->Message);
      }
   }
catch(Exception ^e){
   MessageBox::Show("Sem comunicação em Rede!!! " + e->Message);
   }

//Exibe o programa
frmPri::Show();

Acho que as variáveis já estão compreensiveis o suficiente.

O problema é na linha do "buffRea += c;", quando acabam os bytes, ele simplesmente sai e pula para o "catch(Exception ^ex){" e depois para o "frmPri::Show();", ai não executa o if de comparação para enviar o password!!!

Alguém sabe porque???

Grato desde já, t+ :D :D :D

  • Membro VIP
Postado

Veja qual erro da, facilita bastante.

Vendo o código ha alguns erros que podem ocorrer:

while(serSoc->Available != 0){//Esse Avaliable é desnecessário é pode causar erros, prefiro o "i == -1" para saber que fechou a conexão.

while((i = serDat->ReadByte()) > 0){//o ReadByte() retornara -1 se fechar a conexão.

Char c = (Char) i; // se for -1 vai dar erro de conversão

buffRea += c;

}

if(buffRea->Contains("senha:")){//limpe o buffer dentro desse if, se não ele sempre vai entrar aqui

buffWri = System::Text::Encoding::ASCII->GetBytes(L"password" + Convert::ToChar(13));

serDat->Write(buffWri,0,buffWri->Length);//ele pode tentar executar esse write mesmo que i seja -1 (conexão fechada) e ai vai dar erro.

}

}

Postado

Olá EduardoS,

Conferi tudo como me disse e consigo comunicar perfeitamente, o problema agora, é com fechar os sockets!!!

Me parece que com o Close() ele não encerra perfeitamente a conexão.

Depois de algumas vezes conectando e desconectando, eu não consigo abrir ou manter uma conexão perfeitamente!!!

Eu vi o EndConnect, mas não consigo utilizar, não sei os parametros e não achei nada falando sobre os parametros, só código completo, montado.

Saberia me ajudar a desconectar, fechar a conexão e acabar de vez com o socket, para ter tudo livre para a próxima conexão???

valeu T+ :D :D :D

Postado

Olá EduardoS,

Pois então, eu usei o serSoc->Close();

Mas parece que depois de algumas vezes ele começa a dar erro, é como se o socket continuasse aberto no Windows!!!

Não tem outro método???

Eu quero fechar o socket e descarregar da memória, posso usar o close, tudo bem, mas como descarrego da memória? Eu criei ele via código, como elimino ele via código?

Eu tenho outro problema também, criei o socket, fiz a conexão, fechei, tudo dentro do Load do Form.

Se tento criar o socket dentro de uma função eu consigo, mas o objeto serSoc não foi declarado!!!

Eu crio o socket (serSoc), envio dados, gravo no buffer de leitura e preciso logo após fazer uma verificação do serSoc->Connected, nesse ponto ele diz que o objeto não foi declarado!!!

Porque não consigo criar o socket em outro lugar fora o evento Load???

Valeu, t+ :D :D :D

Obs.: Dá uma olhada no post sobre jogos, de repente pode dar alguma dica em C pro pessoal lá.

  • Membro VIP
Postado

Preste atenção no escopo, você não poderá usar algo que foi declarado fora do escopo, para fechar use o Close do stream e depois o Close do socket...

ps: Só usei sockets com o .Net 1.1, a princípio não mudou nada, nesse fim de semana eu confiro...

Postado

Olá EduardoS,

Acho que não me compreendeu direito, eu declarei o socket no Load e depois fechei a conexão com o Close, na função eu declarei de novo outro socket com o mesmo nome e aceitou, o stream funciona, mas não as funções e propriedades associadas ao socket, como o socket->Available por exemplo!

Porque quando declaro no Load funciona e quando declaro na função não funciona?

A função está no mesmo arquivo .h do Load.

Já tentei declarar o socket na função com outro nome e também só funciona o stream, as funções e propriedades continuam não funcionando, sempre diz "Undeclared Identifier"!!!

Não entendo.

valeu, T+ :D :D :D

  • Membro VIP
Postado

Pullga,

Testei os sockets com o .Net 2.0 aqui, continua a mesma coisa:

- Chamar o close do Close() do client fecha a conexão, sem problemas.

- Clients não podem ser reutilizados, crie um novo a cada vez que abrir uma conexão.

- Aqui, abrindo e fechando uma conexão de cada vez ele chegouaté 10000 conexões sem haver erro, tentando abrir o máximo possível ao mesmo tempo ele deu pau depois de 6970 conexões, se esse não for um limite do windows um CP mais potente pode obter resultados melhores.

E sobre os erros que esta dando no seu projeto, parecem ser por causo dos escopos... Fica difícil falar sem ver o código.

Postado

Olá EduardoS,

Resolvido quase tudo, consegui realizar a conexão e comunicar com o no-break, tudo beleza, o problema é que sexta, conectei e funcionou, hoje, vou conectar e não consigo, dá mensagem de erro dizendo que o componente inicializado não respondeu a tempo!!!

Tirando isso, tá funcionando normal, quer dizer, quando funciona!!!


"Uma tentativa de conexão falhou porque o componente conectado não respondeu corretamente após um período de tempo ou a conexão estabalecida falhou porque o host conectado não respondeu"

valeu T+ :D :D :D

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Sobre o Clube do Hardware

No ar desde 1996, o Clube do Hardware é uma das maiores, mais antigas e mais respeitadas comunidades sobre tecnologia do Brasil. Leia mais

Direitos autorais

Não permitimos a cópia ou reprodução do conteúdo do nosso site, fórum, newsletters e redes sociais, mesmo citando-se a fonte. Leia mais

×
×
  • Criar novo...

LANÇAMENTO!

eletronica2025-popup.jpg


CLIQUE AQUI E BAIXE AGORA MESMO!