程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> C# Socket多線程編程實例

C# Socket多線程編程實例

編輯:C#入門知識

C#是微軟隨著VS.net新推出的一門語言。它作為一門新興的語言,有著C++的強健,又有著VB等的RAD特性。而且,微軟推出C#主要的目的是為了對抗Sun公司的Java。大家都知道Java語言的強大功能,尤其在網絡編程方面。於是,C#在網絡編程方面也自然不甘落後於人。本文就向大家介紹一下C#下實現套接字(Sockets)編程的一些基本知識,以期能使大家對此有個大致了解。首先,我向大家介紹一下套接字的概念。

套接字基本概念:

   套接字是通信的基石,是支持TCP/IP協議的網絡通信的基本操作單元。可以將套接字看作不同主機間的進程進行雙向通信的端點,它構成了單個主機內及整個網絡間的編程界面。套接字存在於通信域中,通信域是為了處理一般的線程通過套接字通信而引進的一種抽象概念。套接字通常和同一個域中的套接字交換數據(數據交換也可能穿越域的界限,但這時一定要執行某種解釋程序)。各種進程使用這個相同的域互相之間用Internet協議簇來進行通信。

   套接字可以根據通信性質分類,這種性質對於用戶是可見的。應用程序一般僅在同一類的套接字間進行通信。不過只要底層的通信協議允許,不同類型的套接字間也照樣可以通信。套接字有兩種不同的類型:流套接字和數據報套接字。

套接字工作原理:

   要通過互聯網進行通信,你至少需要一對套接字,其中一個運行於客戶機端,我們稱之為ClientSocket,另一個運行於服務器端,我們稱之為ServerSocket。

   根據連接啟動的方式以及本地套接字要連接的目標,套接字之間的連接過程可以分為三個步驟:服務器監聽,客戶端請求,連接確認。

   所謂服務器監聽,是服務器端套接字並不定位具體的客戶端套接字,而是處於等待連接的狀態,實時監控網絡狀態。

   所謂客戶端請求,是指由客戶端的套接字提出連接請求,要連接的目標是服務器端的套接字。為此,客戶端的套接字必須首先描述它要連接的服務器的套接字,指出服務器端套接字的地址和端口號,然後就向服務器端套接字提出連接請求。

   所謂連接確認,是指當服務器端套接字監聽到或者說接收到客戶端套接字的連接請求,它就響應客戶端套接字的請求,建立一個新的線程,把服務器端套接字的描述發給客戶端,一旦客戶端確認了此描述,連接就建立好了。而服務器端套接字繼續處於監聽狀態,繼續接收其他客戶端套接字的連接請求。
 C#中的套接字編程實例:

   通過向大家簡單的介紹套接字的基本概念和實現套接字編程的基本原理,我想大家對套接字編程已有了初步的了解。不過,上面介紹的僅僅是基本概念和原理,要真正運用還是需要一定的工作的。對基本概念和原理的真正理解的最好方法莫過於自己動手做一個實例,下面我就向大家介紹一個很好的用C#實現套接字編程的實例――聊天室程序。

   本程序是基於C/S(服務器/客戶端)構架的,程序包含一個服務器端的應用程序和一個客戶端的應用程序。首先,在服務器上運行服務器端的應用程序,該程序一運行就開始服務器監聽。然後,在客戶機上就可以打開客戶端的應用程序。程序打開後可以與服務器端應用程序進行連接,即進行客戶端請求。在連接確認後,客戶端用戶可以和其他的客戶端用戶進行聊天。客戶端人數沒有限制,同時還支持“悄悄話”聊天模式,支持聊天記錄。所以這是一個學習套接字編程的相當不錯的例子。而且,程序中為了處理每個客戶端的信息還用到了多線程機制。在每個客戶端與服務器端連接成功後,它們之間就建立一個線程。這樣運用了多線程之後,客戶端之間就不會相互影響,即使其中一個出了錯誤也不會影響到另一個。

   下面,我就向大家具體介紹該實例:

   服務器端程序:

   1. 打開VS.net,新建一個C#的模板為“Windows 應用程序”的項目,不妨命名為“ChatServer”。

   2. 布置界面。只需在界面上添加一個ListBox控件即可,該控件主要用於顯示客戶端的用戶的一些信息的。圖象如下:

\

   3. 服務器端程序的代碼編寫。
 對於服務器端,主要的作用是監聽客戶端的連接請求並確認其請求。程序一開始便打開一個StartListening()線程。

