[英]Java Networking: Explain InputStream and OutputStream in Socket
我使用ServerSocket
創建了一個服務器。 之后,我使用Socket
創建了Client,並連接到該服務器。
之后,我使用InputStream執行“一些東西”,並從Socket Object獲取OutputStream。 但是,我真的不太了解inputStream和outputStream。 這是我的簡單代碼:
private Socket sock = null;
private InputStream sockInput = null;
private OutputStream sockOutput = null;
...
String msg = "Hello World";
byte[] buffer = null;
try {
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
buffer = new byte[test.length()];
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
sockInput.read(buffer, 0, test.length());
System.out.println(new String(buffer));
} catch (IOException e1) {
e1.printStackTrace();
}
結果將是:“Hello World”和“Hello StackOverFlow”。
這是服務器端代碼:
private int serverPort = 0;
private ServerSocket serverSock = null;
public VerySimpleServer(int serverPort) {
this.serverPort = serverPort;
try {
serverSock = new ServerSocket(this.serverPort);
}
catch (IOException e){
e.printStackTrace(System.err);
}
}
// All this method does is wait for some bytes from the
// connection, read them, then write them back again, until the
// socket is closed from the other side.
public void handleConnection(InputStream sockInput, OutputStream sockOutput) {
while(true) {
byte[] buf=new byte[1024];
int bytes_read = 0;
try {
// This call to read() will wait forever, until the
// program on the other side either sends some data,
// or closes the socket.
bytes_read = sockInput.read(buf, 0, buf.length);
// If the socket is closed, sockInput.read() will return -1.
if(bytes_read < 0) {
System.err.println("Server: Tried to read from socket, read() returned < 0, Closing socket.");
return;
}
System.err.println("Server: Received "+bytes_read
+" bytes, sending them back to client, data="
+(new String(buf, 0, bytes_read)));
sockOutput.write(buf, 0, bytes_read);
// This call to flush() is optional - we're saying go
// ahead and send the data now instead of buffering
// it.
sockOutput.flush();
}
catch (Exception e){
System.err.println("Exception reading from/writing to socket, e="+e);
e.printStackTrace(System.err);
return;
}
}
}
public void waitForConnections() {
Socket sock = null;
InputStream sockInput = null;
OutputStream sockOutput = null;
while (true) {
try {
// This method call, accept(), blocks and waits
// (forever if necessary) until some other program
// opens a socket connection to our server. When some
// other program opens a connection to our server,
// accept() creates a new socket to represent that
// connection and returns.
sock = serverSock.accept();
System.err.println("Server : Have accepted new socket.");
// From this point on, no new socket connections can
// be made to our server until we call accept() again.
sockInput = sock.getInputStream();
sockOutput = sock.getOutputStream();
}
catch (IOException e){
e.printStackTrace(System.err);
}
// Do something with the socket - read bytes from the
// socket and write them back to the socket until the
// other side closes the connection.
handleConnection(sockInput, sockOutput);
// Now we close the socket.
try {
System.err.println("Closing socket.");
sock.close();
}
catch (Exception e){
System.err.println("Exception while closing socket.");
e.printStackTrace(System.err);
}
System.err.println("Finished with socket, waiting for next connection.");
}
}
public static void main(String argv[]) {
int port = 54321;
VerySimpleServer server = new VerySimpleServer(port);
server.waitForConnections();
}
我的問題是:
當我使用sockOutput.write
,我可以通過sockInput.read
返回這些消息。 那么,那些消息已被保存,對吧? 如果這是真的,它是否保存在我創建的服務器上,或者只保存在其他東西中,例如Socket Object
。
如果我已經寫入套接字字符串A1,A2,...那么我將分別收到A1,A2,...一個字符串,對嗎?
套接字是一種抽象,可用於與網絡中的某些內容進行通信。 見下圖......
在Java中,要通過套接字發送數據,您將從中獲取OutputStream
(1),並寫入OutputStream
(您輸出一些數據)。
要從套接字讀取數據,您將獲得其InputStream
,並從此第二個流中讀取輸入。
您可以將流視為連接到牆上插座的一對單向管道。 在牆的另一邊發生的事情不是你的問題!
在您的情況下,服務器有另一個套接字(連接的另一端)和另一對流。 它使用其InputStream
(2)從網絡讀取,並使用其OutputStream
(3)將相同的數據通過網絡寫回客戶端,客戶端通過其InputStream
(4)再次讀取它完成往返。
Client Server
1. OutputStream -->\ /--> 2. InputStream -->
Socket <--> network <--> ServerSocket |
4. InputStream <--/ \<--3. OutputStream <--
更新:回復評論:
請注意,流和套接字只發送原始字節; 他們在這個抽象層面上沒有“信息”的概念。 因此,如果您發送X個字節和另外X個字節,然后讀取X個字節並讀取另外X個字節,那么您的系統就像有兩個消息一樣,因為這就是您划分字節的方式。
如果發送X個字節和另外X個字節,然后讀取長度為2X的回復,那么您可能能夠讀取單個組合的“消息”,但正如您所注意到的,流的底層實現可以選擇何時到傳遞大塊的字節,因此它可能返回X字節,然后是X字節,稍后或一次2X,或0.5X四次......
InputStream
和OutputStream
是兩個完全獨立的流。 你寫入的內容與你從另一個中讀到的內容沒有先驗關系。 InputStream
為您提供服務器決定發送給您的任何數據。 我還想評論你的代碼:
sockOutput.write(msg.getBytes(), 0, test.length());
sockOutput.write("Hello StackOverFlow".getBytes(), 0, test.length());
您使用字符串test
的長度(未在代碼中顯示),這與您作為第一個參數傳遞的字節數組無關。 這可能導致ArrayIndexOutOfBoundsException
或截斷您的預期消息。
查看服務器端代碼時,編寫的代碼不正確。 你需要try { handleConnection(...); } finally { socket.close(); }
try { handleConnection(...); } finally { socket.close(); }
try { handleConnection(...); } finally { socket.close(); }
,以確保適當的清除錯誤之后,以及正常完成時相同。 您的代碼永遠不會關閉服務器端的任何內容。
最后,最重要的是,您的整個代碼都是以可能導致死鎖的方式編寫的。 通常,您需要一個單獨的線程來讀取和寫入; 否則可能發生以下情況:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.