Java comunicando com C++ com socket

Ola pessoal

estou precisando muito de fazer um programa em java q se comunique com c++, na realidade eu ja concegui enviar msg do java para o c++ porem no c++ mostra a mensagem como um ponto de interrogacao (?)

preciso enviar um byte do java para o c++ dai o c++ deve converter este byte para string, aguem ai sab alguma coisa? abaixo esta meu codigo:

java:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

public class Main {

private static Socket conexao;

public static void main(String[] args) throws UnknownHostException, IOException {
    
    String msg = "108";

    //byte[] bytes = msg.getBytes("ASCII"); //ascII
    byte[] bytes = msg.getBytes("Charset");//unicode
    System.out.println("Bytes:  "+bytes);
    System.out.print("Posicoes:  ");
    for (int i = 0; i < bytes.length; i++) {
        System.out.print(bytes[i]) ;
        
    }
    String strg = new String (bytes, "ISO-8859-1");
    System.out.println("\nString:  "+strg);

    //byte[] b;
    Socket s = new Socket("192.168.56.2",30000);
    OutputStream  saida1 = s.getOutputStream();
    ObjectOutputStream saida = new ObjectOutputStream(saida1);
    //b=intToFourBytes(msg, false);
    //System.out.println("Byte: "+b[0]+" "+b[1]+" "+b[2]+" "+b[3]+" ");
    //saida.write(bytes);
    saida.write(bytes);
    saida.flush();
    saida.close();
}

C++:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/wait.h>
#include<unistd.h>

int main(int argc, char ** argv)
{
int sockfd, novo_fd;
struct sockaddr_in meu_end;
struct sockaddr_in outro_end;
int sin_size;
int bytesEnviados;

meu_end.sin_family = AF_INET;
meu_end.sin_port = htons(30000);
meu_end.sin_addr.s_addr = INADDR_ANY;
memset(&(meu_end.sin_zero), ‘\0’, 8);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
printf("\nErro na chamada socket()");
return 1;
}

if(bind(sockfd, (struct sockaddr *) &meu_end, sizeof(struct sockaddr)) == -1)
{
printf("\nErro na chamada de bind()");
return 1;
}

if(listen(sockfd, 10))
{
printf("\nErro na chamada de listen()");

  return 1;

}

    sin_size = sizeof(struct sockaddr_in);
    printf("\nServidor: Aguardando conexao!");
    novo_fd = accept(sockfd, (struct sockaddr *)&outro_end, (socklen_t*)&sin_size);

//char *msg = “Bem vindo, cliente”;

//printf("\n\nBytes tentando enviar: %d", sizeof(msg));

char buffer[20];

recv(novo_fd, (void *) buffer, 20, 0);

//bytesEnviados = send(novo_fd, msg, sizeof(msg), 0);

printf("\n\nBytes recebidos: %s", buffer);

return 0;
}

aguardo suas opcoes

eu acho que seria mais pratico vc no java escrever em um arquivo e no c++ ler este arquivo

nao é possivel pois ficam em maquinas diferentes, alem disso, eu fiz d um geito q um java escrevia em um arkivo e uma aplicacao c++ lia e mandava para a outra ponta c++ porem isto nao pode ser feito deste geito pois fik mbm porko neh

vlw

  1. Ao postar códigos, use a tag code, como descrito aqui;
  2. Seu código não é C++, é C. Se você quer fazer algo em C++, considere pelo menos usar a STL. Melhor ainda se usar o boost::asio. Senão depois não vale reclamar que C++ é difícil.
  3. Você precisa definir um protocolo para sua aplicação. Com sockets, vc nunca sabe quantos bytes ler, a menos que envie essa informação. Simplesmente escrever bytes e ler de qualquer jeito do outro lado não resolve, pois o número de reads pode não corresponder ao número de writes do outro lado do canal. Veja o tópico O que é um protocolo para mais informações;
  4. Sugiro que você use ByteBuffers em java. Eles tratam detalhes como endianess. Certifique-se que sua máquina transmissora e receptora usem o mesmo endianess. Além disso, lembre-se que variáveis do tipo unsigned não são bem representadas em java. A classe ByteBufferWorker pode te ajudar nesse sentido.

Esqueci de comentar:
5. Evite usar o ObjectOutputStream. Prefira o DataOutputStream. O formato da serialização de um objeto só é conhecido por sua classe, e você não terá essa classe no C++. Portanto, você precisa serializa-la manualmente, num protocolo que você conheça;
6. Não converta dados para String para envia-los, a menos que você crie um protocolo baseado em texto. Lembre-se que a transmissão de Strings costuma a ser muito ineficiente. Por exemplo, o número 9.223.372.036.854.775.807 usa 19 bytes como String e só 8 se for transmitido como long.

