【问题标题】:Socket InputStream and UTF-8套接字输入流和 UTF-8
【发布时间】:2014-06-24 17:46:23
【问题描述】:

我正在尝试与 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;
   
  }

但它不起作用。好像socket什么都没有收到。

【问题讨论】:

    标签: java sockets encoding utf-8


    【解决方案1】:

    努力为未来的访客提供更多亮点。

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

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

    使用套接字编码

    我想要理解的最重要的一点是:最终通过套接字发送字节,但这完全取决于这些字节的编码方式

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

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

    回答这个问题

    在 Java 中,有一些特殊的“桥”流(阅读 here)可以用来指定流的编码。

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

    下面是客户端和服务端的sn-p代码,这里我试图展示如何在客户端的输出流和服务端的输入流上指定编码

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

    客户端:

            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"));
    

    【讨论】:

      【解决方案2】:

      试试

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

      然后

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

      【讨论】:

      • 好的,我试过了,但它不起作用。它不打印任何东西。
      • 我认为它仍然停留在一段时间
      • 或者简单地使用 java 8:`in.lines().collect(Collectors.joining(StringUtils.LF));'此外,您可能希望将阅读器的创建包装到 try-catch 中。
      【解决方案3】:

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

      如果你想阅读整行内容,你可以用BufferedReader 包裹InputStreamReader。 同样,您可以使用包裹在OutputStreamWriter 周围的BufferedWriterPrintWriter 将数据写成行。

      【讨论】:

        【解决方案4】:

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

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

        您应该根据输入流中的字节和字符集来重构String。执行此操作的一种方法是read the InputStream into a byte[],然后致电new String(byte[] bytes, String charset)

        您还可以使用Reader,它表示可读的字符流。 InputStreamReader 读取一个InputStream 作为其字符流的源,然后BufferedReader 可以获取那个字符流并使用它来生成Strings,一次一行,如程序员杰夫的回答说明了。

        【讨论】:

          【解决方案5】:

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

              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

          【讨论】:

            【解决方案6】:
            BufferedReader rd  = null;
            rd  = new BufferedReader(new InputStreamReader(connection.getInputStream(),"UTF-8"));
            

            【讨论】:

              猜你喜欢
              • 2011-05-29
              • 2012-09-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-04-06
              相关资源
              最近更新 更多