![](/img/trans.png)
[英]Java parallel stream: how to wait for threads for a parallel stream to finish?
[英]Java - Wait for stream to finish writing?
我有一個在 java 中運行的“服務器”,我通過字節數組將文件發送到“客戶端”(android 系統)。 該功能運行良好,但我注意到當我嘗試發送更大的文件 (1MB+) 時,它在關閉之前沒有成功寫入所有字節(例如:嘗試發送 5mb,它只發送了 902 個字節)。 有沒有辦法讓代碼在關閉流之前等待流完成寫入? 下面是代碼和堆棧跟蹤。 本質上,當附加和發送文件時(在處理 GUI 的類中)調用發送消息方法。 在這種情況下,我沒有嘗試從客戶端接收數據,只是將數據發送到客戶端。
編輯:我知道我現在只將字節數組設置為 1MB。 我有它 5MB,它仍然只寫 <1MB。 即使在 1MB 時,它仍然只寫入 902 個字節。
EDIT2:我在客戶端上發布了一些處理接收數據的代碼。
public void sendMessage(File file) {
if(mOut != null) {
try {
FileInputStream inStream = new FileInputStream(file);
byte[] message = new byte[1024 * 1024];
inStream.read(message);
mOut.write(message, 0, message.length);
mOut.flush();
inStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void run() {
super.run();
running = true;
try {
System.out.println("S: Connecting...");
ServerSocket serverSocket = new ServerSocket(SERVERPORT);
Socket client = serverSocket.accept();
linked = true;
System.out.println("S: Receiving...");
try {
mOut =client.getOutputStream();
InputStream in = client.getInputStream();
while(running) {
byte[] message = new byte[1024 * 1024];
in.read(message);
if(message != null && messageListener != null) {
messageListener.messageReceived(message);
}
}
} catch (Exception ex) {
System.out.println("S:Error");
ex.printStackTrace();
} finally {
client.close();
System.out.println("S:Done");
}
} catch (Exception ex) {
System.out.println("S: Error");
ex.printStackTrace();
}
}
---------------------------------------------------------------------------
java.net.SocketException: Connection reset by peer: socket write error
at java.net.SocketOutputStream.socketWrite0(Native Method)
at java.net.SocketOutputStream.socketWrite(Unknown Source)
at java.net.SocketOutputStream.write(Unknown Source)
at Server.sendMessage(Server.java:34)
at ServerBoard$2.actionPerformed(ServerBoard.java:57)
at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
at java.awt.Component.processMouseEvent(Unknown Source)
at javax.swing.JComponent.processMouseEvent(Unknown Source)
at java.awt.Component.processEvent(Unknown Source)
at java.awt.Container.processEvent(Unknown Source)
at java.awt.Component.dispatchEventImpl(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
at java.awt.Container.dispatchEventImpl(Unknown Source)
at java.awt.Window.dispatchEventImpl(Unknown Source)
at java.awt.Component.dispatchEvent(Unknown Source)
at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
at java.awt.EventQueue.access$000(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.awt.EventQueue$3.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.awt.EventQueue$4.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.security.ProtectionDomain$1.doIntersectionPrivilege(Unknown Source)
at java.awt.EventQueue.dispatchEvent(Unknown Source)
at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
at java.awt.EventDispatchThread.run(Unknown Source)
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at Server.run(Server.java:58)
這是客戶端的代碼片段。
public void run() {
mRun = true;
serverMessage = new byte[1024 * 1024];
try {
InetAddress serverAddr = InetAddress.getByName(SERVERIP);
Log.e("TCP Client", "C:Connecting...");
Socket socket = new Socket(serverAddr, SERVERPORT);
try {
in = socket.getInputStream();
while(mRun) {
in.read(serverMessage);
if(serverMessage != null && mMessageListener != null) {
mMessageListener.messageReceived(new String(serverMessage));
}
serverMessage = null;
}
Log.e("RESPONSE FROM SERVER","S:Received Message: '" + serverMessage + "'");
} catch(Exception ex) {
Log.e("TCP","S: Error", ex);
} finally {
socket.close();
}
} catch(Exception ex) {
Log.e("TCP","C: Error", ex);
}
}
首先, 讀取的JavaDoc:
從輸入流中讀取一定數量的字節並將它們存儲到緩沖區數組 b 中。 實際讀取的字節數作為整數返回。 此方法會阻塞,直到輸入數據可用、檢測到文件結尾或拋出異常。
由於源是一個套接字,它可能返回比預期少的字節,即使緩沖區的大小為 1 MB,返回 902 KB 也可以。 你必須循環直到流結束。
以下方法讀取所有字節,而不是調用偵聽器:
byte[] message = new byte[0];
byte[] buffer = new byte[4096];
int len;
while(( len = is.read( buffer )) > -1 ) {
byte[] tmp = new byte[message.length+len];
System.arraycopy( message, 0, tmp, 0, message.length );
System.arraycopy( buffer , 0, tmp, message.length, len );
message = tmp;
}
messageListener.messageReceived( message );
如您所見,發生了很多重新分配:您必須重新設計協議以首先發送文件的大小並分配一次接收緩沖區。
在完成閱讀之前,您將讀取緩沖區設置為 null:
in = socket.getInputStream();
while(mRun) {
in.read(serverMessage);
if(serverMessage != null && mMessageListener != null) {
mMessageListener.messageReceived(new String(serverMessage));
}
serverMessage = null;
}
這將導致 NullPointerException 並且您的代碼將關閉套接字。
設置socket.setSendBufferSize(1024)
(你用來發送的)也確保在接收時你讀取了1024
字節的塊。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.