[英]java socket InputStream hangs/blocks on both client and server
我最近正在開發一個旨在遠程關閉瀏覽器的小程序。 基本程序如下:
服務器端:
客戶端:
下面的代碼:
服務器.java
package socket;
import java.io.IOException;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Enumeration;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Server {
private static ExecutorService es = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws IOException {
InetAddress targetAddress = null;
NetworkInterface ni = NetworkInterface.getByName("eth2");
System.out.println(ni);
Enumeration<InetAddress> inetAddresses = ni.getInetAddresses();
while(inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if(inetAddress.toString().startsWith("/10")) {
targetAddress = inetAddress;
break;
}
}
ServerSocket sSocket = new ServerSocket(11111, 0, targetAddress);
while(true) {
System.out.println("Server is running...");
Socket client = sSocket.accept();
System.out.println("Client at: " + client.getRemoteSocketAddress());
es.execute(new ClientRequest(client));
}
}
}
客戶端請求.java
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
public class ClientRequest implements Runnable {
private Socket client;
public ClientRequest(Socket client) {
this.client = client;
}
@Override
public void run() {
try {
System.out.println("Handled by: " + Thread.currentThread().getName());
// get input/output streams for client socket
InputStream cis = client.getInputStream();
OutputStream cos = client.getOutputStream();
// buffer size : 1024 ?
byte[] buffer = new byte[1024];
int recvSize;
int totalRecvSize = 0;
while(-1 != (recvSize = cis.read(buffer, totalRecvSize, 1024 - totalRecvSize))) {
totalRecvSize += recvSize;
}
String command = new String(buffer, "utf-8");
System.out.println("Command from client: " + command);
String commandNative = CommandMap.getNativeCommand(command.trim());
if(null != commandNative) {
Process np = Runtime.getRuntime().exec(commandNative);
InputStream is = np.getInputStream();
byte[] bufferProcess = new byte[1024];
int bytesRead;
int totalBytesRead = 0;
while(-1 != (bytesRead = is.read(bufferProcess, totalBytesRead, 1024 - totalBytesRead))) {
totalBytesRead += bytesRead;
}
// give feed back of process output
cos.write(bufferProcess);
// close process input stream
is.close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(null != client) {
try {
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
最后, Client.java
package socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.charset.Charset;
public class Client {
private static final int BUF_SIZE = 1024;
// feedback message size will not exceed 1024 bytes
private static final byte[] BUFFER = new byte[BUF_SIZE];
public static void main(String[] args) throws UnknownHostException, IOException, InterruptedException {
Socket socket = new Socket("10.117.37.176", 11111);
System.out.println("Connected to Server...");
OutputStream os = socket.getOutputStream();
InputStream is = socket.getInputStream();
String command = "kill ie";
byte[] commandBytes = command.getBytes(Charset.forName("utf-8"));
System.out.println("Send: " + command);
os.write(commandBytes);
System.out.println("After send: " + command);
int totalRecv = 0;
int recvSize;
while(-1 != (recvSize = is.read(BUFFER, totalRecv, BUF_SIZE - totalRecv))) {
totalRecv += recvSize;
}
String feedback = new String(BUFFER, "utf-8");
System.out.println("Feedback: " + feedback);
socket.close();
}
}
重申問題:
我想知道這段代碼中隱藏的原因是什么?
您的套接字讀取代碼正在讀取直到 EOF。 在關閉套接字之前,您不會收到 EOF。 因此,您的代碼永遠不會繼續。
如果您只想在套接字連接上發送單個命令,則在編寫命令后關閉 OutputStream(使用Socket.shutdownOutput()
)。
如果您想在單個套接字連接上發送多個命令,那么您需要想出一種分隔每個命令的方法(此處為簡單示例)。
您正在閱讀直到兩端的 EOS,這是一個糟糕的選擇,因為您無法“發送” EOS 而不會失去在同一連接上發送更多數據的能力。 你需要重新設計你的應用程序協議,這樣你就可以一次讀取一個命令,而不需要關閉連接來完成它。 例如,發送行,或長度字前綴,或諸如 XML 或 Java 對象序列化之類的自描述協議,或者您可以通過 DataInputStream 讀取的任何內容,而無需依賴 EOFException。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.