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

package com.examenginedashboard.docker.utils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.HashMap; import com.examenginedashboard.CONSTANTS.MyValuesConstans; import com.examenginedashboard.codePG.service.HttpHijack; import com.github.dockerjava.api.DockerClient; import com.github.dockerjava.api.command.CreateContainerResponse; import com.github.dockerjava.api.command.DockerCmdExecFactory; import com.github.dockerjava.api.command.ExecCreateCmdResponse; import com.github.dockerjava.api.command.InspectExecResponse; import com.github.dockerjava.api.model.Bind; import com.github.dockerjava.api.model.ExposedPort; import com.github.dockerjava.api.model.Ports; import com.github.dockerjava.api.model.Volume; import com.github.dockerjava.core.DefaultDockerClientConfig; import com.github.dockerjava.core.DockerClientBuilder; import com.github.dockerjava.core.DockerClientConfig; import com.github.dockerjava.core.command.ExecStartResultCallback; import com.github.dockerjava.jaxrs.JerseyDockerCmdExecFactory; public class APIBasedCodeCompiler { public static void connectToDocker(){ DockerCmdExecFactory dockerCmdExecFactory = new JerseyDockerCmdExecFactory() .withReadTimeout(1000) .withConnectTimeout(1000) .withMaxTotalConnections(100) .withMaxPerRouteConnections(10); ExposedPort tcp22 = ExposedPort.tcp(22); ExposedPort tcp23 = ExposedPort.tcp(23); Ports portBindings = new Ports(); portBindings.bind(tcp22, Ports.Binding.bindPort(11022)); portBindings.bind(tcp23, Ports.Binding.bindPort(11023)); DockerClientConfig config = DefaultDockerClientConfig. createDefaultConfigBuilder() .withDockerHost("tcp://127.0.0.1:2375") .build(); DockerClient docker = DockerClientBuilder.getInstance(config).build(); Volume volume1 = new Volume("/mydockerbuild"); CreateContainerResponse containerResp = docker.createContainerCmd("busybox") .withImage(MyValuesConstans.JAVA_DOCKER) .withCmd("sh", "-c", "while :; do sleep 1; done") .withAttachStderr(true) .withAttachStdout(true) .withAttachStdin(true) .withVolumes(volume1) .withBinds(new Bind("/home/itcostcut/mydockerbuild",volume1)) .exec(); String containerId = containerResp.getId(); docker.startContainerCmd(containerId).exec(); System.out.println("HOST........... "); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); ByteArrayOutputStream stderr = new ByteArrayOutputStream(); final String[] command = {"bash", "-c", "cd mydockerbuild/ && javac NumberToWord.java && java -cp . NumberToWord exit"}; ExecCreateCmdResponse execCreateCmdResponse = docker.execCreateCmd(containerId) .withAttachStdout(true) .withAttachStderr(true) .withAttachStdin(true) .withCmd(command) .exec(); InspectExecResponse inpect = docker.inspectExecCmd(execCreateCmdResponse.getId()).exec(); System.out.println("Inspect Info........... "+inpect); HashMap<String, String> headers = new HashMap<>(); headers.put("Content-Type", "application/json"); HttpHijack ws; // http://localhost:4243 //unix:///var/run/docker.sock docker.execStartCmd(execCreateCmdResponse.getId()).exec( new ExecStartResultCallback(stdout, stderr)); System.out.println("Output: "+stdout.toString()); System.out.println("Error: "+stderr.toString()); try { ws = new HttpHijack(new URI("http://127.0.0.1:2375/v1.27/exec/" + execCreateCmdResponse.getId() + "/start")); String payload = "{\"Detach\": false,\"Tty\": false}"; ws.post(headers, payload); String request = "10"; //Thread.sleep(3000); InputStream input = ws.send(request); int expectedDataLength=5000; ByteArrayOutputStream baos = new ByteArrayOutputStream(expectedDataLength); byte[] chunk = new byte[expectedDataLength]; int numBytesJustRead; while((numBytesJustRead = input.read(chunk)) != -1) { baos.write(chunk, 0, numBytesJustRead); } System.out.println("Result ............... "+baos.toString()); } catch (URISyntaxException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }} public static void main(String[] args){ connectToDocker(); }} 

下面是连接到Java Docker的HttpHijack.java类。

 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(); }} 

我会尽力解释我想要达到的目标。 在我的scheme中,我试图在Docker上执行一些Java程序,以便使用Java:7泊坞窗图像。 command = {“bash”,“-c”,“cd mydockerbuild / && javac NumberToWord.java && java -cp。NumberToWord exit”}; 用于运行java代码,而NumberToWord.java是java类。 我们可以采取任何Java代码运行,但它应该需要一些input执行在我的情况下用户input是10。

问题是,当我读取从socket.getInputStream输出的一些行的输出是在二进制字符请参阅下面的日志。

 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 ............... 

输出实际上如图像最终输出在这里所示

问题在于docker原始stream。 它将stdoudstderr复用成一个通道。 为此,在每个内容位之前,它发送一个8位标题。

  • 如果以下内容用于stdout,则第一位是1,stderr是2,stdin是0。
  • 第二,第三和第四位总是零
  • 最后4位是大端内容的长度。

要解码,请执行以下操作:

  1. 阅读标题
  2. 确定内容的长度
  3. 阅读内容(请注意,即使内容是stderr,我们不需要它,我们仍然需要阅读它)。
  4. 如果内容是实际内容,则将其添加到缓冲区

以下testing为您提供的数组执行此操作:

 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 !!