網路程式設計之即時通訊程式(聊天室)------(一)通訊流程簡介及通訊協議定製
在開始講之前,我想先跟大家描述一下,這個所謂的通訊程式具體是一個什麼樣的東西。該通訊程式類似一個弱版本的qq,登入時需要進行註冊,登入成功後,可以實現即時的通訊,群聊,私聊,同時還可傳檔案。先上個圖
服務端: 客戶端登入: 客戶端主介面:
所謂的即時的通訊程式,也就是利用TCP和UDP的傳輸協議,進行資訊、檔案的傳輸。那什麼是TCP,什麼是UDP呢?
TCP是Transmission Control Protocol
UDP 是User Datagram Protocol(使用者資料報協議)的簡稱,是 OSI 參考模型中一種無連線的傳輸層協議,提供面向事務的簡單不可靠資訊傳送服務。UDP協議的主要特點是:基於無連線協議,資料傳送迅速,反應快,同時缺點也很明顯,就是資料傳輸不穩定,不能保證資料到達的順序,可能會有資料的缺失。
我們所熟悉的QQ就是一種基於TCP和UDP兩種協議結合的一種即時通訊程式,在我們進行會話、聊天的時候,採用UDP協議,通過伺服器中轉方式。大家都知道,UDP 協議是不可靠協議,它只管傳送,不管對方是否收到的,但它的傳輸很高效。但是,作為聊天軟體,怎麼可以採用這樣的不可靠方式來傳輸訊息呢?於是,騰訊採用了上層協議來保證可靠傳輸:如果客戶端使用UDP協議發出訊息後,伺服器收到該包,需要使用UDP協議發回一個應答包。如此來保證訊息可以無遺漏傳輸。之所以會發生在客戶端明明看到“訊息傳送失敗”但對方又收到了這個訊息的情況,就是因為客戶端發出的訊息伺服器已經收到並轉發成功,但客戶端由於網路原因沒有收到伺服器的應答包引起的。在我們進行檔案傳輸的時候使用的是基於TCP的資料傳輸協議,因為要保證傳輸資料的順序到達,同時還要保證不能有資料的丟失。
在我們的.NET平臺下如果想要實現即時的通訊就需要藉助於Socket網路程式設計,Socket(網路套接字)是網路通訊的基本構件,它是可以被命名和定址的通訊埠,使用中,每個Socket 都有對應的型別和一個與之相關的程序。在開始介紹Socket建立即時通訊之前我們需要先了解下使用TCP進行即時通訊的操作流程:
下邊我會結合這個流程圖,一步一步跟大家講通訊的具體流程。
1、建立服務端套接字,監聽本機的IP和一個特定的埠,把本機作為服務端。(下面的只是一個簡單的演示例項)
int port = 11615;//監聽埠,最好設定的大一些,避免和一些特定的埠衝突IPAddress ipAdd=IPAddress.Parse(“192.168.245.1”);//監聽IP,我們通過Dns.GetByHostName().Arrylist[],動態獲得本機的IP,這裡僅是示例。TcpListener listener=new TcpListener(ipAdd, port);//建立監聽物件
2、監聽伺服器埠,等待客戶端連線請求
listener.Start();
3、建立客戶端的套接字,並向遠端服務端傳送連線請求
TcpClient tcpClient=new TcpClient();int port = 11615;IPAddress ipAdd=IPAddress.Parse(“192.168.245.1”); tcpClient.Connect(ipAdd, port);
4、服務端確認與客戶端的連線,並建立與該客戶端對應的Socket物件
Socket clientSocket= listener.AcceptSocket();
5、客戶端獲取與伺服器通訊的流通道
NetworkStream stream = tcpClient.GetStream();
6、客戶端通過流通道與伺服器端進行資料傳輸
6.1、客戶端向伺服器端傳送數
string hello=“Hello World!”;byte [] buffer=Encoding.Default.GetBytes(hello);stream.Write(buffer,0,buffer.Length);
6.2、客戶端接收從伺服器端發來的資料
byte [] buffer=new byte[1024];int length= stream.Read(buff,0,buff.Length);string msg = Encoding.Default.GetString(buffer,0,length);
7、服務端接受客戶端請求
7.1、服務端向客戶端傳送資料
string hello=“Hello World!”;byte [] buffer=Encoding.Default.GetBytes(hello);stream.Write(buffer,0,buffer.Length);
7.2、服務端接收從客戶器端發來的資料
byte [] buffer=new byte[1024];int length= stream.Read(buff,0,buff.Length);string msg = Encoding.Default.GetString(buffer,0,length);
8、服務端斷開與客戶端的連線
clientSocket.Close();
9、客戶端斷開與服務端的連線
tcpClient.Close();
10、服務端關閉服務套接字
tcpClient.Close();
大體的通訊流程就是這樣子,但是到具體的實際應用中還有不同 ,因為我們要涉及到多個客戶端之間的互動,而服務端只是相當於一箇中間的媒介,接收客戶端傳遞的訊息,並將訊息轉發給另一個客戶端,如果有多個客戶端,同時進行通訊,而這個時候就需要用到多執行緒進行通訊的管理和控制。
具體的流程如下:
首先,我們在需要服務端建立一個TCPLister物件,啟用一個執行緒,專門負責監聽客戶端的請求。
其次,只要有一個客戶端進行請求 ,則TCPLister物件會馬上建立一個專門負責通訊的Socket與客戶端請求的套接字,
同時再啟用一個新的執行緒專門負責與客戶端進行通訊。
在客戶端,我們只需要建立一個TCPClient物件,啟用一個新的執行緒來專門的負責資訊的接受即可。
在具體的通過過程中,我們還需要定製一些列的訊息通訊協議,在訊息內部用“|”管道符將其內容進行分割,通過對協議的解析我們可以對不同的訊息做不同的處理。在本應用才程式中,具體的通訊協議如下:
在服務端接收協議如下:
命令格式 接收到客戶端傳送的通訊流的位元組陣列中的首位元組Msg[0] |
說明 1、如果Msg[0]則說明發送的是檔案,則遍歷線上使用者列表,像使用者線上使用者逐一發送該位元組陣列 2、如果Msg[0]!=0,則說明發送過來的資訊字串,則直接進行Encoding將位元組陣列轉換為字串,並對字串進行如下的分析,根據不同的分析結果執行不同的命令。 |
ON|傳送者的使用者名稱| |
1、該命令在客戶端與伺服器端建立連線後由客戶端自動傳送 2、伺服器端收到該命令後,將“使用者名稱”新增到線上使用者列表並向所有線上使用者傳送訊息“***上線啦!" |
Off|傳送者的使用者名稱| |
1、該命令是在使用者上線、或者離開時執行的,用於向客戶端傳送線上人員名單,客戶端接受到該資訊後就會對線上列表進行更新。 |
MSG|接收者姓名|傳送者姓名|傳送內容| MSGALL|傳送者的使用者名稱|傳送內容| |
1、該命令是使用者點擊發送訊息按鈕時,傳送的資訊,前提是使用者必須選定要傳送的物件 2、服務端收到該訊息後,對訊息進行解析,從中取得接受者使用者名稱,並從線上列表中取得相應的通訊Socket,將“傳送者使用者名稱說“傳送內容“這樣格式的訊息傳送回客戶端 3、如果是MSGALL,則為群發訊息,伺服器端收到該命令後,將遍歷線上使用者列表的使用者,並逐一向線上使用者傳送”傳送者的使用者名稱說‘傳送內容’”這樣的資訊傳送給所有的線上使用者 |
在客戶端接收協議如下:
命令格式 |
說明 |
接受服務端傳送的通訊流位元組陣列中的首位元組Msg[0] |
如果Msg[0]==0則說明服務端傳送的是檔案,直接新建檔案流從接收到的位元組陣列中的第二個位元組開始讀取,讀取長度為位元組陣列長度減一個位元組,並在本地儲存檔案。 如果Msg[0]!=0則說明服務端傳送的是訊息字串,然後再根據下面的命令格式進行解析,進而做出不同的操作 |
OnLine|剛登入的使用者名稱| |
客戶端收到該命令後,在聊天串列埠中看到“****”上線了的通知! |
Off|使用者1、使用者2、使用者3、| |
該命令是在伺服器端收到客戶端發來的Off和On命令,回發給客戶端的命令,然後客戶端解析命令,更新線上人員列表。 |
以上這些就是該即時通訊程式的通訊格式,在下一節中,我會帶領大家一步一步的構建該即時通訊程式的服務端,在構建的過程中會逐步向大家演示TCPLister的應用,以及相關的涉及的多執行緒的知識。
好了,這一節就到這裡了,希望能給大家帶來些許幫助,同時也希望大家多多指點。