質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.65%

ポートを変更しても アドレスはすでに使用中です となってしまう

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 845

yukkuri

score 554

前提・実現したいこと

現在、Java で ServerSocket のラッパークラスを作っていて、
その接続テストを行う場合にエラーが発生してしまいました。

発生している問題・エラーメッセージ

Exception in thread "main" java.net.BindException: アドレスは既に使用中です
    at java.net.PlainSocketImpl.socketBind(Native Method)
    at java.net.AbstractPlainSocketImpl.bind(AbstractPlainSocketImpl.java:387)

該当のソースコード

package org.jyl.base.io.socket;

import java.io.IOException;

import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;

import java.util.ArrayList;

/**
 * クライアントソケットが接続されるサーバーを実装します。
 * 仕様上、切断されたかの判断は {@code isClosed()} を用いて行うため、
 * 通信を終了する際確実にクローズしてください。
 */
public class JylServer extends ServerSocket implements Runnable
{
    private ArrayList<Socket> sockets = new ArrayList<Socket>( 0 );

    private ServerCheckOption option;

    /**
     * クライアントソケットが接続するサーバーを構築します。
     *
     * @param port ポート番号  0 から 65535 までである必要があります。
     * @param maxque 受信する接続要求の最大数
     * @param timeout タイムアウトまでにかかる時間(ms)
     *
     * @throws IOException
     */
    public JylServer( int port, int maxque, int timeout ) throws IOException
    {
        new ServerSocket( port, maxque );
        setSoTimeout( timeout );

        setServerCheckOption( new DefaultServerCheckOption() );

        bind( new InetSocketAddress( port ), maxque );

        Thread th = new Thread( this );
        th.start();
    }

    /**
     * サーバーに対しての接続要求を受け取ります。
     *
     * @throws IOException
     */
    public synchronized void waitConnect() throws IOException
    {
//        WHILE:
        while( true ){
            Socket sc = accept();
//            System.out.println( "scPort:" + sc.getLocalPort() );
//            System.out.println( sc );
            if( sc != null ){
                sockets.add( sc );
                System.out.println( "added" );
//                break WHILE;
            }
            System.out.println( "noBreak" );
            try{
                Thread.sleep( 1 );
                break;
            }catch( Exception e ){}
        }
    }

    /**
     * 現在サーバーに接続しているメンバーを接続された順番に格納された配列で返します。
     * 新しいクライアントソケットが接続、または切断されたかは、この関数の戻り値の
     * 長さで取得することができます。
     *
     * @return 接続されているメンバーを示すソケット
     */
    public synchronized Socket[] getAccessNembers()
    {
        Socket[] scs = new Socket[ sockets.size() ];
        return sockets.toArray( scs );
    }

    /** 
     * 指定された順番で入ってきたプレイヤーを強制的に切断させます。
     *
     * @param joinNumber 接続された順番  getAccessNembers() での配列内位置
     *
     * @see #getAccessNembers()
     *
     * @throws IOException
     */
    public synchronized void kick( int joinNumber ) throws IOException
    {
        sockets.get( joinNumber ).close();
    }

    /**
     * ソケットが接続されているかなどの管理方法を設定します。
     *
     * @param option 管理方法
     *
     * @see org.jyl.base.io.socket.ServerCheckOption
     */
    public synchronized void setServerCheckOption( ServerCheckOption option )
    {
        this.option = option;
    }

    /**
     * ここでは、接続の確認などを行います。
     */
    @Override public final void run()
    {
        while( true ){
            int[] kicklist;

            //    接続されたかなどをチェック
            try{
                waitConnect();
            }catch( IOException ie ){
                ie.printStackTrace();
            }

            synchronized( this ){
                Socket[] scs = new Socket[ sockets.size() ];
                kicklist = option.check( sockets.toArray( scs ) );

                System.out.println( "length:" + kicklist.length );

                if( kicklist != null ){
                    for( int l = 0; l < kicklist.length; l++ ){
                        System.out.println( "for:" + l );
                        sockets.remove( l );
                        for( int m = 0; m < kicklist.length; m++ ) kicklist[ m ]--;
                    }
                }
            }

            try{
                Thread.sleep( option.wait );
            }catch( Exception e ){}
        }
    }
}
import org.jyl.base.io.socket.*;

public class TestServer
{
    public static void main( String... a ) throws Exception
    {
        JylServer server = new JylServer( 14000, 10, 17713 );
//        int size = server.getAccessNembers().length;

/*        Thread th = new Thread( new Runnable(){
            @Override public void run()
            {
                while( true ){
                    server.waitConnect();
                    try{
                        Thread.sleep( 3 );
                    }catch()
                }
            }
        });
        th.start();*/

//        if( size < server.getAccessNembers().length )
//            System.out.println( "誰かログインしたようですよ!" );


        System.out.println( "while" );
        while( true ){
            int member = server.getAccessNembers().length;

            System.out.println( "member:" + member );

            try{
                Thread.sleep( 3 );
            }catch( Exception e ){}

            if( member > server.getAccessNembers().length ) System.out.println( "誰か切断したようです" );
            if( member < server.getAccessNembers().length ) System.out.println( "誰かログインしたようです" );

            if( member == 0 ){
                try{
                    server.close();
                    System.exit( 0 );
                }catch( Exception e ){}
            }
        }
    }
}
import org.jyl.base.*;
import org.jyl.base.io.*;

import java.io.*;
import java.net.*;

public class Test
{
    public static void main( String[] args ) throws Exception
    {
/*        long ms = System.currentTimeMillis();

        System.out.println( "timer start" );

        JylFileInput fileinput = new JylFileInput( "text.txt", CharCode.EUCJP );
        System.out.println( fileinput.getFileString() );

        System.out.println( "timer stop" );
        System.out.println( "time is " + ( System.currentTimeMillis() - ms ) + " ms" );*/

        Socket sc = new Socket( "localhost", 17713 );

        try{
            Thread.sleep( 15000 );
        }catch( Exception e ){}

        sc.close();
        System.out.println( "closed:" + sc.isClosed() );
    }
}

試したこと

JylServer のコンストラクタで bind を呼び出してみた(コメントアウト箇所)
->エラーが変わった

java.net.SocketException: Socket is not bound yet
    at java.net.ServerSocket.accept(ServerSocket.java:511)
    at org.jyl.base.io.socket.JylServer.waitConnect(JylServer.java:53)
    at org.jyl.base.io.socket.JylServer.run(JylServer.java:118)
    at java.lang.Thread.run(Thread.java:745)

ポート番号の変更
->変更後実行するも変わらず

netstat を使用してみた
->そのポートが使用されている様子はない

補足情報(FW/ツールのバージョンなど)

linux(Raspberry Pi)を用いています
また、一台のPCに二つのコマンドラインを用意し、それぞれサーバー(ServerTest)、クライアント(Test)で実行しています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+2

JylServer extends ServerSocket

ですのに, 

new ServerSocket( port, maxque );

というのは変なはずですけれど...

super(port, maxque);

ではないかと思うのですが, 如何でしょうか.

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/03/09 23:34

    確かに見落としていました...
    基は継承してなかったので、その名残みたいなものでした。
    直したところ、エラーが変わりました。
    新しく出たエラーについて、調べたいと思います!

    キャンセル

  • 2019/03/09 23:43

    なぜわざわざ継承に変えられたのかが不思議に思います.
    ServerSocket の何かを変えているようにも見えません.

    キャンセル

  • 2019/03/09 23:45

    たしかにそうですね...
    エラーは解決しましたが、もう少し構成を考えてみます。
    ありがとうございました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.65%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる