久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

對(duì)于分布式即時(shí)通訊程序的思考和實(shí)踐

 修行的嘟嘟 2011-05-09

計(jì)算機(jī)網(wǎng)絡(luò)最根本的目的是實(shí)現(xiàn)網(wǎng)絡(luò)中計(jì)算機(jī)之間的分布式進(jìn)程間通信

即時(shí)通訊所使用的傳輸協(xié)議是TCP和UDP

windows系統(tǒng)和linux系統(tǒng)都支持socket 按照這樣的規(guī)范 我們可以實(shí)現(xiàn)垮平臺(tái)的信息交換

所以我們都經(jīng)過(guò)socket傳輸數(shù)據(jù),TCP和UDP位于網(wǎng)絡(luò)中的傳輸層,,位于IP層之上 是用戶(hù)功能的最底層

TCP:面向連接的,、可靠的、基于字節(jié)流的運(yùn)輸層通信協(xié)議 數(shù)據(jù)一定是可靠地到達(dá),,先發(fā)送的先到,,丟包重傳 可以提供流控制機(jī)制,建立一個(gè)TCP連接需要經(jīng)過(guò)3次握手,,關(guān)閉一個(gè)TCP連接需要經(jīng)過(guò)4此握手 ,,在一個(gè)TCP連接中只支持兩方的通信,不支持廣播,,采用字節(jié)流方式,,如果字節(jié)流太長(zhǎng),將其分段,。

UDP:無(wú)連接的傳輸層協(xié)議,,提供面向事務(wù)的簡(jiǎn)單不可靠信息傳送服務(wù)。選擇UDP必須要謹(jǐn)慎,。在網(wǎng)絡(luò)質(zhì)量令人不十分滿(mǎn)意的環(huán)境下,,UDP協(xié)議數(shù)據(jù)包丟失會(huì)比較嚴(yán)重,但是UDP不是面向連接的 它有資源消耗小,處理速度快的特點(diǎn) 對(duì)于那些要求不是特別嚴(yán)格的數(shù)據(jù) 如音頻流,,視頻流和普通數(shù)據(jù) 即時(shí)偶爾丟幾個(gè)包也不會(huì)對(duì)結(jié)果產(chǎn)生多大的影響,。并且它能減輕對(duì)網(wǎng)絡(luò)的壓力

對(duì)于即時(shí)通訊軟件,例如像騰訊QQ 百度Hai 阿里旺旺 以及大型的聊天室,,我的理解應(yīng)該是這樣的

有時(shí)候它們需要可靠的連接,,有時(shí)候可能需要UDP就夠了 所以像QQ那樣的軟件是同時(shí)使用TCP和UDP這兩種協(xié)議的

可以設(shè)想服務(wù)端負(fù)責(zé)處理客戶(hù)端的數(shù)據(jù) 具體包括如響應(yīng)客戶(hù)端的好友列表請(qǐng)求,通知其它用戶(hù)好友的狀態(tài)更改上線(xiàn)下線(xiàn),,轉(zhuǎn)發(fā)文字消息

而客戶(hù)端直接可以進(jìn)行視頻和語(yǔ)言聊天 視頻語(yǔ)音數(shù)據(jù)量大,,服務(wù)器也無(wú)法承擔(dān)這樣的壓力,所以服務(wù)端不會(huì)對(duì)語(yǔ)音視頻進(jìn)行轉(zhuǎn)發(fā) 所以應(yīng)當(dāng)在兩個(gè)客戶(hù)端直接建立連接實(shí)現(xiàn)兩個(gè)客戶(hù)端進(jìn)程間的通信 此部分服務(wù)器不管,。

所以即時(shí)通訊軟件應(yīng)該具有這樣的特點(diǎn):

1.服務(wù)端處理小的數(shù)據(jù)

2.大的數(shù)據(jù)(如語(yǔ)音 視頻 文件)在客戶(hù)端直接進(jìn)行傳送 無(wú)須服務(wù)器轉(zhuǎn)發(fā)

C#局域網(wǎng)聊天的程序源代碼在網(wǎng)上到處都是 千篇一律地同一種方式,,都是基于TCP協(xié)議的

