2008-09-18 18 views
7

Estoy tratando de escribir un cliente C# a un servidor que está escrito en Java. El servidor espera un encabezado de mensaje de 4 bytes (DataInputStread readInt() en Java) seguido del mensaje real.Enviando un encabezado de mensaje de 4 bytes del cliente C# a un servidor Java

Soy absolutamente nuevo en C#, ¿cómo puedo enviar este encabezado de mensaje al servidor Java? Lo intenté de varias maneras (principalmente de prueba y error sin profundizar demasiado en el lenguaje C#), y nada funcionó. El lado de Java terminó con la longitud incorrecta (muy grande) del mensaje.

Respuesta

2

Es simple, pero ¿ha comprobado la permanencia? Fácilmente podría haber un desajuste entre el orden de bits que ha enviado los datos de entrada y el orden de bits que está recibiendo en

0

No sé C#, pero sólo tiene que hacer el equivalente a esto:.

out.write((len >>> 24) & 0xFF); 
out.write((len >>> 16) & 0xFF); 
out.write((len >>> 8) & 0xFF); 
out.write((len >>> 0) & 0xFF); 
1

Si vas a intercambiar una gran cantidad de datos, recomendaría implementar (o encontrar) un contenedor de flujo que pueda escribir y leer entradas en orden de red. Pero si en realidad sólo necesita escribir la longitud hacer algo como esto:

using(Socket socket = ...){ 
    NetworkStream ns = new NetworkStream(socket);  
    ns.WriteByte((size>>24) & 0xFF); 
    ns.WriteByte((size>>16) & 0xFF); 
    ns.WriteByte((size>>8) & 0xFF); 
    ns.WriteByte(size  & 0xFF); 
    // write the actual message 
} 
11

Es, como otros críticos han señalado, hasta endianness.

Java DataInputStream espera que los datos sean big-endian (orden de bytes de red). A juzgar por la documentación de Mono (para equivalentes como BinaryWriter), C# tiende a ser little-endian (el valor predeterminado para Win32/x86).

Por lo tanto, cuando se utiliza la biblioteca de clases estándar para cambiar el int de 32 bits '1' a bytes, que producen resultados diferentes:

//byte hex values 
Java: 00 00 00 01 
    C#: 01 00 00 00 

Puede alterar la forma en que escribe enteros en C#:

private static void WriteInt(Stream stream, int n) { 
    for(int i=3; i>=0; i--) 
    { 
     int shift = i * 8; //bits to shift 
     byte b = (byte) (n >> shift); 
     stream.WriteByte(b); 
    } 
} 

EDIT:

Una forma más segura de hacer esto sería:

private static void WriteToNetwork(System.IO.BinaryWriter stream, int n) { 
    n = System.Net.IPAddress.HostToNetworkOrder(n); 
    stream.Write(n); 
} 
2

Como todo el mundo ya ha señalado, la causa más probable es que la aplicación C# envíe ints en orden little-endian mientras que la aplicación Java los espera en orden de red (big-endian). Sin embargo, en lugar de reorganizar explícitamente los bytes en la aplicación C#, la forma correcta es confiar en las funciones integradas para convertir el host en una orden de red (htons y "me gusta"); de esta manera, su código seguirá funcionando incluso cuando se ejecute en una máquina big-endian.

En general, cuando resuelvo problemas de este tipo, me parece útil registrar el tráfico correcto (por ejemplo, Java a Java en su caso) utilizando herramientas como netcat o wireshark, y luego compararlo con el tráfico incorrecto para ver dónde está yendo mal. Como beneficio adicional, también puede usar netcat para inyectar las solicitudes capturadas/pregrabadas en el servidor o inyectar respuestas capturadas/pregrabadas en el cliente. Sin mencionar que también puede modificar las solicitudes/respuestas en un archivo y probar los resultados antes de comenzar con la reparación del código.

0

La clase Sysetm.Net.IPAddress tiene dos métodos estáticos de ayuda: HostToNetworkOrder() y NetworkToHostOrder() que hacen la conversión por usted. Puede usarlo con un BinaryWriter sobre la secuencia para escribir el valor correcto:

using (Socket socket = new Socket()) 
using (NetworkStream stream = new NetworkStream(socket)) 
using (BinaryWriter writer = new BinaryWriter(stream)) 
{ 
    int myValue = 42; 
    writer.Write(IPAddress.HostToNetworkOrder(myValue)); 
} 
Cuestiones relacionadas