3

私は現在、Android フォンで使用する通信システムを構築している学校のプロジェクトに参加しています。このために、すべてのクライアントに対してソケットを開いて通信させるサーバーを使用します。

以前、ソケットやスレッドの処理に問題なくチャット アプリケーションをいくつか実行したことがありますが、今回は、何らかの理由で頭がおかしくなりました。

問題は、ではなくServerSocketオブジェクトを開始するとすぐに、アプリケーションがリッスンを開始することです。serverSocket = new ServerSocket(5000)serverSocket.accept()

何故ですか?

次の方法を使用するとすぐに:

public void startListen(String port) {
try {
    serverSocket = new ServerSocket(Integer.parseInt(port));
    portField.setEditable(false);
} catch (IOException e) {
    printMessage("Failed to initiate serverSocket: " + e.toString());
}}

コマンド プロンプトでポートが Listening として表示されます ( を使用netstat)。呼び出さないと、ポートはリッスンとしてリストされません。

TCP 0.0.0.0:5000 コンピューター:0 リッスン中

それで、ServerSocketオブジェクトを使用するときに欠けているものはありますか? を使用している古いプログラムServerSocketは、 を呼び出すまでリッスンを開始しませんaccept()

4

3 に答える 3

8

Java ServerSocket について話している場合listen、おそらくクライアント側のソケットとは異なるため、メソッドはありません。その場合、(コンストラクター内または の一部としてbind) ポート番号を取得すると、先に進んで自動的にリッスンできます。

「通常の」ソケット (BSD 風) に listen がある理由は、クライアントサーバーに同じタイプが使用されるためです。ServerSocketまあ、それはサーバーソケットなので、そうではありません:-)

accept正直なところ、呼び出される前にリスニングがアクティブかどうかを気にする理由がわかりません。サーバーをビジネス用に開いているとマークするのは、(このクラスでは暗黙的な) "listen" 呼び出しです。その時点で、通信レイヤーが開始され、着信コールがキューに入れられ、コールを待機できるようになりますaccept。プログラムが要求を受け入れるのが少し遅い場合に備えて、要求をキューに入れるのが一般的な方法です。


なぜそうするのかというと、実際にはソースコードによると想定されています。OpenJDK6source/share/classes/java/net/ServerSocket.javaでは、すべてのコンストラクターが 1 つのコンストラクターを呼び出すことになります。

public ServerSocket(int port, int backlog, InetAddress bindAddr)
throws IOException {
    setImpl();
    if (port < 0 || port > 0xFFFF)
        throw new IllegalArgumentException(
                   "Port value out of range: " + port);
    if (backlog < 1)
      backlog = 50;
    try {
        bind(new InetSocketAddress(bindAddr, port), backlog);
    } catch(SecurityException e) {
        close();
        throw e;
    } catch(IOException e) {
        close();
        throw e;
    }
}

そして、(同じファイル)への呼び出しは次のbindとおりです。

public void bind(SocketAddress endpoint, int backlog) throws IOException {
    if (isClosed())
        throw new SocketException("Socket is closed");
    if (!oldImpl && isBound())
        throw new SocketException("Already bound");
    if (endpoint == null)
        endpoint = new InetSocketAddress(0);
    if (!(endpoint instanceof InetSocketAddress))
        throw new IllegalArgumentException("Unsupported address type");
    InetSocketAddress epoint = (InetSocketAddress) endpoint;
    if (epoint.isUnresolved())
        throw new SocketException("Unresolved address");
    if (backlog < 1)
      backlog = 50;
    try {
        SecurityManager security = System.getSecurityManager();
        if (security != null)
            security.checkListen(epoint.getPort());
        getImpl().bind(epoint.getAddress(), epoint.getPort());
        getImpl().listen(backlog);
        bound = true;
    } catch(SecurityException e) {
        bound = false;
        throw e;
    } catch(IOException e) {
        bound = false;
        throw e;
    }
}

関連するビットは次のとおりです。

getImpl().bind(epoint.getAddress(), epoint.getPort());
getImpl().listen(backlog);

つまり、ソケットを作成するときに、bind との両方が下位レベルで実行されます。 listen

netstatですから、「なぜ突然 に現れるのか」という質問はそれほど多くありません。しかし、「なぜnetstat以前に登場しなかったのですか?」

私はおそらくそれをあなたの側の読み違い、または のあまり良くない実装に置くでしょうnetstat。呼び出していないソケットを特にテストしていない限り、前者の可能性が高くなりますaccept

于 2012-10-27T09:30:23.463 に答える
2

の目的について少し間違った考えを持っていると思いますaccept。ServerSocket をキューおよびacceptブロッキングデキュー操作に例えます。ソケットは、ポートにバインドされるとすぐに着信接続をキューに入れ、acceptメソッドは独自のペースでそれらをデキューします。そうです、彼らはacceptより良い名前を付けたかもしれません。

于 2012-10-27T09:49:23.327 に答える