Javaソケットプログラミング
-
19-08-2019 - |
質問
私は、Javaソケットを使用してObjectOutputStreamなどを試して、単純なクライアント/サーバーアプリケーションを構築しています。
このURLでチュートリアルを行っています http://java.sun .com / developer / technicalArticles / ALT / sockets ソケットを介してオブジェクトを転送することについて話すとき、途中で開始します。
クライアントのコードを参照 http:// pastebin。 com / m37e4c577 ただし、これは機能していないようで、何が機能していないのかわかりません。一番下にコメントアウトされたコードは、チュートリアルから直接コピーされています-これは、クライアントオブジェクトを作成する代わりにそれを使用するだけで機能します。
間違っていることを誰でも見ることができますか?
解決
問題は、ストリームを作成する順序です:
記事のサーバー(私が使用していると思われます)では、新しい接続が開かれると、サーバーは最初に入力ストリームを開き、次に出力ストリームを開きます。
public Connect(Socket clientSocket) {
client = clientSocket;
try {
ois = new ObjectInputStream(client.getInputStream());
oos = new ObjectOutputStream(client.getOutputStream());
} catch(Exception e1) {
// ...
}
this.start();
}
コメント付きのサンプルコードでは、逆の順序を使用します。最初に出力ストリームを確立し、次に入力ストリームを確立します。
// open a socket connection
socket = new Socket("localhost", 2000);
// open I/O streams for objects
oos = new ObjectOutputStream(socket.getOutputStream());
ois = new ObjectInputStream(socket.getInputStream());
しかし、あなたのコードは他の方法でそれを行います:
server = new Socket(host, port);
in = new ObjectInputStream(server.getInputStream());
out = new ObjectOutputStream(server.getOutputStream());
出力ストリーム/入力ストリームのペアを確立すると、ハンドシェイク情報を交換するまで停止するため、作成順序を一致させる必要があります。これを行うには、サンプルコードの34行目と35行目を入れ替えるだけです。
他のヒント
オブジェクトをどこにも書いていません。
リンクをもう一度確認してください。どこかで書く必要があります:
oos.writeObject( new Date() );
あなたのコードにはあなただけがあります
ois.readObject();
だからこそ
リマインダー。
ObjectOutputStreamを使用するときは、参照キャッシュを保持することに注意してください。オブジェクトを作成し、オブジェクトの内容を変更してから同じオブジェクトを再度送信すると、重複したデータが取得されます。例:
List list = new ArrayList();
list.add("value1");
out.writeObject(list);
list.clear();
list.add("value2");
out.writeObject(list);
クライアント側で、文字列<!> quot; value1 <!> quot;を持つ2つのリストを生成します。
これを回避するには、resetメソッドを呼び出して、同じオブジェクト参照を複数回書き込むときにストリームキャッシュをリセットする必要があります。
List list = new ArrayList();
list.add("value1");
out.writeObject(list);
out.reset();
list.clear();
list.add("value2");
out.writeObject(list);
おそらく最も基本的なものを最初に学びたいと思うでしょう。
これは、私がコーディングしたばかりのサンプルです。
1つのクライアントのみに参加するサーバーを起動し、オブジェクトを送信して死にます。
ユーザー(あなた)がEnterを押すと、新しいクライアントが作成され、以前に作成されたサーバーに接続し、サーバーが送信するオブジェクトを読み取ります。
ここでは例外は処理されません。単純にするためだけに、これは例外を処理する方法ではありません。
ここですべての概念を理解すると、チュートリアルの概念を理解しやすくなります。
import java.io.*;
import java.net.*;
import java.util.*;
public class SimpleServer implements Runnable {
// Creates the server, send a "date" and die.
public void run() {
try {
ServerSocket server = new ServerSocket( 8090 );
Date creationDate = new Date();
System.out.println("(Server) Server is ready "
+ "and running at " + creationDate );
Socket uniqueClient = server.accept();
// We will write using this "chained" object.
ObjectOutputStream out = new ObjectOutputStream(
uniqueClient.getOutputStream());
out.writeObject( creationDate );
// close all, at this point forget about the exceptions.
// this is lesson #1
out.close();
uniqueClient.close();
server.close();
System.out.println("(Server) The server is down");
}catch( IOException ioe ) {}
}
public static void main ( String [] args ) throws IOException ,
ClassNotFoundException {
Thread serverThread = new Thread( new SimpleServer() );
serverThread.start(); // start the server thread ... doh..
System.out.println("(Client) Press enter when you want "+
" to connect to the server...");
Scanner scanner = new Scanner( System.in );
scanner.nextLine();
Socket client = new Socket("localhost", 8090 );
// Read from this object.
ObjectInputStream in = new ObjectInputStream( client.getInputStream() );
Date date = ( Date ) in.readObject();
System.out.println("(Client) Current time is: " + new Date() );
System.out.println("(Client) Object read from server : " + date );
in.close();
client.close();
}
}
これが役立つことを願っています。
デバッガを試した場合、問題がどこにあったかがわかります(おそらくそうではありません)
問題は、ObjectOutputStreamがヘッダーを書き込み、ObjectInputStreamがそのヘッダーを読み取ることです。最初にObjectInputStreamを作成しました。これは、書き込まれないヘッダーを読み取ろうとしていることを意味します。
解決策:常に最初にObjectOutputStreamを作成し、ObjectInputStreamを作成する前にflush()します。
出力ストリームがブロックしないため、outputStream
を開く方が適切です。次に、Stream
を待つ入力ストリームがあります。すべてのストリームの後、ストリームに書き込み、フラッシュします-outputStream.flush()
バイトのデータを送信します。また、入力を読み取るためのもう一方のメソッドも必要になります。単にinputStream.read()
がすべてのバイトをchar
の整数として読み取るか、BufferedReader
またはScanner
を使用するかです。ほとんどすべての方法を使用しましたが、最も効果的な送信方法はoutputStream.write(String)
で、一連のbyte
sを<=> sとしてストリームに書き込み、<=>を読み取ると1つの<=>を読み取ります。これがお役に立てば幸いです。