繁体   English   中英

套接字 InputStream 和 UTF-8

[英]Socket InputStream and UTF-8

我正在尝试与 Java 聊天。 一切正常,除了特殊字符不起作用。 我认为这是一个编码问题,因为在我的Outputstream我将字符串编码为 UTF-8,如下所示:

  protected void send(String msg) {
    
        try {
          msg+="\r\n";            
          OutputStream outStream = socket.getOutputStream();              
          outStream.write(msg.getBytes("UTF-8"));
          System.out.println(msg.getBytes("UTF-8"));
          outStream.flush();
        }
        catch(IOException ex) {
          ex.printStackTrace();
        }
      }

但是在我的receive方法中,我没有找到一种方法来做到这一点:

public String receive() throws IOException {
   
    String line = "";
    InputStream inStream = socket.getInputStream();    
                
    int read = inStream.read();
    while (read!=10 && read > -1) {
      line+=String.valueOf((char)read);
      read = inStream.read();
    }
    if (read==-1) return null;
    line+=String.valueOf((char)read);       
    return line; 
    
  }

那么有没有一种快速的方法来指定缓冲区读取的字节是用 UTF-8 编码的?

编辑:好的,我像这样尝试使用BufferedReader

 public String receive() throws IOException {
    
    String line = "";           
    in = new BufferedReader(new InputStreamReader(socket.getInputStream(), "UTF-8"));           
    String readLine = "";   
    
    while ((readLine = in.readLine()) != null) {
        line+=readLine;
    }
    
    System.out.println("Line:"+line);
    
    return line;
   
  }

但它不起作用。 似乎套接字没有收到任何东西。

试图为未来的访客提供更多的光线。

经验法则:服务器和客户端必须在编码方案之间同步,因为如果客户端发送使用某种编码方案编码的数据而服务器正在使用其他编码方案读取数据,则永远无法实现预期的结果。

对于尝试测试这一点的人要注意的重要一点是不要在客户端使用 ASCII 编码(或者换句话说在客户端使用 ASCII 编码)并在服务器端使用 UTF8 解码(或者换句话说使用 UTF8 编码在服务器端)因为 UTF8 向后兼容 ASCII,所以可能会觉得“经验法则”是错误的,但不,它不是,所以最好在客户端使用 UTF8,在服务器端使用 UTF16,你就会明白。

使用套接字编码

我想要理解的最重要的事情是:最后通过套接字您将发送 BYTES 但这一切都取决于这些字节的编码方式

例如,如果我使用 Windows 命令提示符将输入发送到服务器(通过客户端 - 服务器套接字),那么数据将使用某种编码方案进行编码(我真的不知道是哪个),如果我使用另一个客户端将数据发送到服务器代码/程序然后我可以指定我想用于我的客户端套接字的 o/p 流的编码方案,然后所有数据将使用该编码方案转换/编码为 BYTES 并通过套接字发送。

现在,最后我仍然通过线路发送 BYTES,但这些是使用我指定的编码方案进行编码的。 如果假设在服务器端,我在读取套接字的 i/p 流时使用另一种编码方案,则无法实现预期的结果,如果我在服务器上也使用相同的编码方案(与客户端的编码方案相同),那么一切都将是完美

回答这个问题

在 Java 中,有特殊的“桥接”流( 在此处阅读),您可以使用它们来指定流的编码。

请注意:在 Java 中InputStreamOutputStream是 BYTE 流,因此使用这些流读取和写入的所有内容都将是 BYTES,您不能使用InputStreamOutputStream类的对象指定编码,因此您可以使用 Java 桥接类。

下面是客户端和服务器的代码片段,我试图展示如何在客户端的输出流和服务器的输入流上指定编码

只要我在两端指定相同的编码,一切都会很完美。

客户端:

        Socket clientSocket = new Socket("abc.com", 25050);
        OutputStreamWriter clientSocketWriter = (new OutputStreamWriter(clientSocket.getOutputStream(), "UTF8"));

服务器端:

    ServerSocket serverSocket = new ServerSocket(8001);
    Socket clientSocket = serverSocket.accept();
    // PLEASE NOTE: important thing below is I am specifying the encoding over my socket's input stream, and since Java's <<InputStream>> is a BYTE stream,  
    // so in order to specify the encoding I am using Java I/O's bridge class <<InputStreamReader>> and specifying my UTF8 encoding.
    // So, with this all my data (BYTES really) will be read from client socket as bytes "BUT" those will be read as UTF8 encoded bytes.
    // Suppose if I specify different encoding here, than what client is specifying in its o/p stream than data cannot read properly and may be all "?"
    InputStreamReader clientSocketReader = (new InputStreamReader(clientSocket.getInputStream(), "UTF8"));

尝试

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

然后

String readLine = "";
while ((readLine = in.readLine()) != null) {
    line+=readLine
}

使用以 utf-8 创建的InputStreamReaderOutputStreamWriter作为字符编码。

如果要阅读整行内容,可以使用BufferedReader包装InputStreamReader 同样,您可以使用环绕OutputStreamWriterBufferedWriterPrintWriter将数据作为行写出。

您应该了解unicode chars 和 bytes 之间区别 简而言之,无论编码如何,unicode 字符点(Java char s,或多或少)都是相同的。 编码会更改给定byte序列转换为的字符。

在您的代码中,您有一个String ,它实际上只是一个char序列。 您可以使用getBytes("UTF-8")将其转换为byte序列。 当您回读它时,您正在回读每个单独的byte (作为int ,但这是一个细节)——而不是每个char 您尝试使用普通转换将这些字节转换为chars ,这仅在字符的代码点值与字节的 int 值完全相等时才有效; 对于 UTF-8,这仅适用于“普通”字符。

您应该根据输入流中的字节和字符集重建一个String 一种方法是InputStream读入byte[] ,然后调用new String(byte[] bytes, String charset)

您还可以使用代表可读字符流的Reader InputStreamReader读取InputStream作为其字符流的源,然后BufferedReader可以获取字符流并使用它来生成String s,一次一行,如 ProgrammerJeff 的回答所示。

这对我有用,服务器端代码:

    try {   
    Scanner input = new Scanner(new File("myfile.txt"),"UTF-8");
    //send the first line only
    String line=input.nextLine();
    ServerSocket server = new ServerSocket(12345);
    Socket client = server.accept();
    PrintWriter out = new PrintWriter(
    new BufferedWriter(new OutputStreamWriter(
        client.getOutputStream(), "UTF-8")), true);
    out.println(line);
    out.flush();
    input.close();
    server.close();
    }catch (Exception e) {
        e.printStackTrace();
    }

客户端:

Socket mysocket = new Socket(SERVER_ADDR, 12345);
       bfr = new BufferedReader(new 
                InputStreamReader(mysocket.getInputStream(), "UTF-8"));
String tmp=bfr.readLine();

文本文件应编码为 UTF-8

BufferedReader rd  = null;
rd  = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM