ページ更新: 2009-10-20 (火) (4147日前)
(2004-09-05 新規作成) 説明用に即席で使ったコード。手抜き多し。せっかくなので貼っておく。 目次 [編集]UDP: DatagramPacket, DatagramSocket (2005-04-06, 2009-10-20) #
ソースコード #// -*-mode:java; coding:utf-8;-*- import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.SocketException; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.nio.ByteOrder; public final class UdpSocketTrial { private static final int MAX_PACKETS = 10; private static final int PORT = 9999; private static final byte[] ADDRESS = { (byte) 127, (byte) 0, (byte) 0, (byte) 1, }; public static void main(final String[] args) { try { // サーバーを起動する new Thread(new Server(ADDRESS, PORT, MAX_PACKETS)).start(); // サーバーにパケットをmaxPackets個送信する final InetAddress host = InetAddress.getByAddress(ADDRESS); final DatagramSocket socket = new DatagramSocket(); for (int i = 0; i < MAX_PACKETS; i++) { System.out.println("Client: send data " + i); System.out.flush(); final Data data = new Data(i, "No. " + Integer.toString(i) + ", string data."); final byte[] buf = data.toByteArray(); socket.send(new DatagramPacket(buf, 0, buf.length, host, PORT)); } } catch (final UnknownHostException e) { e.printStackTrace(); } catch (final SocketException e) { e.printStackTrace(); } catch (final IOException e) { e.printStackTrace(); } } /** * Receive UDP Socket * パケットを受信し、デコードして、表示する。 * 所定に個数のパケット {@link maxPackets} を受信すると、サーバを終了する。 */ private static final class Server implements Runnable { private final int maxPackets; private final DatagramSocket socket; private Server(final byte[] address, final int port, final int maxPackets) throws UnknownHostException, SocketException { this.maxPackets = maxPackets; final InetAddress localHost = InetAddress.getByAddress(address); socket = new DatagramSocket(port, localHost); socket.setReuseAddress(true); socket.setReceiveBufferSize(8192); socket.setSendBufferSize(8192); socket.setSoTimeout(100 * 1024); socket.setBroadcast(false); } public void run() { try { doServer(); } catch (final IOException e) { e.printStackTrace(); } } /** * パケットを受信し、デコードして、表示する。 * 所定に個数のパケット {@link maxPackets} を受信すると、サーバを終了する。 * @throws IOException */ private void doServer() throws IOException { final byte[] buf = new byte[8192]; final DatagramPacket received = new DatagramPacket(buf, buf.length); received.setLength(buf.length); System.out.println("Server: start"); System.out.flush(); for (int nPackets = 0; nPackets < maxPackets; nPackets++) { socket.receive(received); final Data data = Data.fromByteArray(received.getData()); System.out.println("Server: nPackets=" + nPackets + " data=" + data); System.out.flush(); } System.out.println("Server: end"); System.out.flush(); } } /** * パケットとして送受信するデータ。 * * データフォーマット * <pre> * | id (int) | string-len (int) | string | * </pre> */ private static final class Data { private final int id; private final String string; private Data(final int id, final String string) { this.id = id; this.string = string; } private static Data fromByteArray(final byte[] array) { final ByteBuffer buf = ByteBuffer.wrap(array); buf.order(ByteOrder.BIG_ENDIAN); final int id = buf.getInt(); final int len = buf.getInt(); final byte[] str = new byte[len]; buf.get(str, 0, len); final String string = new String(str); return new Data(id, string); } private byte[] toByteArray() { final ByteBuffer buf = ByteBuffer.allocate(8192); buf.order(ByteOrder.BIG_ENDIAN); buf.putInt(id); final byte[] str = string.getBytes(); buf.putInt(str.length); buf.put(str); final byte[] result = new byte[buf.position()]; System.arraycopy(buf.array(), 0, result, 0, result.length); return result; } public String toString() { return "id=" + id + " string='" + string + "'"; } } }[編集] 実行結果 #Server: start Client: send data 0 Client: send data 1 Client: send data 2 Client: send data 3 Client: send data 4 Server: nPackets=0 data=id=0 string='No. 0, string data.' Client: send data 5 Server: nPackets=1 data=id=1 string='No. 1, string data.' Client: send data 6 Server: nPackets=2 data=id=2 string='No. 2, string data.' Client: send data 7 Server: nPackets=3 data=id=3 string='No. 3, string data.' Client: send data 8 Server: nPackets=4 data=id=4 string='No. 4, string data.' Client: send data 9 Server: nPackets=5 data=id=5 string='No. 5, string data.' Server: nPackets=6 data=id=6 string='No. 6, string data.' Server: nPackets=7 data=id=7 string='No. 7, string data.' Server: nPackets=8 data=id=8 string='No. 8, string data.' Server: nPackets=9 data=id=9 string='No. 9, string data.' Server: end[編集] TCP: Socket, ServerSocket, 例外 (2004-09-05, 2009-10-20) #
ソースコード #
// -*-mode:java; coding:utf-8;-*- import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.net.Socket; public final class SocketTrial { private static final int CONNECT_TIMEOUT = 2 * 1000; private static final int CONNECTION_TIMEOUT = 1 * 1000; private static final String UNKNOWN_HOST = "unknown.example.jp"; private static final String NON_EXIST_HOST = "192.168.1.99"; private static final String LOCALHOST = "localhost"; private static final int PORT = 40000; private static final int BACKLOG = 1; public static void main(final String[] args) { final StopWatch watch = new StopWatch(); // 逆引きできないホストに接続しようとしたときの例外を調べる try { watch.start(); tryConnect(UNKNOWN_HOST, PORT); } catch (final IOException e) { e.printStackTrace(System.out); } System.out.println("Client: duration (msec)=" + watch.end()); System.out.println(); // 同じサブネットだが、存在しないホストに接続しようとしたときの例外を調べる try { watch.start(); tryConnect(NON_EXIST_HOST, PORT); } catch (final IOException e) { e.printStackTrace(System.out); } System.out.println("Client: duration (msec)=" + watch.end()); System.out.println(); // 同じホストだが、サーバプロセスがないときの例外を調べる try { watch.start(); tryConnect(LOCALHOST, PORT); } catch (final IOException e) { e.printStackTrace(System.out); } System.out.println("Client: duration (msec)=" + watch.end()); System.out.println(); // 同じホストで、サーバプロセスもあるときに、通信タイムアウトの例外を調べる try { final SampleServer sampleServer = new SampleServer(PORT, BACKLOG); new Thread(sampleServer).start(); watch.start(); tryConnect(LOCALHOST, PORT); } catch (final IOException e) { e.printStackTrace(System.out); } System.out.println("Client: duration (msec)=" + watch.end()); System.out.println(); } private static void tryConnect(final String hostname, final int port) throws IOException { final long startTimeMillis = System.currentTimeMillis(); System.out.println("Client: enter tryConnect (hostname=" + hostname + ", port=" + port + ")"); // ソケットを作成する final Socket socket = new Socket(); socket.setSoTimeout(CONNECTION_TIMEOUT); // 接続を試みる final InetSocketAddress endpoint = new InetSocketAddress( InetAddress.getByName(hostname), port); socket.connect(endpoint, CONNECT_TIMEOUT); System.out.println("Client: connect! socket=" + socket.getLocalSocketAddress()); System.out.println("Client: leave tryConnect"); // ソケットで受信したデータを読み込んで表示 final BufferedInputStream in = new BufferedInputStream(socket.getInputStream()); for (;;) { final Data data = Data.readStream(in); System.out.println("Client: receive data:" + data); } } private static final class StopWatch { private long startTimeMillis = 0; public void start() { startTimeMillis = System.currentTimeMillis(); } public long end() { try { return System.currentTimeMillis() - startTimeMillis; } finally { startTimeMillis = 0; } } } private static final class SampleServer implements Runnable { private final int port; private final int backlog; private SampleServer(final int port, final int backlog) { this.port = port; this.backlog = backlog; } public void run() { try { doServer(); } catch (final IOException e) { e.printStackTrace(System.out); } catch (final Throwable e) { e.printStackTrace(System.out); } } /** * サーバを起動する。 * このサーバはクライアントからの接続を待ち、shutdownInput(), shutdownOutput(), close() を * @throws IOException */ private void doServer() throws IOException { final ServerSocket server = new ServerSocket(port, backlog); System.out.println("Server: start, listen port=" + port); // クライアントからの接続を待つ final Socket client = server.accept(); // 接続されたら、クライアントのソケットアドレスを表示する System.out.println("Server: connected from client=" + client.getRemoteSocketAddress()); // データを10個、クライアントに送る。 final BufferedOutputStream out = new BufferedOutputStream(client.getOutputStream()); try { for (int i = 0; i < 10; i++) { final Data data = new Data(i, "test data no." + i); data.writeStream(out); } } finally { out.flush(); } // 2秒まち、shutdownInputする。 sleep(2 * 1000); client.shutdownInput(); System.out.println("Server: shutdownInput"); // 2秒待ち、shutdownOutputする。 sleep(2 * 1000); client.shutdownOutput(); System.out.println("Server: shutdownOutput"); // 2秒待ち、closeする。 sleep(2 * 1000); client.close(); System.out.println("Server: close"); } private static void sleep(final long millisec) { try { Thread.sleep(millisec); } catch (final InterruptedException e) { e.printStackTrace(); } } } /** * パケットとして送受信するデータ。 * * データフォーマット * <pre> * | id (int) | string-len (int) | string | * </pre> * * intはbig-endianで。 */ private static final class Data { private final int id; private final String string; private Data(final int id, final String string) { this.id = id; this.string = string; } private static Data readStream(final InputStream in) throws IOException { final DataInputStream dis = new DataInputStream(in); final int id = dis.readInt(); final int len = dis.readInt(); final byte[] str = new byte[len]; dis.read(str); final String string = new String(str); return new Data(id, string); } private void writeStream(final OutputStream out) throws IOException { final DataOutputStream dos = new DataOutputStream(out); try { dos.writeInt(id); final byte[] str = string.getBytes(); dos.writeInt(str.length); dos.write(str); } finally { dos.flush(); } } public String toString() { return "id=" + id + " string='" + string + "'"; } } }[編集] 実行結果 #以下の環境を使用。OSはWindows XP Professional SP3。 C:> java -version java version "1.6.0_16" Java(TM) SE Runtime Environment (build 1.6.0_16-b01) Java HotSpot(TM) Client VM (build 14.2-b01, mixed mode, sharing) 実行結果: Client: enter tryConnect (hostname=unknown.example.jp, port=40000) java.net.UnknownHostException: unknown.example.jp at java.net.Inet4AddressImpl.lookupAllHostAddr(Native Method) at java.net.InetAddress$1.lookupAllHostAddr(InetAddress.java:849) at java.net.InetAddress.getAddressFromNameService(InetAddress.java:1200) at java.net.InetAddress.getAllByName0(InetAddress.java:1153) at java.net.InetAddress.getAllByName(InetAddress.java:1083) at java.net.InetAddress.getAllByName(InetAddress.java:1019) at java.net.InetAddress.getByName(InetAddress.java:969) at SocketTrial.tryConnect(SocketTrial.java:95) at SocketTrial.main(SocketTrial.java:37) Client: duration (msec)=15 Client: enter tryConnect (hostname=192.168.1.99, port=40000) java.net.SocketTimeoutException: connect timed out at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) at java.net.Socket.connect(Socket.java:525) at SocketTrial.tryConnect(SocketTrial.java:96) at SocketTrial.main(SocketTrial.java:48) Client: duration (msec)=2016 Client: enter tryConnect (hostname=localhost, port=40000) java.net.ConnectException: Connection refused: connect at java.net.PlainSocketImpl.socketConnect(Native Method) at java.net.PlainSocketImpl.doConnect(PlainSocketImpl.java:333) at java.net.PlainSocketImpl.connectToAddress(PlainSocketImpl.java:195) at java.net.PlainSocketImpl.connect(PlainSocketImpl.java:182) at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:366) at java.net.Socket.connect(Socket.java:525) at SocketTrial.tryConnect(SocketTrial.java:96) at SocketTrial.main(SocketTrial.java:59) Client: duration (msec)=1062 Client: enter tryConnect (hostname=localhost, port=40000) Server: start, listen port=40000 Server: connected from client=/127.0.0.1:2197 Client: connect! socket=/127.0.0.1:2197 Client: leave tryConnect Client: receive data:id=0 string='test data no.0' Client: receive data:id=1 string='test data no.1' Client: receive data:id=2 string='test data no.2' Client: receive data:id=3 string='test data no.3' Client: receive data:id=4 string='test data no.4' Client: receive data:id=5 string='test data no.5' Client: receive data:id=6 string='test data no.6' Client: receive data:id=7 string='test data no.7' Client: receive data:id=8 string='test data no.8' Client: receive data:id=9 string='test data no.9' java.net.SocketTimeoutException: Read timed out at java.net.SocketInputStream.socketRead0(Native Method) at java.net.SocketInputStream.read(SocketInputStream.java:129) at java.io.BufferedInputStream.fill(BufferedInputStream.java:218) at java.io.BufferedInputStream.read(BufferedInputStream.java:237) at java.io.DataInputStream.readInt(DataInputStream.java:370) at SocketTrial$Data.readStream(SocketTrial.java:219) at SocketTrial$Data.access$2(SocketTrial.java:216) at SocketTrial.tryConnect(SocketTrial.java:103) at SocketTrial.main(SocketTrial.java:73) Client: duration (msec)=1500 Server: shutdownInput Server: shutdownOutput Server: close |