服務(wù)端:?jiǎn)?dòng)后在內(nèi)存中維持一個(gè)在線(xiàn)客戶(hù)列表(數(shù)據(jù)結(jié)構(gòu)為哈希表或者字典),之后開(kāi)啟一個(gè)線(xiàn)程使用循環(huán)監(jiān)聽(tīng)客戶(hù)端的TCP連接 客戶(hù)端點(diǎn)擊登錄后請(qǐng)求建立連接,,服務(wù)端則發(fā)送在線(xiàn)列表并通知其它用戶(hù)有新用戶(hù)上線(xiàn)了,,并將這個(gè)TCP連接交給一個(gè)新的線(xiàn)程去執(zhí)行,這個(gè)新線(xiàn)程的任務(wù)就是循環(huán)地接受新連接的數(shù)據(jù) 并處理這些數(shù)據(jù),。于是服務(wù)端便這樣工作了 不停地響應(yīng)TCP連接,,一旦有新用戶(hù)就創(chuàng)建新的線(xiàn)程專(zhuān)門(mén)為該用戶(hù)服務(wù) 這樣服務(wù)端就可以做到同時(shí)響應(yīng)多個(gè)客戶(hù)的多條請(qǐng)求 很容易地就實(shí)現(xiàn)了局域網(wǎng)聊天

但是這里就有一些問(wèn)題了:運(yùn)行于Internet上的大型聊天室能這樣做嗎?

個(gè)人覺(jué)得肯定不能.如果這個(gè)程序是運(yùn)行于Internet上的 在線(xiàn)用戶(hù)數(shù)以萬(wàn)計(jì) 服務(wù)端就需要和數(shù)萬(wàn)個(gè)用戶(hù)保持這樣一個(gè)TCP連接 并且服務(wù)端上有上萬(wàn)個(gè)線(xiàn)程在運(yùn)行著

而用戶(hù)大多數(shù)時(shí)候只是掛著聊天工具 于是發(fā)生了這樣一種情況,,TCP連接數(shù)等于在線(xiàn)用戶(hù)數(shù) 線(xiàn)程數(shù)等于在線(xiàn)用戶(hù)數(shù),,而這些TCP連接絕大多數(shù)時(shí)間是沒(méi)有數(shù)據(jù)傳輸?shù)?而這些線(xiàn)程絕大多數(shù)時(shí)間也是沒(méi)有執(zhí)行實(shí)際任務(wù)的,但是它們依然消耗著網(wǎng)絡(luò)資源和CPU資源 線(xiàn)程依然在輪流地使用著CPU時(shí)間片,,它們消耗著資源卻什么也沒(méi)做,。還會(huì)產(chǎn)生一個(gè)矛盾,給服務(wù)器帶來(lái)極大的壓力 我相信沒(méi)有哪個(gè)程序能運(yùn)行上萬(wàn)個(gè)線(xiàn)程吧,!于是有了以下的突出問(wèn)題:

1.如何解決線(xiàn)程數(shù) 有效地理由CPU

2.如何解決連接數(shù)

先說(shuō)第一個(gè)問(wèn)題,,解決線(xiàn)程數(shù) .NET 提供了ThreadPool類(lèi),我們通過(guò)向線(xiàn)程池指派任務(wù)而不用使用new Thread()來(lái)為每一個(gè)客戶(hù)端創(chuàng)建一個(gè)線(xiàn)程,。但是這樣又會(huì)發(fā)生新的問(wèn)題了 由于線(xiàn)程池中的線(xiàn)程執(zhí)行任務(wù)的時(shí)間是從客戶(hù)登陸到客戶(hù)下線(xiàn),,所以可以把任務(wù)耗時(shí)看做的無(wú)限的 線(xiàn)程池規(guī)定了最大連接數(shù),盡管可以通過(guò)設(shè)置來(lái)更改最大任務(wù)數(shù)容納更多的線(xiàn)程 但太多的認(rèn)為仍然需要排隊(duì),,這可以有效的控制線(xiàn)程數(shù)量 但是依然是治標(biāo)不治本的,,運(yùn)行的線(xiàn)程依然絕大多數(shù)時(shí)候只是占著CPU而沒(méi)有處理用戶(hù)發(fā)送過(guò)來(lái)的數(shù)據(jù) 因?yàn)橛脩?hù)在線(xiàn)10個(gè)小時(shí) 服務(wù)器處理10個(gè)小時(shí)信息可能只需要1秒鐘 執(zhí)行這些任務(wù)的線(xiàn)程大多數(shù)時(shí)候只是在等待毫無(wú)無(wú)用武之地,當(dāng)用戶(hù)數(shù)太多之后服務(wù)端的響應(yīng)就變得十分遲鈍。所以像這種服務(wù)端的工作方式就決定了它只能用于在線(xiàn)人數(shù)很少局域網(wǎng)聊天 無(wú)法進(jìn)行大型多人的即時(shí)通訊,。經(jīng)過(guò)一段時(shí)間之后 我開(kāi)始接觸到異步編程,,于是對(duì)此進(jìn)行了一些更改,以充分地利用CPU

