Comunicar Java com C++ via rede

Ae pessoal. Eu tô querendo fazer um esquema pra facilitar a comunicação entre programas Java com C++. Eu já li um pouco sobre JNI, mas conversando com algumas pessoas veio a idéia q usar rede pode ser mais fácil.

Meu objetivo específico pro momento é desenvolver a lógica em Java e usar o CBuilder pra fazer a GUI, em vez de usar Swing. Mas eu queria aproveitar pra fazer alguma coisa q já fosse pra uso geral.

A idéia é fazer a lógica toda indepentende da interface com usuário. Daí qd ela tivesse pronta (ou pelo menos bem documentada), em vez de usar Swing pra fazer a GUI fizesse uma interface em rede, com um protocolo simples. Toda a troca de informações seria via XML, assim o client só ia precisar ter suporte a socket e um XML Parser razoável.

Blz, eu comecei a ler sobre Socket em Java e fiz 2 aplicações exemplo de servidor e client, elas funcionam de acordo.

Daí eu li uns tutoriais sobre Winsocks e fiz um client C++. Só q na hora de ler os dados o servidor desconecta e levanta uma Exception falando q ele resetou :frowning:

Analisando um pouco (comentando códigos e vendo resultado) eu vi q o client C++ conecta sem problema no server, o problema é qd ele manda uma string e o server tenta ler.

Alguém tem idéia de como enviar strings em C++ pra Java?
Em java eu usei a classe String e em C++ usei array de char, tudo tradicional. Tentei uma um esquema mais baixo nível em Java lendo arrays de bytes mas deu o mesmo erro…

Segue o código se alguem tiver vontade de olhar oq eu já consegui.
O Server Java só suporta 1 client, qd um client conecta ele entra em loop lendo uma linha e imprimindo ela no stdout; qd ele recebe a string “finish” ele sai do loop e fecha; se passar 10s sem receber nenhuma mensagem ele expira e recomeça o loop; eu fiz um contador só pra ficar fácil ver q o loop tá acontecendo.
O Client Java conecta no server e fica esperando entrada no prompt, toda string q ele recebe ele manda pro server, qd ele recebe a string “finish” ele manda ela pro server (pra q ele feche) e fecha tb.
Essas 2 classes tão se comunicando sem problema.

[code]import java.io.;
import java.net.
;

public class Server {

public static void main(String[] args) {
    
    //Declaro o ServerSocket
    ServerSocket serv=null; 
    
    //Declaro o Socket de comunicação
    Socket s= null;
    
    //Declaro o leitor para a entrada de dados
    BufferedReader entrada=null;
            
    try{
        
        //Cria o ServerSocket na porta 7000 se estiver disponível
        serv = new ServerSocket(7000);
    
        //Aguarda uma conexão na porta especificada e cria retorna o socket que irá comunicar com o cliente
        
        
		String string;
		s = serv.accept();
		s.setSoTimeout(10000);
		int i=0;


        //Cria um BufferedReader para o canal da stream de entrada de dados do socket s
        entrada = new BufferedReader(new InputStreamReader(s.getInputStream()));
		do{
				
					try{
						string=entrada.readLine();
						if(string!=null && string.trim().equals("finish")) break;
							

						//Aguarda por algum dado e imprime a linha recebida quando recebe
						System.out.println(string); 
					}catch(java.net.SocketTimeoutException ex){
						ex.printStackTrace();
					}

					System.out.println("\n"+(i++)+"\n");
					

		}while(true);


        
    //trata possíveis excessões de input/output. Note que as excessões são as mesmas utilizadas para as classes de java.io    
    }catch(IOException e){
    
        //Imprime uma notificação na saída padrão caso haja algo errado.
        e.printStackTrace();
    
    }finally{
        
        try{
            
            //Encerro o socket de comunicação
            s.close();
            
            //Encerro o ServerSocket
            serv.close();
            
        }catch(IOException e){
        }
    }

}

}
[/code]

