- PR -

タイマーを使ったメッセージの再送

投稿者投稿内容
さくらば
大ベテラン
会議室デビュー日: 2002/11/12
投稿数: 145
投稿日時: 2003-10-05 05:31
こんにちは、さくらばです。

解決なさったようなので、蛇足ですが。

引用:

fuzukiさんの書き込み (2003-10-04 22:51) より:
スレッドも考えたのですが、まだ基本的なことしか理解しておらず、考えていると頭がこんがらかってくるので今回はこれでよしとしました。



私も安易にスレッドを使うことはやめたほうがいいと思います。
マルチスレッドに関してちゃんと知識があればいいのですが、そうでない場合
変数の同期やデッドロックを引き起こすのは目に見えてます。

それに Socket をマルチスレッドで行うというのは、すでに過去の方法です。

それではどうすればいいかというと、今回のような場合は setSoTimeout よりも、
できれば NIO の非同期 I/O を使ったほうがいいと思います。

非同期 I/O であれば read はブロッキングしません。

Selelctor クラスを使用して、I/O のイベントを待つようにします。待つときに
タイムアウトを設定できるので、タイムアウトで抜けたときに再送するようにす
ればいいと思います。

参考にクライアントのコード例を載せておきます。

コード:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

public class TestClient {
    private static String ADDRESS = "localhost";
    private static int PORT = 9000;
    private static long TIMEOUT = 5000L; // タイムアウト 5 秒

    private SocketChannel channel;
    private Selector selector;

    private ByteBuffer buffer = ByteBuffer.allocate(2048);
    
    private BufferedReader reader;

    public TestClient() throws IOException {
        // ソケットを生成
        channel = SocketChannel.open();
        
        // セレクタを生成
        selector = Selector.open();
            
        // 標準入力
        reader = new BufferedReader(new InputStreamReader(System.in));
    }

    public void start() {
        try {
            // コネクト
            InetSocketAddress address = new InetSocketAddress(InetAddress.getLocalHost(), PORT);
            channel.connect(address);

            // コネクションがはれたら、ノンブロッキングモードに変更
            channel.configureBlocking(false);

            // セレクタにリードを登録
            channel.register(selector, SelectionKey.OP_READ);
            System.out.println("CONNECT");
                
            while (true) {
                // メッセージの送信
                sendMessage();
                
                // 入力をタイムアウトまで待つ
                // タイムアウトした場合、戻り値が 0 なので、その場合は再送
                if (selector.select(TIMEOUT) > 0) {
                    
                    // 入力があった場合
                    Iterator it = selector.selectedKeys().iterator();
                    while (it.hasNext()) {
                        // 一覧から 1 つだけ抜き出し、削除したあと、入力処理する
                        SelectionKey key = (SelectionKey)it.next();
                        it.remove();
                        
                        // 入力であるかチェックしてから入力を行う
                        if (key.isReadable()) {
                            readMessage();
                        }
                    }
                }
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                channel.close();
                selector.close();

                reader.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    private void sendMessage() throws IOException {
        System.out.print("input> ");
        String tmp = reader.readLine();

        buffer.clear();
        CharBuffer chBuf = buffer.asCharBuffer();
        chBuf.put(tmp);

        buffer.limit(chBuf.position() * 2);

        channel.write(buffer);
    }

    private void readMessage() throws IOException {
        buffer.clear();
        channel.read(buffer);

        buffer.flip();
        System.out.println("READ: " + buffer.asCharBuffer().toString());
    }

    public static void main(String[] args) {
        try {
            TestClient client = new TestClient();
            client.start();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}

fuzuki
常連さん
会議室デビュー日: 2003/08/23
投稿数: 48
投稿日時: 2003-10-07 01:12
さくらばさん

ソースまでこんなに載せてくださってありがとうござます。
setSoTimeoutでとりあえずは解決しましたが、さくらばさんの方法のほうが優れているようですので、検討しています。ソースを読んでいてまだ分からない箇所などがあるので勉強しているところです。
もし自力で分からない箇所があったらお聞きするかもしれませんが、よろしくお願いします。

スキルアップ/キャリアアップ(JOB@IT)