// Main.java package net.sf.gogui.tools.client; import net.sf.gogui.util.Options; import net.sf.gogui.util.StreamCopy; import net.sf.gogui.util.StringUtil; import net.sf.gogui.version.Version; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; import java.net.ConnectException; import java.net.Socket; import java.util.ArrayList; /** Connects to a remote Go program supporting GTP. */ public final class Main { private static Socket connect(String hostname, int port, int timeout) throws IOException { int totalTime = 0; while (true) { try { return new Socket(hostname, port); } catch (ConnectException connectException) { if (totalTime >= timeout) throw connectException; String text = "Connect failed; retrying in 5 sec..."; System.err.println(text); try { Thread.sleep(5000); } catch (InterruptedException interruptedException) { } totalTime += 5; } } } public Main(String hostname, int port, int timeout) throws Exception { Socket socket = connect(hostname, port, timeout); Thread fromNet = new Thread(new StreamCopy(false, socket.getInputStream(), System.out, false)); SocketOutputCopy toNet = new SocketOutputCopy(socket); fromNet.start(); toNet.start(); fromNet.join(); // Actually I would expect that // System.in.close(); // toNet.join(); // socket.close(); // is good enough to terminate thread toNet, but the read on System.in // blocks even after a close(). Also it seems not to be possible to // use java.nio and have System.in as a interruptible channel. So // System.exit() is called to kill this thread. If you find a cleaner // solution to terminate both threads, please tell me. // The two possible reasons for termination of gogui-client are: // - System.in reaches EOF (no more GTP input) // - socket input stream reaches EOF (server closes connection // after response to a quit command) System.exit(0); } public static void main(String[] args) { try { String options[] = { "config:", "help", "timeout:", "version" }; Options opt = Options.parse(args, options); if (opt.contains("help")) { printUsage(System.out); System.exit(0); } if (opt.contains("version")) { System.out.println("gogui-client " + Version.get()); System.exit(0); } int timeout = opt.getInteger("timeout", 10, 0); ArrayList<String> arguments = opt.getArguments(); if (arguments.size() != 2) { printUsage(System.err); System.exit(1); } String hostname = arguments.get(0); int port = Integer.parseInt(arguments.get(1)); new Main(hostname, port, timeout); } catch (Throwable t) { StringUtil.printException(t); System.exit(1); } } private static void printUsage(PrintStream out) { String text = "Usage: gogui-client [options] hostname port\n" + "\n" + "-config config file\n" + "-help display this help and exit\n" + "-timeout stop trying to connect after n seconds (default 10)\n" + "-version print version and exit\n"; out.print(text); } } class SocketOutputCopy extends Thread { public SocketOutputCopy(Socket socket) { m_socket = socket; } public void run() { try { InputStream src = System.in; OutputStream dest = m_socket.getOutputStream(); byte buffer[] = new byte[1024]; while (true) { int n = src.read(buffer); if (n < 0) { m_socket.shutdownOutput(); break; } dest.write(buffer, 0, n); dest.flush(); } } catch (Throwable e) { StringUtil.printException(e); } } private final Socket m_socket; }