private void StartListening()
{
  listener = new TcpListener(listenport);
  listener.Start();
  while (true)
  {
   try
   {
    Socket s = listener.AcceptSocket();
    clientsocket = s;
    clientservice = new Thread(new ThreadStart(ServiceClient));
    clientservice.Start();
   }
   catch(Exception e)
   {
    Console.WriteLine(e.ToString() );
   }
  }
}
   該線程是一直處於運行狀態的。當服務器端接收到一個來自客戶端的連接請求後,它就打開一個ServiceClient()線程來服務客戶端。當一個連接被建立後,每個客戶端就被賦予一個屬於它自己的套接字。同時,一個Client類的對象被建立。該對象包含了客戶端的一些相關信息,該信息被保存在一個數組列表中。    Client類如下:

using System;
using System.Threading;

namespace ChatServer
{
using System.Net.Sockets;
using System.Net;

///
/// Client 的摘要說明。
///
public class Client
{
private Thread clthread;
private EndPoint endpoint;
private string name;
private Socket sock;

public Client(string _name, EndPoint _endpoint, Thread _thread, Socket _sock)
{
// TODO: 在此處添加構造函數邏輯
clthread = _thread;
endpoint = _endpoint;
name = _name;
sock = _sock;
}

public override string ToString()

      return endpoint.ToString()+ " : " + name;
}

public Thread CLThread
{
get{return clthread;}
set{clthread = value;}
}

public EndPoint HZ喎?http://www.BkJia.com/kf/ware/vc/" target="_blank" class="keylink">vc3QgPGJyIC8+DQp7IDxiciAvPg0KZ2V0e3JldHVybiBlbmRwb2ludDt9IDxiciAvPg0Kc2V0e2VuZHBvaW50ID0gdmFsdWU7fSA8YnIgLz4NCn0gPGJyIC8+DQo8YnIgLz4NCnB1YmxpYyBzdHJpbmcgTmFtZSA8YnIgLz4NCnsgPGJyIC8+DQpnZXR7cmV0dXJuIG5hbWU7fSA8YnIgLz4NCnNldHtuYW1lID0gdmFsdWU7fSA8YnIgLz4NCn0gPGJyIC8+DQo8YnIgLz4NCnB1YmxpYyBTb2NrZXQgU29jayA8YnIgLz4NCnsgPGJyIC8+DQpnZXR7cmV0dXJuIHNvY2s7fSA8YnIgLz4NCnNldHtzb2NrID0gdmFsdWU7fSA8YnIgLz4NCn0gPGJyIC8+DQp9IDxiciAvPg0KfSA8YnIgLz4NCqGhoaEgs8zQ8rXE1vfM5bK/t9bTpsrHU2VydmljZUNsaWVudKOoo6m6r8r9oaO4w7qvyv3Kx9K7uPa2wMGitcTP37PMo6zG5Nb30qqyv7fWysfSu7j2d2hpbGXRrbu3oaPU2tGtu7fM5cTao6yzzNDytKbA7bj31ta/zbuntsvD/MHuoaO3/s7xxve2y73TytXAtNfUv827p7bLtcTS1EFTQ0lJwuu4+LP2tcTX1rf7tK6jrMbk1tCw/LqswcvSu7j2JmxkcXVvOw=="”形式的分隔符。字符串中“|”以前的部分就是具體的命令,包括CONN、CHAT、PRIV、GONE四種類型。CONN命令建立一個新的客戶端連接,將現有的用戶列表發送給新用戶並告知其他用戶有一個新用戶加入。CHAT命令將新的信息發送給所有用戶。PRIV命令將悄悄話發送給某個用戶。GONE命令從用戶列表中除去一個已離開的用戶並告知其他的用戶某某已經離開了。同時,GONE命令可以設置布爾型的變量keepalive為false從而結束與客戶端連接的線程。ServiceClient()函數如下:

private void ServiceClient()
{
Socket client = clientsocket;
bool keepalive = true;


while (keepalive)
{
Byte[] buffer = new Byte[1024];
client.Receive(buffer);
string clientcommand = System.Text.Encoding.ASCII.GetString(buffer);


string[] tokens = clientcommand.Split(new Char[]{|});
Console.WriteLine(clientcommand);


if (tokens[0] == "CONN")
{
for(int n=0; n
{
Client cl = (Client)clients[n];
SendToClient(cl, "JOIN|" + tokens[1]);
}
EndPoint ep = client.RemoteEndPoint;
Client c = new Client(tokens[1], ep, clientservice, client);
clients.Add(c);
string message = "LIST|" + GetChatterList() +" ";
SendToClient(c, message);


lbClients.Items.Add(c);


}
if (tokens[0] == "CHAT")
{
for(int n=0; n
{
Client cl = (Client)clients[n];
SendToClient(cl, clientcommand);
}
}
if (tokens[0] == "PRIV")
{
string destclient = tokens[3];
for(int n=0; n
{
Client cl = (Client)clients[n];
if(cl.Name.CompareTo(tokens[3]) == 0)
SendToClient(cl, clientcommand);
if(cl.Name.CompareTo(tokens[1]) == 0)

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved