Java 从socket.getInputStream()读取时返回的二进制字符

Java 从socket.getInputStream()读取时返回的二进制字符,java,sockets,docker,character-encoding,java-io,Java,Sockets,Docker,Character Encoding,Java Io,输出实际上如图所示问题在于docker原始流。它将stdoud和stderr多路复用到一个通道中。为此,在内容的每一位之前,它发送一个8位头 如果以下内容用于stdout,则第一位为1,2用于stderr,0用于stdin 第二、第三和第四位始终为零 最后4位是以big-endian表示的内容长度 要对此进行解码,请执行以下操作: 阅读标题 确定内容长度 阅读内容(注意,即使内容是针对stderr的,我们不想要它,我们仍然需要阅读它) 如果内容是实际内容,则将其添加到缓冲区 以下测试对您提供

输出实际上如图所示

问题在于docker原始流。它将
stdoud
stderr
多路复用到一个通道中。为此,在内容的每一位之前,它发送一个8位头

  • 如果以下内容用于stdout,则第一位为1,2用于stderr,0用于stdin
  • 第二、第三和第四位始终为零
  • 最后4位是以big-endian表示的内容长度
要对此进行解码,请执行以下操作:

  • 阅读标题
  • 确定内容长度
  • 阅读内容(注意,即使内容是针对stderr的,我们不想要它,我们仍然需要阅读它)
  • 如果内容是实际内容,则将其添加到缓冲区
  • 以下测试对您提供的阵列执行此操作:

    May 27, 2017 3:46:14 PM com.examenginedashboard.codePG.
     service.HttpHijack  post
      INFO: header: Content-Type: application/vnd.
      docker.raw-stream
      May 27, 2017 3:46:14 PM com.examenginedashboard.
      codePG.service.HttpHijack post
     INFO: header: Connection: Upgrade
     May 27, 2017 3:46:14 PM com.examenginedashboard.
     codePG.service.HttpHijack post
     INFO: header: Upgrade: tcp
      May 27, 2017 3:46:14 PM com.examenginedashboard.
      codePG.service.HttpHijack post
     INFO: header: Api-Version: 1.27
     May 27, 2017 3:46:14 PM com.examenginedashboard.
     codePG.service.HttpHijack post
     INFO: header: Docker-Experimental: false
     May 27, 2017 3:46:14 PM com.examenginedashboard.
      codePG.service.HttpHijack post
     INFO: header: Server: Docker/17.03.1-ce (linux)
      May 27, 2017 3:46:14 PM com.examenginedashboard.
     codePG.service.HttpHijack post
     INFO: header: 
     Input Bytes ...... [B@6436a7db
     Socket String ..............    Socket[addr=/127.0.0.1,port=2375,
      localport=60804]
      Result ............... 
    

    请更好地格式化代码(缩进可以提高可读性)。在这种情况下很难,但请提供一个工作示例,或者至少告诉我们服务器在做什么。@ThijsSteel我已经编辑了这个问题,并试图解释我的场景。请看一看。这将是非常有帮助的。!!我不能退出,因为我看到了错误。我确实看到一些错误,当您写入内容长度时,您使用payload.length(),而应该是字节数组的长度(UTF-8具有可变长度)响应头中有什么?也许反应很快?更重要的是,为什么不使用
    HttpURLConnection
    ?@ThijsSteel感谢您的回复。。预期的输出是:您的话在这里!!你的话就在这里!!你的话就在这里!!来吧,喜欢它!!但是,如果您在第一行结果中看到上面的链接[此处的最终输出]…[某些二进制字符]在那里,我不明白为什么会出现此二进制字符。是否存在任何编码错误。再次感谢。您太棒了!!非常感谢,它就像一个符咒!!我已经工作了8天多了。我不明白整件事。有什么参考文件可以让我了解整个过程吗?。可能是我有点野心勃勃,我试着运行另一种编程语言,它有下面的序列它不工作它有下面的序列。。。。。[2、0、0、0、0、60、98、97、115、104、58、32、108、105、110、101、32、48、58、32、99、100、58、32、109、121、100、111、99、107、101、114、98、117、105、108、100、47、58、32、78111、32、115、117、99、104、32、102、105、108、101、32、111、114、32、114、100、114、114、101、101、99、116、111、111、116、111、111、111、111、114、10]我不理解行的内容大小=((标题[4]&0xFF)对于第一个问题:请注意,第一个字符是2,这意味着这是一条错误消息。如果您想解决第二个问题,也可以保存这些字符:我假设您知道整数存储为32位。一个字节是8位。我在该行中所做的是将所有字节合并为一个整数
    package com.examenginedashboard.codePG.service;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.io.OutputStream;
    import java.net.Socket;
    import java.net.URI;
    import java.nio.charset.StandardCharsets;
    import java.util.Map;
    import java.util.Map.Entry;
    
    import javax.net.SocketFactory;
    import javax.net.ssl.SSLSocketFactory;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    public class HttpHijack {
    
    private static final Logger log =  LoggerFactory.  getLogger(HttpHijack.class);
    
    private URI uri;
    
    private Socket socket;
    
    private boolean handshakeCompleted;
    
    private InputStream chin;
    
    private OutputStream chout;
    
    public HttpHijack(URI url) {
        uri = url;
    }
    
    public void post(Map<String, String> headers, String payload) throws java.io.IOException {
        String host = uri.getHost();
        System.out.println("Hostname ........."+host);
        String path = uri.getPath();
        System.out.println("Path..............."+path);
        if (path.equals("")) {
            path = "/";
        }
    
        String query = uri.getQuery();
        System.out.println("Query................"+query);
        if (query != null) {
            path = path + "?" + query;
        }
    
        socket = createSocket();
        chout = socket.getOutputStream();
        StringBuffer extraHeaders = new StringBuffer();
        if (headers != null) {
            for (Entry<String, String> entry : headers.entrySet()) {
                extraHeaders.append(entry.getKey() + ": " + entry.getValue() + "\r\n");
            }
        }
    
        StringBuffer request = new StringBuffer();
        request.append("POST " + path + " HTTP/1.1\r\n");
        request.append("Upgrade: tcp\r\n");
        request.append("Connection: Upgrade\r\n");
        request.append("Host: " + host + "\r\n");
        if (headers != null) {
            for (Entry<String, String> entry : headers.entrySet()) {
                request.append(entry.getKey() + ": " + entry.getValue() + "\r\n");
            }
        }
    
        request.append("Content-Length: " + payload.length() + "\r\n");
        request.append("\r\n");
        request.append(payload);
    
        chout.write(request.toString().getBytes());
        chout.flush();
    
        chin = socket.getInputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(chin));
        String header = reader.readLine();
        if (!header.equals("HTTP/1.1 101 UPGRADED")) {
            throw new IOException("Invalid handshake response: " + header);
        }
    
        do {
            header = reader.readLine();
            log.info("header: {}", header);
        } while (!header.equals(""));
    
        handshakeCompleted = true;
    }
    
    private Socket createSocket() throws java.io.IOException {
        String scheme = uri.getScheme();
        String host = uri.getHost();
    
        int port = uri.getPort();
        if (port == -1) {
            if (scheme.equals("https")) {
                port = 443;
            } else if (scheme.equals("http")) {
                port = 80;
            } else {
                throw new IllegalArgumentException("Unsupported scheme");
            }
        }
    
        if (scheme.equals("https")) {
            SocketFactory factory = SSLSocketFactory.getDefault();
            return factory.createSocket(host, port);
        } else {
            return new Socket(host, port);
        }
    }
    
    public InputStream send(String command) throws java.io.IOException {
        if (!handshakeCompleted) {
            throw new IllegalStateException("Handshake not complete");
        }
    
        chout.write(command.getBytes(StandardCharsets.UTF_8));
        System.out.println("Input Bytes ...... "+command.getBytes("UTF-8"));
        chout.flush();
        // looks like "exit" can't explicitly close the session,
        // shutdown output stream to force close it
        // so that stdout/stderr can be consumed via inputstream
            socket.shutdownOutput();
            System.out.println("Socket String .............. "+socket.toString());
    
            return socket.getInputStream();
    
    }
    
    public void close() throws java.io.IOException {
        chin.close();
        chout.close();
        socket.close();
    }}
    
    May 27, 2017 3:46:14 PM com.examenginedashboard.codePG.
     service.HttpHijack  post
      INFO: header: Content-Type: application/vnd.
      docker.raw-stream
      May 27, 2017 3:46:14 PM com.examenginedashboard.
      codePG.service.HttpHijack post
     INFO: header: Connection: Upgrade
     May 27, 2017 3:46:14 PM com.examenginedashboard.
     codePG.service.HttpHijack post
     INFO: header: Upgrade: tcp
      May 27, 2017 3:46:14 PM com.examenginedashboard.
      codePG.service.HttpHijack post
     INFO: header: Api-Version: 1.27
     May 27, 2017 3:46:14 PM com.examenginedashboard.
     codePG.service.HttpHijack post
     INFO: header: Docker-Experimental: false
     May 27, 2017 3:46:14 PM com.examenginedashboard.
      codePG.service.HttpHijack post
     INFO: header: Server: Docker/17.03.1-ce (linux)
      May 27, 2017 3:46:14 PM com.examenginedashboard.
     codePG.service.HttpHijack post
     INFO: header: 
     Input Bytes ...... [B@6436a7db
     Socket String ..............    Socket[addr=/127.0.0.1,port=2375,
      localport=60804]
      Result ............... 
    
    public static void main(String[] args) throws FileNotFoundException, IOException {
    
        byte[] data = new byte[] {1, 0, 0, 0, 0, 0, 0, 102, 89, 111, 117, 114, 32, 119, 111, 114, 100, 115, 32, 97, 114, 101, 32, 104, 101, 114, 101, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 32, 33, 33, 10, 89, 111, 117, 114, 32, 119, 111, 114, 100, 115, 32, 97, 114, 101, 32, 104, 101, 114, 101, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 32, 33, 33, 10, 89, 111, 117, 114, 32, 119, 111, 114, 100, 115, 32, 97, 114, 101, 32, 104, 101, 114, 101, 46, 46, 46, 46, 46, 46, 46, 46, 46,46, 46, 32, 33, 33, 10, 1, 0, 0, 0, 0, 0, 0, 21, 105, 110, 112, 117, 116, 32, 105, 110, 32, 87, 111, 114, 100, 115, 32, 58, 32, 32, 84, 101, 110, 1, 0, 0, 0, 0, 0, 0, 1, 10, 1, 0, 0, 0, 0, 0, 0, 19, 67, 79, 77, 69, 32, 79, 78, 32, 76, 73, 75, 69, 32, 73, 84, 32, 33, 33, 10};
        InputStream is = new ByteArrayInputStream(data); //I just created this for testing
    
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] header = new byte[8];
        while(true){
            if(!readFully(is, header, 8)) break;
            int contentSize = ((header[4] & 0xFF) << 24) | ((header[5] & 0xFF) << 16)
                    | ((header[6] & 0xFF) << 8) | (header[7] & 0xFF);
            boolean actualContent = header[0] == 1;
            byte[] content = new byte[contentSize];
            if(!readFully(is, content, contentSize))break;
            if(actualContent)
                baos.write(content, 0, contentSize);
            else
                System.err.println(new String(content));
        }
    
        System.out.println(baos.toString());
    
    
    }
    
    /**
     * Read a given number of bytes from the stream and store them in the buffer.
     * 
     * @param   is
     *          The input stream to read from
     * @param   buffer
     *          The buffer to store it in
     * @size    size
     *          The number of bytes to read
     * 
     * @return  True if and only if all bytes were read.
     */
    public static boolean readFully(InputStream is, byte[] buffer, int size) throws IOException{
        int totalAmountRead = 0;
        while(totalAmountRead < size){
            int amountJustRead = is.read(buffer, totalAmountRead, size-totalAmountRead);
            if(amountJustRead == -1)
                return false;
            totalAmountRead += amountJustRead;
        }
    
        return true;
    }
    
    Your words are here........... !!
    Your words are here........... !!
    Your words are here........... !!
    input in Words :  Ten
    COME ON LIKE IT !!