Socket OutputStream上的PrintWriter导致数据损坏/丢失

时间:2013-11-25 21:13:16

标签: java character-encoding io network-programming java-io

我正在尝试将一个字符串从默认字符编码为 UTF-8 的服务器发送到默认字符编码为 windows-1252 通过套接字 PrintWriter

当我在下面运行客户端时,尽管我尝试使用 CharsetDecoder 转换字符串,但我没有得到原来的141值。

作为一个控制测试,我尝试在Eclipse中运行这两个类,并强制通过下面的对话使用UTF-8作为默认编码系统 - 我观察到当两个客户端都使用UTF-时8,输出在客户端成功解释。

更新:看起来我能够流式传输字节并恢复初始格式,但为了做到这一点,我必须知道服务器上使用的编码。在这种情况下,是否存在某种有用的库?我宁愿不被迫以字节数组的形式传输数据。

Eclipse Dialog

服务器:

import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;

//Runs on a server with default character encoding of UTF-8
public class TestServer {

public static void main(String[] args) throws Exception {

    PrintWriter writer = null;
    ServerSocket serverSocket = null;
    try {

        int x = 141;
        String s = "#" + (char)x;

        serverSocket = new ServerSocket(5555);
        Socket clientSocket = serverSocket.accept();

        writer = new PrintWriter(
                        (new OutputStreamWriter(clientSocket.getOutputStream())), true);

        System.out.println((int)s.charAt(1));
        writer.write(s);
    } catch(Exception e) {

        e.printStackTrace();
    } finally {

        writer.close();
        serverSocket.close();
    }
}
}

客户端:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.Socket;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;

//Runs on a server with default character encoding of windows-1252
public class TestClient {

public static void main(String[] args) throws Exception {

    Socket s = new Socket("localhost", 5555);
    BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));

    String string = reader.readLine();
    System.out.println((int)string.charAt(1)); //prints 194 when it was 141 on the other end

    //Charset.defaultCharset returns windows-1252
    CharsetDecoder decoder = Charset.defaultCharset().newDecoder();
    CharBuffer buffer = decoder.decode(ByteBuffer.wrap(string.getBytes()));
    String convertedString = buffer.toString();

    System.out.println((int)convertedString.charAt(1)); //still prints 194

    String convertedString2 = new String(string.getBytes(), "UTF-8");
    System.out.println((int)convertedString2.charAt(1)); //prints 65533 ??

    s.close();
}
}

2 个答案:

答案 0 :(得分:2)

我发现有OutputStreamWriter和InputStreamReader构造函数将字符集作为参数。这是我采用的解决方案:

发件人:

out = new PrintWriter(
   new BufferedWriter(new OutputStreamWriter(
        socket.getOutputStream(), "UTF-8")), true);

在接收器上:

in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));

答案 1 :(得分:0)

我只是write() byte[]直接OutputStream并避开中间人,然后在客户端根据返回的byte[]构建一个新的String。 PrintWriter文档说:

  

它不包含用于编写程序的原始字节的方法   应该使用未编码的字节流。

在新的服务器代码中:

    bytep[] s = new String("#" + (char)x).getBytes();;
    Socket clientSocket = serverSocket.accept();
    OutputStream writer = clientSocket.getOutputStream();
    System.out.println((int)s.charAt(1));
    writer.write(s);

在客户端,您将创建一个ByteArrayInputStream并将字节转换为字符串:

byte[] return_data = null;
Socket s = new Socket("localhost", 5555);
BufferedInputStream bis = new BufferedInputStream(s.getInputStream());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int byte_read = bis.read();
while(byte_read != -1)
{
    baos.write(byte_read);
    byte_read = bis.read();

}

return_data = baos.toByteArray();
bis.close();
baos.close();   

String s = new String(return_data);