ok, desculpa pelo ultimo post todo atrapalhado, eh q eu sou novo, e num sou mto bom em programacao, eu pensava q c e c++ eram a msm coisa porem q o c++ tinha algumas funcoes a mais, com isso eu pensei q um codigo em c poderia ser compilado normalmente em c++. mas voltando ao assunto, eu to penando aki com isse problema, cheguei a este codigo:

[code]#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
//string
#include
#include
#include <stdlib.h> //atoi();
#include //comparacao de string

using namespace std;

int main(int argc, char ** argv)
{
int sockfd, novo_fd;
struct sockaddr_in meu_end;
struct sockaddr_in outro_end;
int sin_size;

cout<<"\nServidor: Aguardando conexao!";

meu_end.sin_family = AF_INET;
meu_end.sin_port = htons(30000);
meu_end.sin_addr.s_addr = INADDR_ANY;
memset(&(meu_end.sin_zero), ‘\0’, 8);

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd == -1)
{
cout<<"\nErro na chamada socket()";

  return 1;

}

if(bind(sockfd, (struct sockaddr *) &meu_end, sizeof(struct sockaddr)) == -1)
{
cout<<"\nErro na chamada de bind()";

  return 1;

}

if(listen(sockfd, 10))
{
cout<<"\nErro na chamada de listen()";

  return 1;

}

    sin_size = sizeof(struct sockaddr_in);

    novo_fd = accept(sockfd, (struct sockaddr *)&outro_end, (socklen_t*)&sin_size);

//char *msg = “Bem vindo, cliente”;

//printf("\n\nBytes tentando enviar: %d", sizeof(msg));

char* buffer[20];
//unsigned char *p;
//string t="";
//recv(novo_fd, (void *)buffer, 8, 0);

recv(novo_fd, (void *)buffer, sizeof(buffer), 0);

   // Alternate method
   //string s2;
   //s2.append(reinterpret_cast<const char *>(p), 8); // append 30 characters to s2

//bytesEnviados = send(novo_fd, msg, sizeof(msg), 0);

   cout<<"\n\nBytes recebidos: "<< buffer;

   return 0;

}[/code]

aki eu nao concigo baixar o boost::asio mas assim q eu chegar em casa vou tentar baixa-lo e utilizar as dicas q i ViniGodoy falou.

se souberem d mais alguma coisa eu agradeco muito
vlw

Boa parte dos códigos C podem sim ser compiladas em C++. Mas isso só significa que o C++ é compatível com código C, não que código C automaticamente foi promovido para código C++. O C++ tem, além da parte estruturada, orientação e objetos e o paradigma de programação genérica.

De qualquer forma, se você é iniciante em programação, e não sabe fazer isso direito, você está começando por um software extremamente complexo. Esse programa é para sua empresa? Não tem como pegar alguma outra parte mais simples?

Muito obrigado pela ajuda ViniGodoy, este eh o meu projeto de estagio e tenho q conclui-lo para q qm sab eu possa ficar na empresa, eu ja concegui fazer funcionar fazendo o java escrever em um arquivo e dpois um programa em c++ fazia a leitura do arquivo e dpois enviava a um outro prog em c++ q esta no linux, porem agora tenho q fazer esta conexao diretamente com o java, o programa em c++ antigo eu usei socket baseado em um tutorial q achei no google mas ele implementava varios arquivos para facilitar utilizacao de socket mas nao rodou com o java pois ele recebe a mensagem toda destorcida. estou baixando este boost q vc me indicou, vc sab c ele vai ser capaz d se comunicar com o java? outra coisa, onde eu acho um tutorial para instala-lo?

desde ja muito obrigado

vlw

Tanto o socket nativo, quanto a boost, podem comunicar-se facilmente com o Java. Mas o importante é que você saiba o que está acontecendo, e entenda como o TCP/IP funciona.

Uma dica. Baixe o wireshark, e veja exatamente que dados estão sendo enviados em cada lado da rede:
http://www.wireshark.org/

Assim você pode ver que programa está se comunicando errado. E, como eu falei, não use coisas como o ObjectOutputStream.

Quanto à instalação da boost, há diversos tutoriais no próprio site. A maior parte da boost é só um conjunto de arquivos .h, basta adiciona-los ao projeto. No caso do asio, creio que haja a necessidade de montar uma biblioteca externa.

Pessoal, bom dia

fiz a alteracao para DataOutput como o ViniGodoy falou e funcionou, agora tenho outra duvida, como enviar algo para indicar um fim da cadeia de caracteres, no caso estou enviando uma string q converto para ascII e dpois byte porem algumas vez vou enviar um codigo somente e outras mais alguns parametros, no caso meu buff eh [20] a duvida eh como colocar algo pra dizer q uma msg eh so “142” e outra eh “143 3 45” pois se nao indicar o buffer vai mostrar oq recebeu mais alguns lixo

