【发布时间】:2017-10-20 08:00:07
【问题描述】:
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();
}}
我将尝试解释我想要实现的目标。在我的场景中,我试图在 docker 上执行一些 Java 程序,因为我使用了 Java:7 docker 映像。 command = {"bash", "-c", "cd mydockerbuild/ && javac NumberToWord.java && java -cp . NumberToWord exit"};用于运行 java 代码, NumberToWord.java 是 java 类。我们可以运行任何 java 代码,但在我的情况下,它应该需要一些输入才能执行,用户输入是 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 ...............
输出实际如图Final Output Here
【问题讨论】:
-
请更好地格式化您的代码(缩进对可读性有很大帮助)。在这种情况下,这很难,但请为我们提供一个工作示例,或者至少告诉我们服务器在做什么。
-
@ThijsSteel 我已经编辑了问题并试图解释我的情况。请看一下。会有很大帮助的!!
-
我无法退出看到错误。我确实看到了一些错误,当您编写内容长度时,您使用的是 payload.length(),而不是它应该是字节数组的长度(UTF-8 具有可变长度)
-
响应头中有什么?也许响应被压缩了?更重要的是,你为什么不使用
HttpURLConnection? -
@ThijsSteel 感谢您的回复.. 预期输出是:您的话在这里............ !!你的话在这里…………!!你的话在这里…………!!来吧喜欢它!但是如果你看到上面的链接 [Final Output here] 在第一行结果.....[some binary character] is there 我不明白为什么这个二进制字符出现是有任何编码不匹配。谢谢再次。
标签: java sockets docker character-encoding java-io