具體方式是這樣的:

1.服務(wù)器運(yùn)行我們依然需要一個(gè)線(xiàn)程持續(xù)地響應(yīng)客戶(hù)端的連接請(qǐng)求

以下是監(jiān)聽(tīng)線(xiàn)程執(zhí)行的任務(wù)

 

1 private void WaitingClient()
2 {
3     while (running)
4     {
5         remoteClient = listener.AcceptTcpClient();//同步方法
6         RemoteClient newclient = new RemoteClient(remoteClient);
7     }
8     
9 }

 

每當(dāng)我們接收到一個(gè)新的連接后 我們就實(shí)例化一個(gè)新的RemoteClient對(duì)象 而在實(shí)例化這個(gè)對(duì)象中進(jìn)行異步操作,,這里關(guān)鍵就是這個(gè)RemoteClient類(lèi)

 

代碼
 1 public class RemoteClient
 2 {
 3     private TcpClient client;
 4     private NetworkStream streamToClient;
 5     private const int bufferSize = 8192;
 6     private byte[] buffer;
 7     private string userName;
 8 
 9     public RemoteClient(TcpClient client)
10     {
11         this.client = client;
12         streamToClient = client.GetStream();
13         buffer = new byte[bufferSize];
14 
15         //異步操作完成時(shí)調(diào)用的方法
16         AsyncCallback callBack = new AsyncCallback(ReadComplete);
17         streamToClient.BeginRead(buffer, 0, bufferSize, callBack, null); //異步操作完成后將通知回調(diào)方法
18     }
19 
20     private void ReadComplete(IAsyncResult ar) //參數(shù)表示異步操作的狀態(tài)
21     {
22         int bytesRead = 0;
23         CustomMessage message;
24         try
25         {
26             lock (streamToClient)
27             {
28                 bytesRead = streamToClient.EndRead(ar);
29             }
30             if (bytesRead == 0)
31                 throw new Exception("讀取到0字節(jié)");
32             message = (CustomMessage)SerializationHelper.Deserialize(buffer);
33             switch (message.cmd)
34             {
35                 case Cmds.online:
36                     {
37                         //把鏈接的用戶(hù)加入到哈希表中
38                         Server.userTable.Add(message.message, client);
39                         userName = message.message;
40                         Server.richTextBox1.AppendText("已響應(yīng)連接請(qǐng)求" + client.Client.LocalEndPoint.ToString() + "<---" + client.Client.RemoteEndPoint.ToString() + "\n"); ;
41                         Server.richTextBox1.AppendText("用戶(hù) " + message.message + " 上線(xiàn)了\n");
42 
43                         CustomMessage tempMessage = new CustomMessage(userName, Cmds.online);//上線(xiàn)信息
44                         //通知其它用戶(hù)
45                         foreach (object c in Server.userTable.Values)
46                         {
47                             NetworkStream tempStream = ((TcpClient)c).GetStream();
48                             byte[] tempBuffer = SerializationHelper.Serialize(tempMessage);//序列化
49                             tempStream.Write(tempBuffer, 0, tempBuffer.Length);
50                         }
51                         break;
52                     }
53                 case Cmds.messageToAll:
54                     {
55                         Server.richTextBox1.AppendText("接收到數(shù)據(jù)" + message.message + "\n");
56                         break;
57                     }
58                 default:
59                     {
60                         break;
61                     }
62             }
63 
64 
65 
66             Array.Clear(buffer, 0, buffer.Length);//清空緩存
67 
68             streamToClient.Flush();//刷新流中數(shù)據(jù) 保留此方法供將來(lái)使用
69 
70             lock (streamToClient)
71             {
72                 AsyncCallback callBack = new AsyncCallback(ReadComplete);
73                 streamToClient.BeginRead(buffer, 0, bufferSize, callBack, null);
74             }
75         }
76         catch (Exception ex)
77         {
78             Server.userTable.Remove(userName);
79             Server.richTextBox1.AppendText(userName + "下線(xiàn)了,!\n");
80             //從哈希表刪除該用戶(hù)
81 
82             if (streamToClient == null)
83                 streamToClient.Dispose();
84             client.Close();
85         }
86     }
87 }

 

 

