Socket多線程編程實(shí)例_第1頁(yè)
Socket多線程編程實(shí)例_第2頁(yè)
Socket多線程編程實(shí)例_第3頁(yè)
Socket多線程編程實(shí)例_第4頁(yè)
已閱讀5頁(yè),還剩9頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶(hù)提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、C# Socket多線程編程實(shí)例時(shí)間 : 2010-09-05 23:42來(lái)源 : 未知?作者: admin?點(diǎn)擊: 1073次我要投稿 ?高質(zhì)量的ASP.NET空間,完美支持1.0/2.0/3.5/4.0/MVC等C#是微軟隨著 VS.net 新推出的一門(mén)語(yǔ)言。它作為一門(mén)新興的語(yǔ)言,有著 C+的強(qiáng)健,又有著 VB等的 RAD特性。而且,微軟推出 C#主要的目的是為了對(duì)抗 Sun 公司的 Java。大家都知道 Java 語(yǔ)言的強(qiáng)大功能,尤其在網(wǎng)絡(luò)編程方面。于是, C#在網(wǎng)絡(luò)編程方面也自然不甘落后于人。本文就向大家介紹一下C#下實(shí)現(xiàn)套接字( Sockets )編程的一些基本知識(shí),以期能使大家對(duì)此

2、有個(gè)大致了解。首先,我向大家介紹一下套接字的概念。?套接字基本概念: ?套接字是通信的基石,是支持 TCP/IP 協(xié)議的網(wǎng)絡(luò)通信的基本操作單元??梢詫⑻捉幼挚醋鞑煌鳈C(jī)間的進(jìn)程進(jìn)行雙向通信的端點(diǎn),它構(gòu)成了單個(gè)主機(jī)內(nèi)及整個(gè)網(wǎng)絡(luò)間的編程界面。套接字存在于通信域中,通信域是為了處理一般的線程通過(guò)套接字通信而引進(jìn)的一種抽象概念。套接字通常和同一個(gè)域中的套接字交換數(shù)據(jù)(數(shù)據(jù)交換也可能穿越域的界限,但這時(shí)一定要執(zhí)行某種解釋程序)。各種進(jìn)程使用這個(gè)相同的域互相之間用 Internet 協(xié)議簇來(lái)進(jìn)行通信。 ?套接字可以根據(jù)通信性質(zhì)分類(lèi),這種性質(zhì)對(duì)于用戶(hù)是可見(jiàn)的。應(yīng)用程序一般僅在同一類(lèi)的套接字間進(jìn)行通信。不過(guò)只

3、要底層的通信協(xié)議允許,不同類(lèi)型的套接字間也照樣可以通信。套接字有兩種不同的類(lèi)型:流套接字和數(shù)據(jù)報(bào)套接字。?套接字工作原理: ?要通過(guò)互聯(lián)網(wǎng)進(jìn)行通信,你至少需要一對(duì)套接字,其中一個(gè)運(yùn)行于客戶(hù)機(jī)端,我們稱(chēng)之為 ClientSocket ,另一個(gè)運(yùn)行于服務(wù)器端,我們稱(chēng)之為 ServerSocket 。?根據(jù)連接啟動(dòng)的方式以及本地套接字要連接的目標(biāo),套接字之間的連接過(guò)程可以分為三個(gè)步驟:服務(wù)器監(jiān)聽(tīng),客戶(hù)端請(qǐng)求,連接確認(rèn)。 ?所謂服務(wù)器監(jiān)聽(tīng),是服務(wù)器端套接字并不定位具體的客戶(hù)端套接字,而是處于等待連接的狀態(tài),實(shí)時(shí)監(jiān)控網(wǎng)絡(luò)狀態(tài)。 ?所謂客戶(hù)端請(qǐng)求,是指由客戶(hù)端的套接字提出連接請(qǐng)求,要連接的目標(biāo)是服務(wù)器端的

