簡易聊天程序教程(一)自定義異常和消息格式

源代碼下載鏈接:http://download.csdn.net/detail/sky453589103/9514686

如果有什麼問題,歡迎留言。

自定義異常的目的是爲了更好的表示出錯的原因,能夠針對不同的異常執行不同的處理。

異常的自定義是簡單的,只是簡單的繼承了Exception類。下面給出所有聊天程序的異常類的基類的ChatException的定義:

package SimpleChat;

public class ChatException extends Exception{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	public ChatException() {}
	
	public ChatException(String desc) {
		super(desc);
	}

}
聊天程序的所有異常都應該繼承這個類。這個的實現是很簡單的,稍微懂點Java的都能看懂。


消息格式的定義也是簡單的。
爲什麼不用現有的http協議來通信?
    因爲http協議對於這個程序來說,有很多東西是冗餘的,因此爲了提高利用率,這個我自定義了一個參考http協議的消息格式。

舉一個請求消息的例子:

       from:wapoonx

       to:xwp

       command:send

      

       hello

以上就是一個發送消息的請求,from字段表明這個消息是從誰發送過來的。to這個字段表明要發送給誰,也就是接收方是誰。command這個字段表明要執行的命令。以一個空行爲標誌。隔開正文和頭部字段。在這個例子中正文是hello。服務器會根據command字段,從請求報文中選取自己想要的信息。


舉一個響應消息的例子:

code:0

description:success

 

(注意這裏是空的正文)

以上是一個響應消息的格式,code這個字段代表的是一個響應碼,這個響應碼代表着服務器執行響應的客戶請求的結果,0代表成功,其他代表出錯。description是響應消息的描述。不同的描述在客戶端可能有不同的處理。

下面給出請求報文的類的定義:
package SimpleChat;
import java.util.Map;
import java.util.TreeMap;

public class RequestMessage {
	private String from = "";
	private String to = "";
	private String command = "";
	private String rawContext = "";
	
	public RequestMessage() {
		
	}
	
	public RequestMessage(String raw) {
		parse(raw);
	}
	
	public String getFrom() {
		return from;
	}
	
	public String getTo() {
		return to;
	}
	
	public String getCommand() {
		return command;
	}
	
	public String getContext() {
		return rawContext;
	}
	
	public void setFrom(String f) {
		from = f;
	}
	
	public void setTo(String to) {
		this.to = to;
	}
	
	public void setCommand(String cmd) {
		this.command = cmd;
	} 
	
	public void setContext(String con) {
		rawContext = con;
	}
	
	public String Format() {
		String res = "from:" + from+ "\r\n";
		res += "to:" + to + "\r\n";
		res += "command:" + command + "\r\n\r\n";
		res += rawContext;
		
		return res;
	} 
	
	private void parse(String raw) {
		String[] temp = raw.split("\r\n\r\n");
		String[] fields = temp[0].split("\r\n");
		
		if (temp == null || fields == null) {
			return ;
		}
		
		for (int i = 0; i < fields.length; ++i) {
			if (fields[i].indexOf("from:") == 0) {
				from = fields[i].substring("from:".length());
			}
			else if (fields[i].indexOf("to:") == 0) {
				to = fields[i].substring("to:".length());
			}
			else if (fields[i].indexOf("command:") == 0) {
				command = fields[i].substring("command:".length());
			}
		}
		if (temp.length == 2) {
			rawContext = temp[1];			
		}
	}
	
	
	public static Map<String, String> parseContext(String rawContext) throws ChatMessageException {
		if (rawContext == null || rawContext.equals("")) {
			return new TreeMap<String, String>();
		}
		
		Map<String, String> context = new TreeMap<String, String>();
		String[] temp = rawContext.split("\r\n");
		
		for (int i = 0; i < temp.length; ++i) {
			String[] res = temp[i].split(":");
			if (res.length == 2) {
				context.put(res[0], res[1]);				
			} else {
				throw new ChatMessageException("response message is invaild. context's format error"); 
			}
		}
		
		return context;
	}
	
	public Map<String, String> parseContext() throws ChatMessageException {
		return parseContext(this.rawContext);
	}
}

上面這個類的理解難點在於parse函數。其實也很好懂。就是在上面舉得請求消息報文中的字段和正文分析出來。報文的頭部會有很多個字段,然後每個字段會被有一個對應的值,可能爲空。parse函數解析請求報文有下面幾個步驟:
1.使用String的splite函數,將正文和頭部分割開。因爲正文和頭部之間值有連續的兩個CRLF(\r\n)的。整個報文中也只有這個地方會出現連續的兩個CRLF。
2.頭部中的每個字段都是要滿足下面形式:字段之間用一個CRLF隔開,字段中的形式是fieldname:value,因此很容易的就可以再用splite函數處理頭部字段。
3.正文的內容會根據請求報文中的command字段的不同,具有不同的含義。這裏的parseContext函數只是提供了最基本的一種解析方式。這裏的解析基於下面的假設:每行只有一個鍵值對(就是類似頭部字段中的內容那樣)。在這個假設下,解析正文,並且把正文放到Map容器中。返回給調用者。

當然,請求報文還有格式化自己的功能,因此有一個Format函數,來將請求報文的內容格式化,方便以流的形式輸出給服務器端。需要注意的是,客戶端和服務器端的請求報文類是相同的。響應報文類也是完全相同的。響應報文類的作用也和請求報文相似。因此不再贅述。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章