//haBull.java -- by tsaiwn@csie.nctu.edu.tw //javac haBull.java CowBull.java //java haBull //then you can use "telnet hostName 3388" to connect this program import java.io.*; import java.net.*; import java.util.*; // Date is in this package import java.lang.*; // NOT necessary class haBull { // should be same as the File name, 建議該用大寫開頭 haBull ServerSocket ssk; // 用來等待連線 Socket ccc; // 有client連線進來可生出 Socket 小洞 static final int DEFAULT_PORT = 3388; // final 表示後面不可改它 static final int TIME_OUT = 300; // 300 seconds int portNumber; // Listening TCP port PrintStream cout = System.out; // 取個與 C++ 同名的物件變數 PrintStream cerr = System.err; static int getPortNumber(String s) { int kk=0; try { kk = Integer.parseInt(s); }catch(Exception e) { kk = 0; } return kk; } // getPortNumber if any, for example: java haBull 5566 public static void main(String[ ] xxx) throws Exception { // ^^^ 宣稱若出問題會報告馬政府 ! int pp=0; if(xxx.length > 0) pp =getPortNumber(xxx[0]); if(pp==0) pp = DEFAULT_PORT; // 有打就用 user 打的, 否則用原來的 new haBull(pp); // 要求升出 haBull 物件並立刻執行 haBull( ) 建構子 }// main /// haBull(int yy) { // 這就是 class haBull 的 constructor 建構子 portNumber = yy; cout.println("Server started ... at port "+ portNumber); try { ssk = new ServerSocket( portNumber ); ssk.setSoTimeout(TIME_OUT * 1000); // time out = 300 sec ? while(38 == 38) { // true try { ccc = ssk.accept( ); // 等待連線後取得連線暫稱 ccc }catch(Exception e) { cerr.println(" .. " + TIME_OUT/60.0 // to minutes + " minutes past "+new Date( )); continue; // to Listen again } Brother b = new Brother(ccc); // 請一個小弟, 並把連線交給小弟 b.start( ); // 叫小弟開始處理該連線 } } catch(Exception e) { cerr.println("Cannot startup ChatServer at port "+ portNumber+"!"); cerr.println("Maybe port "+portNumber+" has been used?\nByebye."); } cerr.println("...Server stop."); } // haBull( ) } // class haBull //////// class Brother extends Thread { // 表示這 class Brother 是一個 Thread 執行緒 Socket mySock; // 用來記住"老大"傳來的資料, 方便這class內其他 function 用 Date now; String name="???"; // remember user name private String remoteAddr; // 連著我的對方 IP address private BufferedReader in; private PrintStream out; private PrintStream cout = System.out; // cout 只是簡寫而已 Brother(Socket x) { mySock = x; now = new Date( ); try { remoteAddr = mySock.getInetAddress().getHostAddress(); // 然後取得InputStream並包成 BufferedReader 方便 readLine() in = new BufferedReader( new InputStreamReader(mySock.getInputStream()) ); // 再取得 OutputStream 並包成 PrintWriter out = new PrintStream( (mySock.getOutputStream()), true ); cout.println("Friend from " + remoteAddr + " at " + now); } catch(Exception e) { // say something } } public void run( ) { // 規定 Thread 內一定要這樣寫才有用 name = "???"; // 接著, 可以 與 連線者對話 try { out.print("Welcome to the BullCow Land.\n\r"); out.flush( ); while(name.length( ) < 7) { // 不可能短於 7 :-) out.print("Give me your 學號與姓名: "); name = in.readLine( ); if(name.startsWith(" ") || name.length( )< 6 ) { name = "???"; out.print(" ! 不可亂打, "); } } out.println("歡迎 " + name + " 開始玩, 公牛是位置對數字也對!\n\r"); cout.println(" " + name + " from " + remoteAddr + " play on " + new Date( ) +".."); log(1, name + " @" + remoteAddr+" " + new Date( ) ); // 1=start CowBull cb = new CowBull(in, out, this); // this 指到我 ! /// cb.play( ); // auto play in constructor out.println("\n\rBye bye " + name + " at " + new Date( )); log(0, name + " leaving " + new Date( ) ); // 0= leaving try { mySock.close( ); }catch(Exception e) { } }catch(Exception e) { } cout.println(" " + name + " leaving at " + new Date( ) +"..."+ remoteAddr); } // run( ) void log(int k, String s) { FileWriter f; PrintWriter logFile; try { f = new FileWriter(logFileName, true); // true to Append logFile = new PrintWriter(f); }catch(Exception e) { return; } // No log if fail if(k == 0) logFile.append(" .."); logFile.append(s +"\r\n"); logFile.close( ); return; } // log String logFileName = "bullLog.txt"; } // class Brother