[code]import java.io.;
import java.net.Socket;
import java.util.
;

public class Client {

public static void main(String[] args) {
    
    //Declaro o socket cliente
    Socket s = null;
    
    //Declaro a Stream de saida de dados
    PrintWriter pw = null;
    
    try{
        

		Scanner sc = new Scanner(System.in);
		String string;

		//Cria o socket com o recurso desejado na porta especificada
		s = new Socket("127.0.0.1",7000);
		//Cria a Stream de saida de dados
		pw = new PrintWriter (s.getOutputStream(), true /*autoflush*/);

		do{

			string=sc.next();
			pw.println(string);

			if(string!=null && string.trim().equals("finish")) break;


		}while(true);

        
    //Trata possíveis exceções
    }catch(IOException e){
        
        e.printStackTrace();
    
    }finally{
        
        try{
            
            //Encerra o socket cliente
            s.close();
            
        }catch(IOException e){}
    
    }

}

}
[/code]

O Client C++ foi compilado usando o “Borland C++ 5.6 for Win32” (eu tentei compilar ele usando o Dev-C++ e akele compilador bugado naum conseguiu linkar). Ele compila sem erro e executa sem erro tb. Eu fiz um loop pra testar o envio de várias mensagens, ele diz q todas foram enviadas mas o server naum imprime nenhuma e qd ele fecha a conexão o server levanda a “java.net.SocketException: Connection reset”.
Isso leva a 2 problemas:

  1. Se o client diz q as mensagens tão sendo enviadas, pq o server não imprime elas?
  2. A exception Connection reset tá sendo levantada pelo server qd o client desconecta. Como seria a forma certa de desconectar então?

[code]#include <stdio.h>
#include “winsock2.h”

void main() {

// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup( MAKEWORD(2,2), &wsaData );
if ( iResult != NO_ERROR )
    printf("Error at WSAStartup()\n");

// Create a socket.
SOCKET m_socket;
m_socket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );

if ( m_socket == INVALID_SOCKET ) {
    printf( "Error at socket(): %ld\n", WSAGetLastError() );
    WSACleanup();
    return;
}

// Connect to a server.
sockaddr_in clientService;

clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr( "127.0.0.1" );
clientService.sin_port = htons( 7000 );

if ( connect( m_socket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR) {
    printf( "Failed to connect.\n" );
    WSACleanup();
    return;
}





// Send and receive data.
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[32] = "Client: Sending data.";
char recvbuf[32] = "";

for(int i=0;i<5;i++){

bytesSent = send( m_socket, sendbuf, strlen(sendbuf), 0 );
printf( "Bytes Sent: %ld\n", bytesSent );

}

WSACleanup();
return;

}[/code]

a) Se você observou seu código C++ com mais cuidado, vai ver que ele não manda linhas terminadas por “\n” (ou “\r\n” se for Windows).
O código Java está esperando que você termine cada linha por “\n” (ou “\r\n”), para que readLine funcione corretamente.

b) Sempre fui meio desconfiado de usar modo texto para comunicação via sockets. Acho que isso não funciona direito, principalmente porque uma leitura de socket pode terminar antes de receber todos os bytes que você está esperando.

Prefiro mandar mensagens com um cabeçalho com indicador de comprimento (digamos 2 bytes, mais significativo primeiro) e depois um array de bytes cujo comprimento foi enviado no cabeçalho, e se você for realmente chato, enviar também um CRC ou outro método de checksum.

Para trabalhar com isso, você pode usar DataInputStream/DataOutputStream (Java) e htons (no C, para converter um short - 2 bytes - para o formato que o Java espera, byte mais significativo primeiro.)

Cara achei muito legal a sua iniciativa, mas você já deu uma olhada em alguns padrões consolidados e bastante usados como por exemplo:

  1. CORBA - A pedra filosofal para a intercomunicação entre linguagens diferentes;
  2. XML-RPC - Uma abordagem mais moderna e mais leve que possui implementações em diversas linguagens (inclusive java e C++);
  3. Webservices - Você pode implementar um webservice em uma linguagem e utilizá-lo em qualquer outra linguagem.