4、套接字。為此,客戶(hù)端的套接字必須首先描述它要連接的服務(wù)器的套接字,指出服務(wù)器端套接字的地址和端口號(hào),然后就向服務(wù)器端套接字提出連接請(qǐng)求。?所謂連接確認(rèn),是指當(dāng)服務(wù)器端套接字監(jiān)聽(tīng)到或者說(shuō)接收到客戶(hù)端套接字的連接請(qǐng)求,它就響應(yīng)客戶(hù)端套接字的請(qǐng)求,建立一個(gè)新的線程,把服務(wù)器端套接字的描述發(fā)給客戶(hù)端,一旦客戶(hù)端確認(rèn)了此描述, 連接就建立好了。 而服務(wù)器端套接字繼續(xù)處于監(jiān)聽(tīng)狀態(tài),繼續(xù)接收其他客戶(hù)端套接字的連接請(qǐng)求。C#中的套接字編程實(shí)例: ?通過(guò)向大家簡(jiǎn)單的介紹套接字的基本概念和實(shí)現(xiàn)套接字編程的基本原理,我想大家對(duì)套接字編程已有了初步的了解。不過(guò),上面介紹的僅僅是基本概念和原理,要真正運(yùn)用還是需要一定的

5、工作的。對(duì)基本概念和原理的真正理解的最好方法莫過(guò)于自己動(dòng)手做一個(gè)實(shí)例,下面我就向大家介紹一個(gè)很好的用 C#實(shí)現(xiàn)套接字編程的實(shí)例聊天室程序。 ?本程序是基于 C/S(服務(wù)器 / 客戶(hù)端)構(gòu)架的,程序包含一個(gè)服務(wù)器端的應(yīng)用程序和一個(gè)客戶(hù)端的應(yīng)用程序。首先,在服務(wù)器上運(yùn)行服務(wù)器端的應(yīng)用程序,該程序一運(yùn)行就開(kāi)始服務(wù)器監(jiān)聽(tīng)。然后,在客戶(hù)機(jī)上就可以打開(kāi)客戶(hù)端的應(yīng)用程序。程序打開(kāi)后可以與服務(wù)器端應(yīng)用程序進(jìn)行連接,即進(jìn)行客戶(hù)端請(qǐng)求。在連接確認(rèn)后,客戶(hù)端用戶(hù)可以和其他的客戶(hù)端用戶(hù)進(jìn)行聊天。客戶(hù)端人數(shù)沒(méi)有限制,同時(shí)還支持“悄悄話”聊天模式,支持聊天記錄。所以這是一個(gè)學(xué)習(xí)套接字編程的相當(dāng)不錯(cuò)的例子。而且,程序中為了

6、處理每個(gè)客戶(hù)端的信息還用到了多線程機(jī)制。在每個(gè)客戶(hù)端與服務(wù)器端連接成功后,它們之間就建立一個(gè)線程。這樣運(yùn)用了多線程之后,客戶(hù)端之間就不會(huì)相互影響,即使其中一個(gè)出了錯(cuò)誤也不會(huì)影響到另一個(gè)。 ?下面,我就向大家具體介紹該實(shí)例:?服務(wù)器端程序: ?1 打開(kāi) VS.net ,新建一個(gè) C#的模板為“ Windows 應(yīng)用程序”的項(xiàng)目,不妨命名為“ChatServer ”。 ?2 布置界面。只需在界面上添加一個(gè) ListBox 控件即可,該控件主要用于顯示客戶(hù)端的用戶(hù)的一些信息的。圖象如下: ?3 服務(wù)器端程序的代碼編寫(xiě)。對(duì)于服務(wù)器端,主要的作用是監(jiān)聽(tīng)客戶(hù)端的連接請(qǐng)求并確認(rèn)其請(qǐng)求。程序一開(kāi)始便打開(kāi)一個(gè)

