読者です 読者をやめる 読者になる 読者になる

シンプルなTCPサーバのサンプル〜その2〜

Java

TCPは、ポートへのアクティブな接続や、これからクローズする接続があるときは、リッスンしているポートの再利用ができません。サーバの接続のクローズ処理は、プロトコルを最後まで正しく実行するために2分ぐらいかかります。サーバの起動や停止を繰り返す場合に、ローカルポートを再利用するオプションが指定できます。

this.server = new ServerSocket();
this.server.setReuseAddress(true); // ローカルポートの再利用
this.server.bind(new InetSocketAddress(port));


これを踏まえると、TcpServer

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;

public class TcpServer {
    private static final int DEFOULT_PORT = 1000;
    private ServerSocket server;

    public TcpServer() throws IOException {
        this(DEFOULT_PORT);
    }
    public TcpServer(int port) throws IOException {
        this.server = new ServerSocket();
        this.server.setReuseAddress(true);
        this.server.bind(new InetSocketAddress(port));
    }

    public void start() {
        new Thread() {
            @Override public void run() {
                while(true) {
                    try {
                        Socket socket = server.accept(); // block 
                        new Thread(new ConnectionHandler(socket)).start();
                    } catch (SocketException e) {
                        if (e.getMessage().equalsIgnoreCase("Socket closed")) {
                            System.out.println("Socket closed");
                            break;
                        }
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }.start();
    }

    class ConnectionHandler implements Runnable {
        private final Socket socket;
        public ConnectionHandler(final Socket socket) {
            this.socket = socket;
        }
        
        @Override public void run() {
            System.out.println("accepted " + socket.getInetAddress() 
                    + ":" + socket.getPort());
            try {
                socket.setTcpNoDelay(true);
            } catch (SocketException e) {
                // do nothing
            }
            try {
                handleConversation();
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                try {
                    if(socket != null) socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        
        void handleConversation() throws IOException {
            InputStream in = new BufferedInputStream(socket.getInputStream());
            OutputStream out = new BufferedOutputStream(socket.getOutputStream());
            byte[] buffer = new byte[8192];
            int count;
            while((count = in.read(buffer)) >= 0) {
                System.out.println("received " + count
                        + " bytes from " + socket.getInetAddress()
                        + ":" + socket.getPort());
                System.out.println(new String(buffer).trim());
                out.write(buffer, 0, count);
                out.flush();
            }
            socket.shutdownOutput(); // half close
        }
    }
    
    public static void main(String[] args) throws Exception {
        TcpServer tcpServer = new TcpServer();
        tcpServer.start();
    }
}