日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

可扩展的SockBase设计和实现(1)

發布時間:2024/9/5 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 可扩展的SockBase设计和实现(1) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

目錄<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

?? 摘要

?? 基于Sockets網絡編程存在的問題

?? 可擴展的SockBase設計

?? SockBase的編程實現

?? SockBase繼承及其使用方法

?

???

摘要

??? System.Net 命名空間為當前網絡上使用的多種協議提供了簡單的編程接口,如果需要底層控制更多的編程而言,開發人員就需要使用System.Net.Sockets 命名空間了。System.Net.Sockets為需要嚴密控制網絡訪問的開發人員提供了 Windows Sockets (Winsock) 接口的托管實現。 但是Sockets編程既煩雜,又毫無可擴展性,需要開發人員自己控制消息的接受和發送以及處理,這些與業務邏輯有關的工作在編程之時就需要寫入代碼,一旦需求發生變化,又得改寫Sockets的接受消息列表和處理。同時對于命令字符串的構造都需要底層的程序員去控制,不僅容易出錯,而且不易改變。面對復雜多變的業務邏輯,這樣的架構毫無可重用而言,同時給程序員提出了很高的要求,很大程度的工作量放在了做底層的重復性的勞動上。因此,為了提供一種易于擴展的Sockets編程架構,使得開發人員將注意力放在業務邏輯上,我們提出了設計可擴展的SockBase思路,同時實現了這個架構,經驗表明,不僅解決了上述存在的問題,而且取得了非常好的效果。

?

?

基于Sockets網絡編程存在的問題

??? 在一般的基于Sockets網絡編程中,不難出現以下代碼:

?while(sock != null){

?????? temp=ReadMsg(); //調用sock.Recevie(..)函數,byte[]轉成字符串

??? if( temp.Trim() == "Login")

?????? {

??????? // do some thing…

??????? sock.Send( TransMsg("OK"));

??? }

??? else if (temp.Trim() == "show")

?????? {

??????? // do some thing…

??????? sock.Send( TransMsg(ips));

?????? }

?????? else if (temp.Trim() == "Upload"){

??????? // do some thing…

??????? sock.Send(TransMsg("OK"));

??????? // do some thing…

????????????? sock.Send(TransMsg("OK"));

?????? }

?????? else if (temp.Trim() == "list"){

??????? // do some thing…

??????? sock.Send(TransMsg(files));

?????? }

?????? else if (temp.Trim() == "Get"){

??????? // do some thing…

??????? sock.Send(TransMsg("OK"));

????????????? temp = ReadMsg().Trim();

??????? // do some thing…

??? }

}

?

從上面的代碼中,我們可以注意到,對于所有的從客戶端發來的消息,都是統一在這個while()循環中進行處理的

??? 對于消息命令的接收,顯然一般都是和上面的代碼方式類似,統一放到一個地方來執行.但是上述代碼對于消息的派發是使用的Switch case的結構.這樣就帶來一個問題.Switch Case是在程序代碼編寫階段寫的,也就是所謂的硬性編入.即在程序運行過程中不可修改.這樣就使得程序不能在運行過程中對用戶不同的輸入/不同的條件發送不同的消息,或是用戶自定義的,或是程序完成后新加入的擴展的命令..同時,也還是由于Switch case結構,使得對于消息的處理也固定下來了,同樣也不能動態的去修改消息處理函數.這樣使得程序的擴展性很差,而且對于底層的如上述代碼,對于Socket的操作,完全不能直接使用到別的軟件中.(因為消息命令,處理函數不一定是完全一樣的).

?????? 也就是說,在通常的Sockets的網絡開發中,開發人員自己控制消息的接受和發送以及處理,這些與業務邏輯有關的工作在編程之時就需要寫入代碼,一旦需求發生變化,又得改寫Sockets的接受消息列表和處理。同時對于命令字符串的構造都需要底層的程序員去控制,不僅容易出錯,而且不易改變。面對復雜多變的業務邏輯,這樣的架構毫無可重用而言,同時給程序員提出了很高的要求,很大程度的工作量放在了做底層的重復性的勞動上。

?

?

可擴展的SockBase設計

??? 針對上面的問題,我們提出了可擴展的SockBase.可擴展性主要在于能接收任意的消息,而且能對同一個消息在不同的情況下面有不同的處理函數..