這里我們看到在實(shí)例化對(duì)象的時(shí)候定義了一個(gè)異步回調(diào)函數(shù)的委托 我們獲取streamToClient(TCP連接的數(shù)據(jù)流)之后開(kāi)始異步讀數(shù)據(jù)操作,,當(dāng)?shù)谝淮巫x操場(chǎng)完成后它將調(diào)用回調(diào)方法,回調(diào)方法處理接收到的數(shù)據(jù) 并再次進(jìn)行異步讀操作,,并在讀操作完成后回調(diào)自身再次處理數(shù)據(jù) 再次異步讀 再回調(diào)自身,,這樣形成了一個(gè)類(lèi)似在while循環(huán)中使用同步的Read()方法的效果 線(xiàn)程數(shù)會(huì)得到更有效的控制,異步編程本質(zhì)上雖然是多線(xiàn)程,,但是它在某些環(huán)境下比直接使用多線(xiàn)程有莫大的好處 這里我們用異步代替了創(chuàng)建新的線(xiàn)程或者是直接使用線(xiàn)程池 ,。服務(wù)端的線(xiàn)程數(shù)將得到真正的有效控制,并且由于是異步調(diào)用 將能充分地利用CPU提高服務(wù)端的性能.當(dāng)采用這種異步方式后 服務(wù)端處理能力的提高將是之前局域網(wǎng)聊天中服務(wù)端的成千上萬(wàn)倍,。到這里 對(duì)于線(xiàn)程數(shù),,服務(wù)端性能和充分利用CPU算有那么一個(gè)小小的成果了 采用這種方式我們可以根據(jù)服務(wù)能承載用戶(hù)數(shù)設(shè)置一些參數(shù) 這樣在監(jiān)聽(tīng)線(xiàn)程中可以加以判斷,當(dāng)在線(xiàn)用戶(hù)已達(dá)到服務(wù)器極限的時(shí)候 我們給新的客戶(hù)端服務(wù)器忙的提示,,拒絕其登陸,,就像web服務(wù)器那樣 當(dāng)連接數(shù)超過(guò)最大并發(fā)連接數(shù)的時(shí)候就返回一個(gè)錯(cuò)誤頁(yè)面

 

2.對(duì)于TCP連接數(shù) TCP既然是面向連接的,只要沒(méi)有顯示的關(guān)閉連接 則這個(gè)連接將一直存在 由于我剛接觸網(wǎng)絡(luò)編程不久,,對(duì)于一臺(tái)服務(wù)器是否有TCP連接數(shù)的限制也并不是很清楚 并且這些連接對(duì)服務(wù)器會(huì)產(chǎn)生怎樣的影響也不清楚,,我將繼續(xù)探索這方面的知識(shí)  。目前我有這樣的初步想法 只是在用戶(hù)請(qǐng)求關(guān)鍵數(shù)據(jù)的時(shí)候建立TCP連接 傳輸完畢后立即關(guān)閉,,需要時(shí)再連接 用完后再關(guān)閉,。

 

希望對(duì)網(wǎng)絡(luò)編程以及即時(shí)通訊有經(jīng)驗(yàn)的的朋友能在回復(fù)中給我提供一個(gè)大致學(xué)習(xí)的方向或者是某些建議 或者是對(duì)即時(shí)通訊軟件的工作和處理方式能有一點(diǎn)提示,或者通過(guò)電子郵箱發(fā)過(guò)來(lái)一點(diǎn)資料

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶(hù)發(fā)布,,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購(gòu)買(mǎi)等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶(hù) 評(píng)論公約

    類(lèi)似文章 更多