[quote=brunogamacatao]1) CORBA - A pedra filosofal para a intercomunicação entre linguagens diferentes;
[/quote]

Que planeta você vive? Já usou pra valer? CORBAé um oceano de incompatibilidades. Sem falar que a grande maioria das ORBs são uma carroça e desenvolver para esse treco é um pé no saco.

A questão é que existem alternativas existentes, consolidadas e que funcionam. Quanto a questão da pedra filosofal, realmente eu errei na metáfora, a metáfora correta seria a pedra de roseta (aquela pedra que serviu pra traduzir alguns idiomas antigos), mas isso não vem ao caso.
Você tem alguma observação edificante sobre XML-RPC, Web Services ou alguma outra tecnologia correlata ?

[quote=brunogamacatao]A questão é que existem alternativas existentes, consolidadas e que funcionam. Quanto a questão da pedra filosofal, realmente eu errei na metáfora, a metáfora correta seria a pedra de roseta (aquela pedra que serviu pra traduzir alguns idiomas antigos), mas isso não vem ao caso.
Você tem alguma observação edificante sobre XML-RPC, Web Services ou alguma outra tecnologia correlata ?[/quote]

RPC e serviços correlatos são mais antigo que CORBA, por sinal.

Quanto a WS e XML-RPC, cada um tem seu uso, assim como CORBA. Tudo depende da necessidade de cada um.

Usar qualquer um dos três para um serviço distribuido de caching, como o memcached, é fracasso certo. Para este caso TCP e um protocolo proprietario é muito mais indicado.

Só uma pergunta, quando você falou em XML-RPC e disse ser mais leve, em relação a qual alternativa?

Valeu pelas respostas gente! Pelo assunto ser raro e sempre q ele aparece ele ser relacionado com JNI pensei q ninguem ia querer responder.

[quote=brunogamacatao]Cara achei muito legal a sua iniciativa, mas você já deu uma olhada em alguns padrões consolidados e bastante usados como por exemplo:

  1. CORBA - A pedra filosofal para a intercomunicação entre linguagens diferentes;
  2. XML-RPC - Uma abordagem mais moderna e mais leve que possui implementações em diversas linguagens (inclusive java e C++);
  3. Webservices - Você pode implementar um webservice em uma linguagem e utilizá-lo em qualquer outra linguagem.[/quote]

Eu pensei em web service só q pelo q eu entendi ele só é usado em aplicação WEB. Como meu propósito é fazer coisa menor, ter q instalar Tomcat ou coisa do tipo ia aumentar muito o consumo de RAM e deixar o programa inviável.

Esses outros eu naum conheço.

[quote=thingol]
a) Se você observou seu código C++ com mais cuidado, vai ver que ele não manda linhas terminadas por “\n” (ou “\r\n” se for Windows).
O código Java está esperando que você termine cada linha por “\n” (ou “\r\n”), para que readLine funcione corretamente. [/quote]

Blz! Agora funcionou! :smiley:
Vou fazer uns testes e se precisar pergunto mais coisa aki.

Pra isso ia ser preciso criar um protocolo mais complexo, e tudo q eu li sobre comunicação via rede usando Java recomenda serializar os dados, q seria converter dados binários em string e depois converter a string and dado de novo. Tem até um projeto da Apache q converte qqr objeto em um pedaço de XML armazenado uma String.

Por causa do objetivo ser fazer Java conversar com qqr linguagem e plataforma com o mínimo de esforço, parece mesmo q XML é o mais adequado. Mais poder colocar CRC junto ia ser uma boa :smiley:

Blz, agora os programas tão funcionando 100%.