我們想到了Windows的消息處理機制.當我們要處理一個系統消息的時候,或是處理我們自定義的消息的時候,首先,我們把自定義消息加入到程序的消息列表中去,同時通過Windows編程中的消息映射的方式,運行增加對處理此消息的函數.使操作系統在收到這個消息后,能夠找到我們對其進行綁定的消息處理函數,進而調用..

回到Sockets中來,我們先做出一個類似Windows消息映射表樣的東西.其中有兩個元素,一個就是收到的消息命令,另一個就是收到此消息后的處理函數,在程序開發者開發過程中,只要在具體的消息接收前先對消息映射表進行初始化,就夠了.SockBase會自動的調用相應的消息處理函數.

?

?

SockBase的編程實現

??? 上面的部分都是理論.現在我們開始完成SockBase的實現代碼.

?

1.定義消息映射表

根據上面所提到的,需要有一個類似消息映射表的東西.這里,我們使用Hashtable來存儲消息和處理函數的數據..由于Hashtable是一種鍵/值型的集合,所以我們把消息命令做為鍵,對應的消息處理函數做為值.由于消息有很多種,而且我們希望對于所有的消息,都能在一個地方去調用相應的處理函數.所以我們使用了.NET的委托做為Hashtable中的值.

定義的委托如下:

Public delegate Command(string args);

?

使用方法如下:

Hashtable Commands = new Hashtable();

Commands.Add( /*消息命令*/, new Command( /*具體的處理函數*/));

調用的時候只要

((Command)Commands[/*消息命令*/])(/*參數*/);

就可以了~

?

2,SockBase的具體實現

,現在,關于消息映射表的準備工作已完成了.現在開始SockBase的實現:P

?????? (1) 構造函數以及變量的聲明,實現

public class SocketBase:IDisposable{

???????? //待處理的命令處理集合

???????? protected Hashtable m_CommandHandlerList;

???????? protected NetworkStream readStream;

???????? protected NetworkStream writeStream;

???????? protected Socket m_sock;

???????? //通過構造函數將Socket的實例傳進來.

???????? public SocketBase(Socket sock){

m_sock = sock;

readStream = new NetworkStream(m_sock);

writeStream = new NetworkStream(m_sock);

}

?

???????? public void Dispose()

???????? {

????????????? // 關閉本地套節子?????

????????????? try

????????????? {

?????????????????? if (m_sock!= null)

?????????????????? {

?????????????????????? if(m_sock.Connected)

?????????????????????? {

??????????????????????????? m_sock.Shutdown(SocketShutdown.Both);

??????????????????????????? m_sock.Close();

?????????????????????? }

?????????????????????? m_sock = null;

?????????????????? }???

????????????? }

????????????? catch(Exception ex)

????????????? {

????????????? }

}

}

?

??? (2) 發送和接收函數

準備工作已完成了.現在就是我們開始對m_sock進行消息接收,以及對消息進行派發了.

首先是消息發送和接收.由于Socket的不確定性,所以很容易出現發送的多個消息在接收的時候混在一起了,所以我們決定每發一個消息就發送固定大小的包,接收時了接收相應大小的包.

SockBase中定義一個包的固定大小:

private static int???? DefaulteBufferSize =5120;

public int BufferSize

{

get{

????????????? if(m_BufferSize!=0)

?????????????????? return m_BufferSize;

????????????? else

?????????????????? return DefaulteBufferSize;

???????? }

???? set{m_BufferSize=value;}

}

再就是發送,接收函數

??????? public string? ReceiveMsg()

????????????? {

??????????????????????????? byte[] Recs=new byte[BufferSize];

??????????????????????????? int count = 0;

??????????????????????????? int num;

??????????????????????????? do {

?????????????????????????????????? num = ReadStream.Read(Recs,count,BufferSize-count);

?????????????????????????????????? if( num == 0){

??????????????????????? throw new Exception("客戶端不正常關閉");

??????????????????? }

??????????????????? count += num;

??????????????????????????? } while( count < BufferSize);

return System.Text.Encoding.GetEncoding(Encoding).GetString(Recs).Replace("\0","");

}

?

??????? public void Send(string msg)

????????????? {

???????????????????? byte[] sender = new Byte[BufferSize];

???????????????????? byte[] temp =? System.Text.Encoding.Unicode.GetBytes(msg) ;

???????????????????? Array.Copy( temp,sender,temp.Length);

???????????????????? WriteStream.Write(sender,0,sender.Length);

???????????????????? WriteStream.Flush();

????????????? }