7、StartListening ()線程。private void StartListening()listener = new TcpListener(listenport);listener.Start();while (true)trySocket s = listener.AcceptSocket();clientsocket = s;clientservice = new Thread(new ThreadStart(ServiceClient); clientservice.Start();catch(Exception e)Console.WriteLine(e.ToString(

8、) );該線程是一直處于運(yùn)行狀態(tài)的。當(dāng)服務(wù)器端接收到一個(gè)來(lái)自客戶(hù)端的連接請(qǐng)求后,它就打開(kāi)一個(gè) ServiceClient ()線程來(lái)服務(wù)客戶(hù)端。當(dāng)一個(gè)連接被建立后,每個(gè)客戶(hù)端就被賦予一個(gè)屬于它自己的套接字。同時(shí),一個(gè) Client 類(lèi)的對(duì)象被建立。該對(duì)象包含了客戶(hù)端的一些相關(guān)信息,該信息被保存在一個(gè)數(shù)組列表中。 Client 類(lèi)如下:using System;using System.Threading;namespace ChatServerusing System.Net;/ Client的摘要說(shuō)明。/public class Clientprivate Thread clthread;p

9、rivate EndPoint endpoint;private string name;private Socket sock;public Client(string _name, EndPoint _endpoint, Thread _thread, Socket _sock)/ TODO: 在此處添加構(gòu)造函數(shù)邏輯clthread = _thread;endpoint = _endpoint;name = _name;sock = _sock;public override string ToString()return endpoint.ToString()+ " : &qu

10、ot; + name;public Thread CLThreadgetreturn clthread;setclthread = value;public EndPoint Hostgetreturn endpoint;setendpoint = value;public string Namegetreturn name;setname = value;public Socket Sockgetreturn sock;setsock = value;程序的主體部分應(yīng)是 ServiceClient ()函數(shù)。該函數(shù)是一個(gè)獨(dú)立的線程,其主要部分是一個(gè) while 循環(huán)。在循環(huán)體內(nèi),程序處理各種

11、客戶(hù)端命令。服務(wù)器端接收來(lái)自客戶(hù)端的以 ASCII 碼給出的字符串,其中包含了一個(gè)“ | ”形式的分隔符。字符串中“ | ”以前的部分就是具體的命令,包括 CONN、 CHAT、 PRIV、GONE四種類(lèi)型。 CONN命令建立一個(gè)新的客戶(hù)端連接, 將現(xiàn)有的用戶(hù)列表發(fā)送給新用戶(hù)并告知其他用戶(hù)有一個(gè)新用戶(hù)加入。 CHAT命令將新的信息發(fā)送給所有用戶(hù)。 PRIV 命令將悄悄話發(fā)送給某個(gè)用戶(hù)。 GONE命令從用戶(hù)列表中除去一個(gè)已離開(kāi)的用戶(hù)并告知其他的用戶(hù)某某已經(jīng)離開(kāi)了。 同時(shí),GONE命令可以設(shè)置布爾型的變量 keepalive 為 false 從而結(jié)束與客戶(hù)端連接的線程。 ServiceClient

12、 ()函數(shù)如下:private void ServiceClient()Socket client = clientsocket;bool keepalive = true;while (keepalive)Byte buffer = new Byte1024;client.Receive(buffer);string tokens = clientcommand.Split(new Char'|'); Console.WriteLine(clientcommand);if (tokens0 = "CONN")for(int n=0; nClient cl

13、= (Client)clientsn;SendToClient(cl, "JOIN|" + tokens1);EndPoint ep = client.RemoteEndPoint;Client c = new Client(tokens1, ep, clientservice, client); clients.Add(c);string message = "LIST|" + GetChatterList() +"rn"SendToClient(c, message);if (tokens0 = "CHAT")

14、for(int n=0; nClient cl = (Client)clientsn;SendToClient(cl, clientcommand);if (tokens0 = "PRIV")string destclient = tokens3;for(int n=0; nClient cl = (Client)clientsn;SendToClient(cl, clientcommand);SendToClient(cl, clientcommand);if (tokens0 = "GONE")int remove = 0;bool found =

15、false;int c = clients.Count;for(int n=0; nClient cl = (Client)clientsn;SendToClient(cl, clientcommand);remove = n;found = true;if(found)clients.RemoveAt(remove);client.Close();keepalive = false;這樣,服務(wù)器端程序就基本完成了。(其他略次要的代碼可以參見(jiàn)源代碼中的 Form1.cs 文件)程序運(yùn)行圖示如下:客戶(hù)端程序:1 打開(kāi) VS.net ,新建一個(gè) C#的模板為“ Windows 應(yīng)用程序”的項(xiàng)目,不

16、妨命名為“ChatClient ”。2 布置界面。往界面上添加一個(gè) ListBox 控件(用于顯示用戶(hù)列表),一個(gè) RichTextBox 控件(用于顯示聊天消息以及系統(tǒng)消息),一個(gè) TextBox 控件(用于發(fā)送消息),一個(gè) CheckBox控件(確定是否為悄悄話),一個(gè) StatusBar 控件以及四個(gè) Button 控件(分別為“連接”、“斷開(kāi)連接”、“開(kāi)始記錄”、“發(fā)送”)。各個(gè)控件的屬性設(shè)置可以參見(jiàn)源代碼中的具體設(shè)置,這里從略。界面設(shè)計(jì)好后的圖象如下:3 客戶(hù)端程序的代碼編寫(xiě)。當(dāng)客戶(hù)端試圖和服務(wù)器端進(jìn)行連接時(shí),一個(gè)連接必須建立而且得向服務(wù)器端進(jìn)行注冊(cè)。 EstablishConnec

17、tion ()函數(shù)運(yùn)用一個(gè) TcpClient 來(lái)和服務(wù)器端取得連接,同時(shí)創(chuàng)建一個(gè) NetworkStream 來(lái)發(fā)送消息。還有,端口號(hào)和服務(wù)器端的是保持一致的, 均為 5555。EstablishConnection()函數(shù)如下:private void EstablishConnection()statusBar1.Text = "正在連接到服務(wù)器 "tryclientsocket = new TcpClient(serveraddress,serverport); ns = clientsocket.GetStream();sr = new StreamReader(

18、ns);connected = true;catch (Exception)MessageBox.Show("不能連接到服務(wù)器! "," 錯(cuò)誤 ", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); statusBar1.Text = " 已斷開(kāi)連接 " 在和服務(wù)器端連接成功后,程序就用 RegisterWithServer ()函數(shù)向服務(wù)器端發(fā)送一個(gè) CONN命令。該命令先是發(fā)送該用戶(hù)的名稱(chēng),然后從服務(wù)器端獲得其他所有用戶(hù)的列表,所有用戶(hù)列表是在ListBox 控件中顯示的。該函數(shù)

19、如下:private void RegisterWithServer()trystring command = "CONN|" + ChatOut.Text;ns.Write(outbytes,0,outbytes.Length);string serverresponse = sr.ReadLine();serverresponse.Trim();string tokens = serverresponse.Split(new Char'|'); if(tokens0 = "LIST")statusBar1.Text = "已

20、連接 "btnDisconnect.Enabled = true;for(int n=1; nthis.Text = clientname + ":已連接到服務(wù)器 "catch (Exception)MessageBox.Show("注冊(cè)時(shí)發(fā)生錯(cuò)誤! "," 錯(cuò)誤 ", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);在此之后,當(dāng)然就是用戶(hù)之間的聊天了,由ReceiveChat ()函數(shù)來(lái)完成。該函數(shù)是一個(gè)獨(dú)立的線程,它處理所有用戶(hù)獲得的消息和用戶(hù)發(fā)送的消息。它主要處理了C

21、HAT、PRIV、JOIN、GONE、QU99v等命令,處理的方法和服務(wù)器端的類(lèi)似。具體函數(shù)實(shí)現(xiàn)如下:private void ReceiveChat()bool keepalive = true;while (keepalive)tryByte buffer = new Byte2048;ns.Read(buffer,0,buffer.Length);string tokens = chatter.Split(new Char'|');if (tokens0 = "CHAT")rtbChatIn.AppendText(tokens1);if(logging

22、)logwriter.WriteLine(tokens1);if (tokens0 = "PRIV")rtbChatIn.AppendText("Private from ");rtbChatIn.AppendText(tokens1.Trim() );rtbChatIn.AppendText(tokens2 + "rn");if(logging)logwriter.Write("Private from ");logwriter.Write(tokens1.Trim() );logwriter.WriteLine

23、(tokens2 + "rn");if (tokens0 = "JOIN")rtbChatIn.AppendText(tokens1.Trim() );rtbChatIn.AppendText(" has joined the Chatrn");if(logging)logwriter.WriteLine(tokens1+" has joined the Chat");string newguy = tokens1.Trim(new char'r','n');if (tokens0

24、= "GONE")rtbChatIn.AppendText(tokens1.Trim() );rtbChatIn.AppendText(" has left the Chatrn");if(logging)logwriter.WriteLine(tokens1+" has left the Chat");if (tokens0 = "QU99v")ns.Close();clientsocket.Close();keepalive = false;statusBar1.Text = "服務(wù)器端已停止 &qu

25、ot;connected= false;btnSend.Enabled = false;btnDisconnect.Enabled = false;catch(Exception)通過(guò)以上的一些函數(shù),客戶(hù)端程序之間就可以進(jìn)行自由地聊天了,各個(gè)用戶(hù)之間還可以互相發(fā)送悄悄話。所以程序已經(jīng)實(shí)現(xiàn)了聊天室的基本功能了,不過(guò)最后各個(gè)用戶(hù)還要正常地退出,那就要用到 QuitChat ()函數(shù)了。該函數(shù)的具體實(shí)現(xiàn)如下:private void QuitChat()if(connected)trystring command = "GONE|" + clientname;ns.Write(o

26、utbytes,0,outbytes.Length);clientsocket.Close();catch(Exception)if(logging)logwriter.Close();if(receive != null && receive.IsAlive)receive.Abort();this.Text = "客戶(hù)端 "到此為止,客戶(hù)端程序的主要部分都已經(jīng)介紹完畢。還有一些按鈕控件的消息處理函數(shù)可以參見(jiàn)源代碼。同時(shí),程序中還有一個(gè)聊天記錄功能,該功能和現(xiàn)在流行的聊天軟件的記錄功能類(lèi)似。不過(guò)限于篇幅,在這里就不一一介紹了,有興趣的讀者可以研究一下本文后

27、面的源代碼。這樣,客戶(hù)端程序就完成了。程序運(yùn)行圖示如下:總結(jié):本文向大家初步介紹了套接字的基本概念和實(shí)現(xiàn)套接字編程的基本原理,還通過(guò)一個(gè)很好的實(shí)例向大家展示了在 C#下進(jìn)行套接字編程的實(shí)現(xiàn)方法和一些編程技巧。 從中,我們不難發(fā)現(xiàn)運(yùn)用 C#進(jìn)行套接字編程乃至網(wǎng)絡(luò)編程有許多優(yōu)越之處。 實(shí)例程序?qū)崿F(xiàn)的思路清晰明了而且通俗易懂,是一個(gè)相當(dāng)不錯(cuò)的例子,希望各位能好好研讀。同時(shí)還希望大家能進(jìn)一步完善該程序,使之功能更強(qiáng)大、界面更友好。在此之后,當(dāng)然就是用戶(hù)之間的聊天了,由 ReceiveChat ()函數(shù)來(lái)完成。該函數(shù)是一個(gè)獨(dú)立的線程,它處理所有用戶(hù)獲得的消息和用戶(hù)發(fā)送的消息。它主要處理了 CHAT、PR

28、IV、JOIN、GONE、QU99v等命令,處理的方法和服務(wù)器端的類(lèi)似。具體函數(shù)實(shí)現(xiàn)如下:private void ReceiveChat()bool keepalive = true;while (keepalive)tryByte buffer = new Byte2048;ns.Read(buffer,0,buffer.Length);string tokens = chatter.Split(new Char'|');if (tokens0 = "CHAT")rtbChatIn.AppendText(tokens1);if(logging)logwr

29、iter.WriteLine(tokens1);if (tokens0 = "PRIV")rtbChatIn.AppendText("Private from ");rtbChatIn.AppendText(tokens1.Trim() );rtbChatIn.AppendText(tokens2 + "rn");if(logging)logwriter.Write("Private from ");logwriter.Write(tokens1.Trim() );logwriter.WriteLine(token

30、s2 + "rn");if (tokens0 = "JOIN")rtbChatIn.AppendText(tokens1.Trim() );rtbChatIn.AppendText(" has joined the Chatrn");if(logging)logwriter.WriteLine(tokens1+" has joined the Chat");string newguy = tokens1.Trim(new char'r','n');if (tokens0 = "GONE")rtbChatIn.AppendText(tokens1.Trim() );rtbChatIn.AppendText(" has left the Chatr

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶(hù)所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶(hù)上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶(hù)上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶(hù)因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論