第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) {}
}
}
}
}

