顯示具有 Port 標籤的文章。 顯示所有文章
顯示具有 Port 標籤的文章。 顯示所有文章

2008年6月8日

TCP/IP Client/Server的互動方式



透過「如何用REBOL寫TCP/IP的Client程式」與「如何用REBOL寫TCP/IP的Server程式」,你應該已經可以使用REBOL 3.0寫出TCP/IP的Client/Server系統。這裡是一個綜合的示意圖,展示出DNS、Client Port、Server Listen Port、Server Service Port之間的互動關係。

2008年6月7日

如何用REBOL寫TCP/IP的Server程式


在「如何用REBOL寫TCP/IP的Client程式」一文中,我說明了Client程式的寫法,現在這篇文章說明Server程式的寫法,程式碼請參考這篇DocBase文章的Pong Server。重點整理如下:

  1. Server會先Open自己電腦上的一個Listen Port,並開始聆聽(Listen)連線請求。對於REBOL來說,只要呼叫Open函數來開啟伺服器的Port,就會同時進行Listen(你不需要呼叫Listen,也沒有這樣的函數可用)。
  2. 當Client呼叫Open,並指定連到Server的IP和Port時,Server就會收到Accept的事件。處理Accept事件的方式是呼叫First,會得到一個Service Port。Server的Awake函數必須傳出false(表示任務尚未完成),否則會結束Listen,只能服務一人。
  3. Listen Port繼續接受來自其他Client的新連線請求,而Service Port開始和連線上的Client溝通。也就是說,Listen Port和Service Port兩個是不同的Port,且Listen Port只有一個,且可能產生出多個Service Port。
  4. Service Port會進行Read、Write、Close動作(函數),會分別收到Read、Wrote、Close事件。這部分和「如何用REBOL寫TCP/IP的Client程式」一文類似,不再贅述。
  5. 通常Service Port會先呼叫Read(而非Write),以讀取來自客戶的請求內容。

2008年6月5日

OOP in REBOL ?

根據REBOL語言設計者Carl在部落格文章中的說法,他以前曾經相當著迷於OOP (Object-Oriented Programming),但是現在已經不再是如此了。雖然Carl不是特別喜歡OOP,但是在REBOL 3.0的設計中,我們依然可以找到少數OOP的影子。最明顯的例子是Scheme與Port。

從OOP的角度來看,Scheme就像是Class,Port就像是Instance;Scheme只有一份,被所有的Port共用。另外,Scheme也像是Super-class;而Port像是Sub-class,Port所提供的action方法可以覆蓋(shadow)掉Scheme的action;而Port如果沒有實做(implement)自己的action,就會使用Scheme的版本。

如果你想在REBOL中寫OOP的程式,那麼你可以參考Scheme與Port的源碼。關於OOP,你可以參考我的這篇文章。

如何用REBOL寫TCP/IP的Client程式


我還記得約14年前讀大學時寫過的第一個網路程式WinBrick(Windows 3.1的網路對打俄羅斯方塊Tetris),當時使用WinSock API。後來讀研究所時用Java Networking API寫VOD(Video-On-Demand)系統,Java的API比C的WinSock稍微簡單一些,但程式還是不好寫。REBOL的TCP/IP程式設計方式,比起上述兩者,都更簡單。你可以閱讀Carl的這篇部落格文章。
經過自己手動實驗之後,我簡單地整理一下重點:
  1. DECODE-URL用來將URL(例如:http://www.rebol.com/index.htm)拆解成區塊(例如[scheme: 'http host: "www.rebol.com" port-id: 80 path: "/index.htm"]),但是DECODE-URL有時候會拆解錯誤,如果與到拆解錯誤的狀況,就必須自己處理。如這個例子所示。
  2. 上述的區塊可以當作OPEN的參數,就可以連接到伺服器。
  3. 如果host是host-name,則程式會先連到DNS,查詢(lookup)伺服器的ip,所以會收到「lookup」事件,這個時候,必須再次呼叫OPEN。
  4. 如果host本來就是host-ip,則不會有上述的步驟(不會收到lookup事件)。
  5. 當程式收到「connect」事件時,表示程式對伺服器的連線請求,已經被伺服器接受(accept),可以開始進行資料通訊,這個時候,通常是由Client先傳送資料(服務請求)給伺服器,而伺服器先聆聽(listen)。因此,在收到connect事件時,Client通常會呼叫WRITE。
  6. 當資料寫入完畢,Client會收到「wrote」事件。這個時候,通常會呼叫READ,進行資料的讀取。當然,你也可以會直接呼叫CLOSE,主動關閉網路連線,這由你的通訊協定(protocol)決定。
  7. 呼叫READ,就會從緩衝區(buffer)讀取資料,一旦讀取完目前緩衝區的資料,就會收到read事件(這個read是「過去分詞」,表示「已經讀取了」)。
  8. 通常你需要解析剛剛讀到的資料,以瞭解資料是否已經讀完。如果尚未讀完,你必須繼續呼叫READ來繼續讀取資料。如果已經讀完,你可能會呼叫WRITE傳資料給伺服器,或者呼叫CLOSE來關閉連線。
  9. 當連線的兩端中,任何一端先呼叫CLOSE來關閉連線時,Client都會收到「close」事件。當client收到這個事件的時候,要做一些收尾的動作。
  10. awake的傳出值如果為false,表示port尚未處理完畢;如果為true,表示port處理完畢,會立刻結束這個port。通常我們會在遇到通訊協定格式錯誤、事件無法識別、或收到close事件之後,傳出true,其他狀況則傳出false。
  11. 為了避免任何動作做太久,我們通常會在外部呼叫WAIT,等候一段Timeout的時間。