第109回 ソケットチャンネルの入出力
今回のテーマは「ソケットチャンネルの入出力」です。
以前、ストリームの入出力によりソケット通信を行うことについて書きましたが、チャンネルの入出力によりソケット通信を行うこともできます。
次のサンプルコードはサーバを起動し、クライアントの接続要求に応答するプログラムです。
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.charset.Charset; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.UIManager; public class Main extends JFrame implements ActionListener { private static final long serialVersionUID = 1L; public static void main(String[] args) throws Exception { SwingUtilities.invokeLater(new Runnable() { public void run() { try { UIManager.setLookAndFeel(UIManager .getSystemLookAndFeelClassName()); } catch (Exception e) {} new Main(); } }); } private final Service service = new Service(); private final JPanel jPanel = new JPanel(); private final JTextField port = new JTextField("9999"); private final DefaultListModel defaultListModel = new DefaultListModel(); private final JList jList = new JList(defaultListModel); private final JScrollPane jScrollPane = new JScrollPane(jList); private final JButton startupButton = new JButton("起動"); private final JButton shutdownButton = new JButton("停止"); public Main() { startupButton.addActionListener(this); shutdownButton.addActionListener(this); jPanel.add(port); jPanel.add(jScrollPane); jPanel.add(startupButton); jPanel.add(shutdownButton); setContentPane(jPanel); setTitle("SERVER"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setSize(300, 225); setResizable(false); setLocationRelativeTo(null); setVisible(true); } public void actionPerformed(ActionEvent actionEvent) { if (startupButton.equals(actionEvent.getSource())) { service.startup(port.getText()); } if (shutdownButton.equals(actionEvent.getSource())) { service.shutdown(); } } private void messageOut(final Object object) { if (SwingUtilities.isEventDispatchThread()) { defaultListModel.addElement(object); } else { SwingUtilities.invokeLater(new Runnable() { public void run() { defaultListModel.addElement(object); } }); } } private class Service implements Runnable { private final ExecutorService executorService = Executors.newCachedThreadPool(); private ServerSocketChannel serverSocketChannel; public void run() { while (serverSocketChannel.isOpen()) { try { SocketChannel socketChannel = serverSocketChannel.accept(); executorService.execute(new Response(socketChannel)); } catch (Exception e) { e.printStackTrace(); } } } private void startup(String port) { if (serverSocketChannel == null || !serverSocketChannel.isOpen()) { try { serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.socket().bind(new InetSocketAddress (Integer.parseInt(port))); new Thread(this).start(); messageOut("起動しました。"); } catch (Exception e) { try { serverSocketChannel.close(); } catch (Exception e2) {} messageOut("起動できませんでした。"); } } else { messageOut("起動しています。"); } } private void shutdown() { if (serverSocketChannel != null && serverSocketChannel.isOpen()) { try { serverSocketChannel.close(); messageOut("停止しました。"); } catch (Exception e) {} } else { messageOut("起動していません。"); } } } private class Response implements Runnable { private SocketChannel socketChannel; private Response(SocketChannel socketChannel) { this.socketChannel = socketChannel; } public void run() { try { ByteBuffer byteBuffer = ByteBuffer.allocate(1024); Charset charset = Charset.forName("Shift-JIS"); socketChannel.read(byteBuffer); byteBuffer.flip(); messageOut(charset.decode(byteBuffer)); socketChannel.write(charset.encode("response from server")); } catch (Exception e) { e.printStackTrace(); } finally { try { socketChannel.close(); } catch (Exception e) {} } } } }