Socketの中継を考える(Java編)


前回のSocketを中継するプログラムをJavaで書き直してみた。C言語と比べるとだいぶすっきりしているがやっている事は同じである。

ソースコード

import java.net.*;
import java.io.*;

class SocketRelay implements Runnable {

	private Socket clientSocket;
	private Socket serverSocket;

	private class Relay implements Runnable {
		private InputStream inputstream;
		private OutputStream outputstream;
		private final int BUFFERSIZE = 1024 * 16;
		private byte buffer[] = new byte[BUFFERSIZE];

		public Relay(InputStream inputstream, OutputStream outputstream) {
			this.inputstream = inputstream;
			this.outputstream = outputstream;
		}

		public void run() {
			try {
				while (true) {
					int ret = this.inputstream.read(buffer);
					if (ret == -1) {
						break;
					}
					synchronized (outputstream) {
						System.out.write(buffer, 0, ret);
					}
					this.outputstream.write(buffer, 0, ret);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public SocketRelay(Socket clients, Socket servers) {
		this.serverSocket = servers;
		this.clientSocket = clients;
	}

	public void run() {
		try {
		    InputStream clientInput = this.clientSocket.getInputStream();
		    OutputStream clientOutput = this.clientSocket.getOutputStream();
			InputStream serverInput = this.serverSocket.getInputStream();
			OutputStream serverOutput = this.serverSocket.getOutputStream();
			
			Relay pushRelay = new Relay(serverInput, clientOutput);
			Relay pullRelay = new Relay(clientInput, serverOutput);
			Thread pushThread = new Thread(pushRelay);
			Thread pullThread = new Thread(pullRelay);

			pushThread.start();
			pullThread.start();
			pullThread.join();
			pushThread.stop();
			
			serverInput.close();
			serverOutput.close();
			clientInput.close();
			clientOutput.close();

			this.serverSocket.close();
			this.clientSocket.close();
		} catch (Exception e) {
		}
	}

	public static void main(String args[]) throws IOException {
		ServerSocket serverSocket=null;
		Socket connectedSocket, clientSocket;
		int inport, outport;
		try {
			inport = new Integer(args[1]).intValue();
			outport = new Integer(args[2]).intValue();
			serverSocket = new ServerSocket(inport);
			while (true) {
				connectedSocket = serverSocket.accept();
				clientSocket = new Socket(args[0], outport);
				SocketRelay sr = new SocketRelay(clientSocket, connectedSocket);
				new Thread(sr).start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

Javaは言語自体にネットワーク等のライブラリが充実しておりプラットフォームの違いを意識する事が無いので便利。C言語だと大抵のプラットフォームで動作するがANCI規格ではないコードは互換性がないので修正が必要になる。

使い方

$javac SocketRelay.java
$java SocketRelay localhost 8080 80
ブラウザ等でhttp://localhost:8080/へアクセス
ctrl+cで終了

出力例

GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ja,en-US;q=0.8,en;q=0.6
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.3

HTTP/1.1 200 OK
Date: Tue, 16 Apr 2013 14:59:19 GMT
Server: Apache/2.2.22 (Unix) DAV/2 PHP/5.3.15 with Suhosin-Patch mod_ssl/2.2.22 OpenSSL/0.9.8r
Content-Location: index.html.en
Vary: negotiate
TCN: choice
Last-Modified: Mon, 11 Feb 2013 08:55:12 GMT
ETag: "35d48-2c-4d56f111c5c00"
Accept-Ranges: bytes
Content-Length: 44
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html
Content-Language: en

<html><body><h1>It works!</h1></body></html>GET /favicon.ico HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Accept: */*
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_3) AppleWebKit/537.31 (KHTML, like Gecko) Chrome/26.0.1410.65 Safari/537.31
Accept-Encoding: gzip,deflate,sdch
Accept-Language: ja,en-US;q=0.8,en;q=0.6
Accept-Charset: Shift_JIS,utf-8;q=0.7,*;q=0.3

HTTP/1.1 404 Not Found
Date: Tue, 16 Apr 2013 14:59:20 GMT
Server: Apache/2.2.22 (Unix) DAV/2 PHP/5.3.15 with Suhosin-Patch mod_ssl/2.2.22 OpenSSL/0.9.8r
Content-Length: 209
Keep-Alive: timeout=5, max=99
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /favicon.ico was not found on this server.</p>
</body></html>
^C