vlw

Você leu o texto sobre protocolos que indiquei ali em cima?

Você tem que formalizar um protocolo da sua aplicação. Isso é, vc deve dar regras para suas mensagens. Senão vc nunca vai saber que ler mesmo.

Um exemplo, sua mensagem poderia ser assim:

Byte 1 - Tipo da mensagem. Um número de 0 até 255 que indica o que está sendo enviado
Bytes 3 até 6 - Tamanho da mensagem: Indica quantos bytes ainda devem ser lidos do socket para que essa mensagem chegue completa.
N bytes - Dados da mensagem.

Para os dados, você poderia definir o seguinte:
Dados do tipo String: Sempre é enviado o tamanho da string (4 bytes), seguido seus seus caracteres, em ascii;
Dados de tipo primitivo: São usados o número de bytes padrão, em little endian, para plataformas de 32 bits;

Quais dados iriam em cada mensagem? Isso depende do campo tipo. Mas com essa informação, vc poderia dizer que mensagens do tipo 1 são, por exemplo, “informações do usuário”. E enviar algo assim:
String: Login
String: Senha criptografada

Segundo esse protocolo, essa mensagem ficaria assim para o login “ViniGodoy” e senha de criptografada “L23$”:

[0000] 01 00 00 00  15 00 00 00  09 56 69 6E  69 47 6F 64    . . . .  . . . .  . V i n i  G o d
[0010] 6F 79 00 00  00 04 4C 32  33 24                       o y . .  . . L 2  3 $

Note que essa mensagem segue exatamente o protocolo definido. E não há duvidas sobre o quanto deve ser lido, nem como.

meu protocolo é o seguinte,

msg1= Cod(int)+coordX(int)+coordY(int)
msg2=cod(int)+Ncomponentes(int)+PressionadoOuNao(int 0/1)+componente1+componente2+…+componenteN(Ncomponentes(int))
msg3=cod(int)

neste caso como posso fazer para trabalhar com isso? vja o meu cod

[code]String msg = “141 sa contedosdfz”;

    byte[] bytes = msg.getBytes("ASCII"); //ascII
    
    System.out.println("Bytes:  "+bytes);
    System.out.print("Posicoes:  ");
    for (int i = 0; i < bytes.length; i++) {
        System.out.print(bytes[i]+" ") ;
        
    }
    String strg = new String (bytes, "ISO-8859-1");
    System.out.println("\nString:  "+strg);

    DatagramSocket s = new DatagramSocket();            //udp
    InetAddress adr=InetAddress.getByName("192.168.56.2"); //udp

    DatagramPacket question = new DatagramPacket(bytes, bytes.length,adr,30000); //udp
    
    s.send(question); //udp

[/code]

este codigo transforma em byte e envia, como q vc implementa a parte de ver o tamanho em bytes e enviar e receber so os bytes certos?

tem como alguem escrever algum codigo basico pra mim continuar ou algo do tipo?

*o cod acima so transforma em bytes(eu acho) e envia os bytes

[code]int main(int argc, char ** argv)
{
int sockfd, novo_fd;
struct sockaddr_in meu_end;
struct sockaddr_in outro_end;
int sin_size;

printf("\nServidor: Aguardando conexao!");

meu_end.sin_family = AF_INET;
meu_end.sin_port = htons(30000);
meu_end.sin_addr.s_addr = INADDR_ANY;
memset(&(meu_end.sin_zero), ‘\0’, 8);

sockfd = socket(AF_INET, SOCK_DGRAM, 17);
if(sockfd == -1)
{
cout<<"\nErro na chamada socket()";

  return 1;

}

if(bind(sockfd, (struct sockaddr *) &meu_end, sizeof(struct sockaddr)) == -1)
{
cout<<"\nErro na chamada de bind()";

  return 1;

}

/*if(listen(sockfd, 10))
{
cout<<"\nErro na chamada de listen()";

  return 1;

}*/

    sin_size = sizeof(struct sockaddr_in);

    //novo_fd = accept(sockfd, (struct sockaddr *)&outro_end, (socklen_t*)&sin_size);

    std::string mensagem;

    char* buffer[20];
    while(true){
    	recv(sockfd, buffer, sizeof(buffer), 0);

    	//bytesEnviados = send(novo_fd, msg, sizeof(msg), 0);
    	//mensagem= (std::string)buffer;

    	printf("\n\nBytes recebidos: %s", buffer);
    }
    return 0;

}[/code]

este eh o code em c++

aguar ajuda

Melhore seu protocolo. Senão fica impossível mesmo saber como ler os dados.

Por que você está usando UDP ao invés de TCP? Está ciente das limitações dele?