Agora q eu tô mais tranquilo (e vi q gostaram da idéia)(apesar do Firefox ter crashado qd eu tava quase acabando de escrever e eu ter perdido tudo), deixa eu explicar melhor oq eu tô querendo.

Swing é uma ótima ferramenta pra desenvolver GUI, mas ele ainda é inferior ao Win32, e o CBuilder já tem componentes prontos mais completos.
E com a tendência atual de separar a camada de lógica da interface com o usuário, sendo tão fácil usar essa metodologia com Java, e ele tendo uma interface tão boa como o JDBC, eu acho “estranho” se fizer a lógica ou a interface em Java a outra camada tb ter q ser em Java tb.
Ia ser legal fazer a lógica em Java e, se quisesse, fazer a GUI usando ferramentas do OS nativo.

1º eu pensei em JNI, mas ele parece ser muito complexo e muito bug phrone, além do javah naum ter funcionado comigo :stuck_out_tongue:

Conversando com umas pessoas veio a idéia de usar a rede pra fazer a comunicação. E tudo q eu li sobre isso recomenda usar a serialização, converter um objeto em String e depois remontar o objeto a partir dela.
Com XML fica perfeito, pq qqr linguagem q quisesse comunicar só ia precisar suportar socket, e ter um XML Parser.

Veio a idéia de usar Web Service, mas pelo q eu entendi ele depende de Web Server, daí o programa ia ficar muito pesado, além do client ter q se virar pra ser HTTP client tb…

Agora eu tô com umas dúvidas, se alguem conhecer melhor sobre o assunto e puder me ajudar eu agradeço :smiley:

  1. Qd o server recebe a string “finish” ele sai do loop, fecha o socket e acaba. Num programa mais real ia ser uma thread finalizando. Isso funciona então como um sinal do client avisando pro server q a comunicação acabou e eles devem fechar a conexão simultaneamente?

  2. Se eu mudar o código do client pra ele chamar a função WSACleanup(); “de repente” o server vai levantar a exception “java.net.SocketException: Connection reset”. Ela indica um erro e deve ser evitada ou é igual a java.net.SocketTimeoutException, só avisando q o outro peer desconectou e a conexão naum pode mais ser usada?

  3. Se sempre q o readLine() acha um \n ele retorna, qual a melhor forma de identificar qd uma mensagem começa e qd ela termina, pra saber qd ela acabou de chegar pra poder tratar ela? A melhor forma de evitar ficar bloqueado esperando mais dados q não vão ser enviados é sempre colocar no início da mensagem o tamanho dela?

Eu vou dar mais uma mexida no código, vou tentar fazer um chat pra ver como fica :slight_smile:

[quote=brunogamacatao]Cara achei muito legal a sua iniciativa, mas você já deu uma olhada em alguns padrões consolidados e bastante usados como por exemplo:

  1. CORBA - A pedra filosofal para a intercomunicação entre linguagens diferentes;
  2. XML-RPC - Uma abordagem mais moderna e mais leve que possui implementações em diversas linguagens (inclusive java e C++);
  3. Webservices - Você pode implementar um webservice em uma linguagem e utilizá-lo em qualquer outra linguagem.[/quote]

Eu dei uma lida sobre CORBA, pelo menos muita gente suporta ele. Tem muito desenvolvedor grande q suporta o VisiBroker da Borland, vcs sabem se ele é bom?

Eu tb fiz uns testes com o RMI, achei ele mais complexo do q o normal e naum gostei de ter q usar uma JVM só pra registrar os objetos. Mas limitando ele um pouco (muito!) dá pra usar ele com o mesmo protocolo do CORBA e fazer eles se comunicarem, dizem q a maioria dos EJB usa o RMI-IIOP e por isso qqr linguagem pode conversar automaticamente com EJB via CORBA, isso é verdade? :smiley:

Considerando q comunicar 2 linguagens diferentes já é dificil e quase impossível de ter boa compatibilidade o CORBA até faz bom trabalho. E qd Java entra no meio a interação sempre fica mais complicada ainda.