??? (3) 消息派發函數

好了,下面就是對消息進行派發的函數了:

??????? public void CmdHandler(string ClientMessage)

????????????? {

??????????? //解析出命令

??????????? string[] cmdList=ClientMessage.Split(‘;’);

??????????? string cmdText = "";

???????????????????? for(int i=1;i<cmdList.Length;i++)

???????????????????? {

??????????????????????????? if(i==cmdList.Length-1)

??????????????????????????? {

?????????????????????????????????? cmdText += cmdList[i];

??????????????????????????? }

??????????????????????????? else

??????????????????????????? {

?????????????????????????????????? cmdText += cmdList[i]+":";

??????????????????????????? }

???????????????????? }

??????????? //尋找合適的匹配處理

???????????

if(m_CommandHandlerList.ContainsKey( cmdList[0] ) ) {

??????????????? ( ( Command ) m_ConnamdHandlerList[ cmdList[0] ) ( cmdText);

}

}

我們通過對m_CommandHandlerList中所有的鍵(即注冊的消息命令)進行判斷,如果和接收到的消息的命令是相同的,就直接去調用存在此Hashtable中對應的值(Command委托)..

(4) SockBase運行的起點

最后的部分,整個SockBase運行的起點:

??????? public void ListenSocket()

????????????? {

???????????????????? try

???????????????????? {

??????????????????????????? while(m_sock!=null&&m_sock.Connected)

??????????????????????????? {

??????????????????? //截獲消息,并作出相應的處理

??????????????????? CmdHandler(ReceiveMsg());

??????????????????????????? }

???????????????????? }

????????????? }

現在我們只要直接在m_CommandHandlerList中加入我們要處理的消息的命令和處理函數,再運行ListenSocket(),就可以對接收到的消息進行相應的處理了..

?

?

SockBase繼承及其使用方法

??? 上面實現了SockBase的基本的構架.對于大部分的Sockets網絡編程,都可適用.下面就是使用的方法..

這里,我們從SockBase直接繼承而來一個Client_ListenThread.在此類中,我們通過構造函數,將相應的Socket的實例傳給m_sock.再對消息映射表進行初始化,用一個線程專門運行ListenSockt來對接收到的消息進行派發,調用其處理函數.

??? public class Client_ListenThread : SocketBase????

?????? {

??????? #region 所有字段包含命令字段

??????? #endregion

?

??????? #region 所有方法

??????? public Client_ListenThread(Socket Client_socket) : base(socket)

??????? {

??????????? LoadCommandHandlerList();

????????????? }

?????????????

??????? //裝載所有的命令處理隊列

???????

??????? public void LoadCommandHandlerList()

????????????? {

???????????????????? CommandHandlerItem.Add(“GetFile” , new Command(GetFileHandler);

???????????????????? CommandHandlerItem.Add(“FileOK”, Command(FileOKHandler);

?

??????? }

?

??????? //以下為所有命令處理函數

??????? private void GetFileHandler(string cmdText)

????????????? {

??????????? //檢查文件是否存在

??????????? if((new FileManager()).CheckFileExist(cmdTxt))

???????????????????? {

??????????????????????????? Send(“OK”);

??????????? }

??????????? else

???????????????????? {

??????????????????????????? Send(“Failure”);

??????????? }

??????? }

??????? private void FileOKHandler(string cmdText)

????????????? {

???????????????????? Dispose();

????????????? }

????????????? #endregion

?????? }

?

通過下面這個函數將其運行:

listen_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

listen_socket.Listen(-1);

while(true){

Client_ListenThread clientthread=new Client_ListenThread(listen_socket.Accept());

?????????????????????? if ( clientthread.Sock.Connected )

?????????????????????? {

??????????????????????????? Thread fileThread = new Thread(new ThreadStart(clientthread.ListenSocket));

??????????????????????????? fileThread.IsBackground=true;

??????????????????????????? fileThread.Start();

?????????????????????? }

}

?

總結

??? 通過上述的SockBase,我們可以在不改變SockBase的前提下,對消息映射表進行動態的修改.這樣使得開發人員將注意力放在業務邏輯上,極大的方便了基于Sockets的網絡編程開發.

轉載于:https://www.cnblogs.com/zhouxiancai0128/archive/2006/08/05/468503.html

總結

以上是生活随笔為你收集整理的可扩展的SockBase设计和实现(1)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。