eu estava usando tcp mas me pediram para usar udp por ser mais rapido, dai agora tenho q utilizar udp

vc viu a parte do codigo em java q transforma em byte? vc acha q ta certo?

Se você quer transmitir ascii, parece certo sim.

O UDP tem as seguintes características:

  1. É orientado a datagramas, e esses tem no máximo 8k;
  2. Não tem garantia de entrega (pacotes podem não chegar);
  3. Não tem garantia de ordenação (um pacote que vc enviou por segundo pode chegar antes do que um que vc enviou por primeiro);
  4. Não tem garantia de integridade (você pode mandar uma coisa, e chegar outra);
  5. Não cria conexão;

O TCP é orientado a conexão, e tem todas as garantias que o UDP não tem.

O UDP vai ser mais eficiente em comunicações de tempo real que admitam perda, tais como tráfego de voz e vídeo. Em comunicações assim, é melhor perder um ou outro datagrama e ter uma ligeira perda de qualidade, do que deixar o vídeo/som congelar ou atrasar.

É um erro comum pessoas simplificarem o problema e acharem, por exemplo, que o UDP será mais rápido que o TCP em todas as situações. Isso não é verdade. Em tráfego de arquivos, que exige sequenciamento correto de dados e confiabilidade, o TCP é muito mais eficiente. Ele tem um mecanismo de retransmissão muito bem implementado, provavelmente muito melhor do que um programador mediano bem intencionado seria capaz de fazer. E, como muitas placas, tem otimizações de hardware, é até impossível fazer uma transmissão tão eficiente quanto a que você pode ter nesse protocolo usando UDP.

infelismente eu tenho q fazer com udp pq me pediram para implementar com udp msm, posso tentar mudar, mas acho q nao tera tanta diferenca no q diz respeito a alteracao do programa, se eu fizer tudo separado em funcoes, a funcao continua receber seus parametros e dpois envia como udp ou tcp, mas mudando um poukinho de assunto, eu estudei um pouco para melhorar o protocolo como foi dito acima:

criei uma classe msg q possui int tamanho e int cod e seu get e set
dpois criei outras classes com extends da classe msg, essa duas sao dos outros tipos de mensagens com outros campos do tipo int

o protocolo q inventei eh o seguinte, int tamanho (com 1byte apenas) + int cod(mostra o tipo de msg) + int complementos

ex de msg para um evento de mouse: tamanho=13,cod=-556,x=123,y=345, a msg q eu qro enviar é a conversao em byte de 13-556123345

o codigo q eu fiz para fazer esta conversao pra int eh o seguinte:


String msg = String.valueOf(msg1.getTamanho())+" "+String.valueOf(msg1.getId())+" "+String.valueOf(msg1.getPosicX())
                +" "+String.valueOf(msg1.getPosicY());
ByteBuffer bufferInt=ByteBuffer.allocate(13);
        bufferInt.put((byte)msg1.getTamanho());
        bufferInt.putInt(msg1.getId());
        bufferInt.putInt(msg1.getPosicX());
        bufferInt.putInt(msg1.getPosicY());
        byte[] msgTotal=new byte[13];
        msgTotal=bufferInt.array();

        System.out.print("Bytess: ") ;
        for (int i = 0; i < msgTotal.length; i++) {
            System.out.print(msgTotal[i]) ;

        }

o resultado eh: para a msg no formato string: 13 -556 785 557 teve como traducao int para byte: 13-1-1-3-440031700245
conversao da string para byte: 495132455353543255565332535355 (decimal)
eu nao intendi este -(menos) que sugiu no meio da msg

esta certo a conversao?como saberei q este 13 eh o tamanho da msg se eu recebo tudo d uma vez?

vlw

Se seu protocolo diz que 13 é o tamanho, então 13 é o tamanho.

Se você quiser conferir, use o wireshark para contar.

Não adianta imprimir os bytes na mensagem diretamente. Assim, alguns bits significativos podem ser interpretados como bits de sinal (um int é formado por quatro bytes. Os bytes após o primeiro não tem bit de sinal, mas na conversão para byte o java irá imprimi-los como se tivessem).

Na classe ByteBufferWorker, que te passei, existe um método chamado getDumpString() que serve para isso. Ele vai mostrar a mensagem byte-a-byte, no formato que te postei ali atrás, de maneira correta. Use-o.

Use também o wireshark para ver sua comunicação. Ele ajuda muito.

diz q o tamanho eh 13 para esta msg 1byte para tamanho + 4 byte dos outros 3 int = 1+4+4+4=13

o tamanho minimo sera 5 ->1+4=5

no lado do c++ eu vou receber estes bytes dentro de um char* buffer[30], alguem sab como pegar este bytes e jogar direto em um int?

vlw