001/* 002 * $URL:$ 003 * $Author: tgutwin $ 004 * $Revision: $ 005 * $Date: 2014-01-26 20:27:05 -0800 (Sun, 26 Jan 2014) $ 006 */ 007/* 008 * 009 * Written by Tom Gutwin - WebARTS Design. 010 * Copyright (C) 2014 WebARTS Design, North Vancouver Canada 011 * http://www.webarts.bc.ca 012 * 013 * This program is free software; you can redistribute it and/or modify 014 * it under the terms of the GNU General Public License as published by 015 * the Free Software Foundation; either version 2 of the License, or 016 * (at your option) any later version. 017 * 018 * This program is distributed in the hope that it will be useful, 019 * but WITHOUT ANY WARRANTY; without_ even the implied warranty of 020 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 021 * GNU General Public License for more details. 022 * 023 * You should have received a copy of the GNU General Public License 024 * along with this program; if not, write to the Free Software 025 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 026 */ 027package ca.bc.webarts.android; 028 029import java.io.DataInputStream; 030import java.io.PrintStream; 031import java.io.BufferedReader; 032import java.io.InputStreamReader; 033import java.io.IOException; 034import java.net.Socket; 035import java.net.UnknownHostException; 036 037/** A simple but functional TCP Socket client that sends messages to a designated IP port. **/ 038public class TCPSocketClient implements Runnable 039{ 040 041 private static String DEFAULT_SERVER_HOST = "localhost"; 042 043 private int debug_ = 0; 044 045 /** The client socket. **/ 046 private Socket clientSocket_ = null; 047 /** The output stream. **/ 048 private PrintStream os_ = null; 049 /** The input stream. **/ 050 private DataInputStream is_ = null; 051 052 private String host_ = "localhost"; 053 private int port_ = 8765; 054 055 private Thread listener_ = null; 056 private boolean listening_ = false; 057 private boolean waitingForResponse_ = false; 058 private boolean errorResponse_ = false; 059 // private boolean listeningLock_ = false; 060 //private boolean responseLock_ = false; 061 062 063 /** default Constructor uses DEFAULTS from this class for IP and port. **/ 064 public TCPSocketClient() 065 { 066 } 067 068 069 /** Instatiates the client with custom IP and port.**/ 070 public TCPSocketClient(String hostName, int portNum) 071 { 072 host_=hostName; 073 port_=portNum; 074 } 075 076 077 /** Initializes the socket, and associated in and out streams. **/ 078 public synchronized Socket initSocket() throws UnknownHostException, IOException 079 { 080 if (debug_>1) System.out.println("initSocket() and isInit: "+isInit()); 081 if(!isInit()) 082 { 083 clientSocket_ = new Socket(host_, port_); 084 os_ = new PrintStream(clientSocket_.getOutputStream()); 085 is_ = new DataInputStream(clientSocket_.getInputStream()); 086 } 087 return clientSocket_; 088 } 089 090 091 /** Starts the listener Thread, AFTER checking that everything is initialized and ready to go (initsocket).**/ 092 public boolean listenToSocket() throws IOException 093 { 094 if (debug_>1) System.out.println("listenToSocket() and isInit: "+isInit()); 095 if(isInit()) 096 { 097 listener_ = new Thread(this, "SocketListener"); 098 listener_.start(); 099 int waiter = 0;int sleepTime=200; 100 while(!isListening() && waiter<1000) {ca.bc.webarts.android.Util.sleep(sleepTime);waiter+=sleepTime;} 101 } 102 return isListening(); 103 } 104 105 106 public void signalClose() 107 { 108 if (debug_>1) System.out.println("signalClose()"); 109 if (listener_!=null && listener_.isAlive()) 110 try{listener_.interrupt();}catch(SecurityException sEx){} 111 } 112 113 114 public synchronized void closeSocket() throws IOException 115 { 116 if (debug_>1) System.out.println("closeSocket() and isInit: "+isInit()); 117 signalClose(); 118 119 int waiter = 0;int sleepTime=75;int maxBlockTime_ms = 2000; 120 while(isWaitngForResponse() && waiter<maxBlockTime_ms) {ca.bc.webarts.android.Util.sleep(sleepTime);waiter+=sleepTime;} 121 122 if (debug_>1) System.out.println(" CloseWaitComplete="+waiter+"/"+maxBlockTime_ms); 123 124 if( os_!=null ) os_.close(); 125 if( is_!=null ) is_.close(); 126 if( clientSocket_!=null ) clientSocket_.close(); 127 //listening_=false; 128 } 129 130 131 /** Only a new thread should call this. **/ 132 private synchronized boolean setListening(boolean l) 133 { 134 //getListeningLock(); 135 listening_=l; 136 //releaseListeningLock(); 137 return l; 138 } 139 140 141 private boolean setListening() 142 { 143 return setListening(true); 144 } 145 146 147 /** Confirms if a listener Thread has started and is running/listening for a server response. Listeners start by calling the listenToSocket() method.**/ 148 private synchronized boolean isListening() 149 { 150 boolean l = false; 151 // getListeningLock(); 152 l=listening_; 153 //releaseListeningLock(); 154 return l; 155 } 156 157 158 private synchronized boolean setWaitngForResponse(boolean l) 159 { 160 //getWaitngingLock(); 161 waitingForResponse_=l; 162 //releaseWaitngingLock(); 163 return l; 164 } 165 166 167 private boolean setWaitngForResponse() 168 { 169 return setWaitngForResponse(true); 170 } 171 172 173 private synchronized boolean isWaitngForResponse() 174 { 175 boolean l = false; 176 //getWaitngingLock(); 177 l=waitingForResponse_; 178 //releaseWaitngingLock(); 179 return l; 180 } 181 182/* 183 synchronized private boolean getWaitngingLock() 184 { 185 if(!responseLock_) 186 responseLock_=true; 187 return responseLock_; 188 } 189 190 191 synchronized private boolean getListeningLock() 192 { 193 if(!listeningLock_) 194 listeningLock_=true; 195 return listeningLock_; 196 } 197*/ 198 199 200 public boolean isInit() 201 { 202 return (clientSocket_!=null && !clientSocket_.isClosed() && os_!=null && is_!=null ); 203 } 204 205 206 public void send(String message) throws IOException 207 { sendAndWait(message,0);} 208 209 210 public void sendAndWait(String message, int maxBlockTime_ms) throws IOException 211 { 212 if (debug_>1) System.out.println("sendAndWait()"); 213 if(isInit()) 214 { 215 //setWaitngForResponse(); 216 if(listenToSocket()) 217 { 218 if (debug_>1) System.out.println(" ...sendingMessage: "+message); 219 os_.println(message+"\n"); 220 int waiter = 0;int sleepTime=75; 221 while(isWaitngForResponse() && waiter<maxBlockTime_ms) {ca.bc.webarts.android.Util.sleep(sleepTime);waiter+=sleepTime;} 222 if (debug_>0) System.out.println("SendWaitComplete="+waiter+"/"+maxBlockTime_ms); 223 } 224 else 225 { 226 // try again 227 if(listenToSocket()) 228 { 229 os_.println(message+"\n"); 230 int waiter = 0;int sleepTime=100; 231 while(isWaitngForResponse() && waiter<maxBlockTime_ms) {ca.bc.webarts.android.Util.sleep(sleepTime);waiter+=sleepTime;} 232 if (debug_>0) System.out.println("SendWaitComplete="+waiter+"/"+maxBlockTime_ms); 233 } 234 } 235 236 } 237 else System.out.println("Socket NOT init"); 238 } 239 240 241 public static void main(String[] args) 242 { 243 TCPSocketClient instance= null; 244 if (args.length < 2) 245 { 246 instance = new TCPSocketClient(); 247 System.out.println("Usage: java TCPSocketClient <host> <portNumber>\n" + 248 "Now using host=" + instance.host_ + ", portNumber=" + instance.port_); 249 } 250 else 251 { 252 //host = args[0]; 253 //portNumber = Integer.valueOf(args[1]).intValue(); 254 System.out.println("Usage: java TCPSocketClient <host> <portNumber>\n" + 255 "Now using host=" + args[0] + ", portNumber=" + Integer.valueOf(args[1]).intValue()); 256 instance = new TCPSocketClient( args[0], Integer.valueOf(args[1]).intValue()); 257 } 258 259 try 260 { 261 if (instance.debug_>0) System.out.print((instance.isListening()?"?":"-")); 262 BufferedReader inputLine = null; 263 inputLine = new BufferedReader(new InputStreamReader(System.in)); 264 String req = ""; 265 266 while (!req.trim().equalsIgnoreCase("Bye") && 267 !req.trim().equalsIgnoreCase("Quit") && 268 !req.trim().equalsIgnoreCase("Exit")) 269 { 270 try 271 { 272 if ( //instance.isListening() && 273 !req.trim().equals("")) 274 { 275 //req = inputLine.readLine().trim(); 276 if (instance.debug_>1) System.out.println("Request: "+req); 277 instance.initSocket(); 278 if (instance.isInit()) 279 { 280 instance.sendAndWait(req,1000); 281 instance.closeSocket(); 282 } 283 else 284 System.err.println("Socket NOT init"); 285 } 286 } 287 catch (IOException e) 288 { 289 System.err.println("IOException: " + e); 290 e.printStackTrace(); 291 } 292 //Go Back for another message 293 System.out.print("?"); 294 req = inputLine.readLine().trim(); 295 } 296 297 } 298 catch (UnknownHostException e) 299 { 300 System.err.println("Don't know about host " + instance.host_); 301 } 302 catch (IOException ioEx) 303 { 304 ioEx.printStackTrace(); 305 System.err.println("Couldn't get I/O for the connection to the host " + instance.host_); 306 } 307 } 308 309 310 public void run() 311 { 312 setListening(); 313 if (debug_>0) System.out.print("\nListening: "+ isListening()); 314 /* 315 * Keep on reading from the socket till we receive "Bye" from the 316 * server. Once we received that then we want to break. 317 */ 318 String responseLine = null; 319 try 320 { 321 errorResponse_ = true; 322 setWaitngForResponse(); 323 if (debug_>0) System.out.println(" is_ is null: "+(is_ == null)); 324 while (is_ != null && (responseLine = is_.readLine()) != null) 325 { 326 System.out.println("ServerResponse: "+ responseLine); 327 if (responseLine.startsWith("END") ) // lirc response 328 { 329 setWaitngForResponse(false); 330 setListening(false); 331 break; 332 } 333 334 if (responseLine.startsWith("ERROR") ) // lirc response 335 { 336 setWaitngForResponse(false); 337 errorResponse_ = true; 338 } 339 if (responseLine.startsWith("SUCCESS") ) // lirc response 340 { 341 setWaitngForResponse(false); 342 } 343 344 } 345 if (debug_>0) System.out.println("NOT Listening & responseLine==null is "+(responseLine==null)); 346 } 347 catch (java.nio.channels.ClosedByInterruptException intEx) 348 { 349 if (debug_>1) System.err.println("listenerThread Interupted"); 350 } 351 catch (IOException e) 352 { 353 System.err.println("runIOException: " + e); 354 e.printStackTrace(); 355 } 356 finally 357 { 358 setWaitngForResponse(false); 359 setListening(false); 360 } 361 if (debug_>1) System.out.println("Exiting Listener Thread.Run"); 362 } 363}