完整的TCP通信包實現

- 中國WEB開發者網絡 (http://www.webasp.net)
-- 技術教程 (http://www.webasp.net/article/)
--- 完整的TCP通信包實現 (http://www.webasp.net/article/17/16513.htm)
-- 作者:未知
-- 發佈日期: 2005-02-03
using System;

namespace Jh.Sockets
{
/// <summary>
/// 線程狀態信號定義
/// </summary>
public enum JhThreadStatus
{
Stop, //停止
Running, //正在運行
Exit //已退出
}
/// <summary>
/// 線程狀態參數
/// </summary>
class Parm
{
public Parm(object obj):this(JhThreadStatus.Stop,obj)
{
}
public Parm(JhThreadStatus nStatus,object obj)
{
Status = nStatus;
ObjParm = obj;
}
JhThreadStatus status;
object objParm;
/// <summary>
/// 上下文對像
/// </summary>
public object ObjParm
{
get
{
return objParm;
}
set
{
objParm = value;
}
}
/// <summary>
/// 控制狀態
/// </summary>
public JhThreadStatus Status
{
get
{
return status;
}
set
{
status = value;
}
}
};
/// <summary>
/// 通訊數據處理接口
/// </summary>
public interface IObserver
{
//
// 數據處理入口
//
void Deal(CommData cd);

//
// 數據處理重載方法.如果不希望後面的處理者繼續處理數據,則返回true,否則返回false;
//
bool OnDeal(CommData cd);

//
// 附加的自身初始化操作
//
bool Init();

//
// 提前初始化接口
//
bool BeforeInit();

//
// 初始化後處理接口
//
bool AfterInit();

//
// 刪除前處理接口
//
bool BeforeExit();

//
// 下一個觀察者
//
IObserver Next
{
get;
set;
}

//
// 上一個觀察者
//
IObserver Prev
{
get;
set;
}

//
// 添加觀察者到後面,如果已經存在鏈表中則不做任何操作
//
void Add(IObserver observer);

//
// 插入觀察者到下一個觀察者的前面
//
void Insert(IObserver observer);
//刪除觀察者
void Remove(IObserver observer);
//是否存在鏈表中
bool IsExist(IObserver observer);
}
/// <summary>
/// 通訊數據處理類的基類,只能派生
/// </summary>
public abstract class Observer : IObserver
{
/// <summary>
/// 數據處理入口.
/// </summary>
/// <param name="client">TcpClient類 實例</param>
/// <param name="s">內存數據流</param>
public void Deal(CommData cd)
{
cd.Data.Position = 0;
if (OnDeal(cd) == false) return ;
if (next != null)
{
next.Deal(cd);
}
return ;
}

/// <summary>
/// 數據處理重載方法.
/// </summary>
/// <param name="client">TcpClient類 實例</param>
/// <param name="s">內存數據流</param>
/// <returns>處理結果,如果不希望後面的處理者繼續處理數據,則返回false,否則返回true;</returns>
public virtual bool OnDeal(CommData cd)
{
return true;
}

//附加的自身初始化操作
public virtual bool Init()
{
return true;
}
//提前初始化接口
public virtual bool BeforeInit()
{
return true;
}
//初始化後處理接口
public virtual bool AfterInit()
{
return true;
}
//刪除前處理接口
public virtual bool BeforeExit()
{
return true;
}
//下一個觀察者
IObserver next = null;
public IObserver Next
{
get
{
return next;
}
set
{
next = value;
}
}
//上一個觀察者
IObserver prev = null;
public IObserver Prev
{
get
{
return prev;
}
set
{
prev = value;
}
}
//添加觀察者
public void Add(IObserver observer)
{
if (this == observer) return;//已經存在
if (next == null)
{
next = observer;//達到最底端
next.Prev = this;
}
else next.Add(observer);//加到後面
}
/// <summary>
/// 插入觀察者到下一個觀察者的前面
/// </summary>
/// <param name="observer"></param>
public void Insert(IObserver observer)
{
//是否等於自己
if (this == observer) return;
//先查找是否已經存在鏈表中
if (Next != null && Next.IsExist(observer)) Next.Remove(observer);
//
observer.Next = Next;
if (Next != null) Next.Prev = observer;
Next = observer;
observer.Prev = this;
}
/// <summary>
/// 刪除觀察者
/// </summary>
/// <param name="observer"></param>
public void Remove(IObserver observer)
{
if (observer == this)
{
if (Prev != null) Prev.Next = Next;
if (Next != null) Next.Prev = Prev;
}
else
{
if (Next != null) Next.Remove(observer);
}
}
/// <summary>
/// 查找是否存在
/// </summary>
/// <param name="observer"></param>
/// <returns></returns>
public bool IsExist(IObserver observer)
{
if (observer == this) return true;
if (Next == null) return false;
else return Next.IsExist(observer);
}
}

/// <summary>
/// 日誌處理基類,本身從通訊數據處理類的基類派生。
/// </summary>
class Log : Observer
{
public Log()
{
}
public Log(string slogfile)
{
LogFile = slogfile;
}
~Log()
{
}
// 日誌文件帶路徑名稱
private string logFile;
public string LogFile
{
get
{
return logFile;
}
set
{
logFile = value;
}
}
}

}
using System;
using System.Collections;
using System.IO;
using System.Threading;

namespace Jh.Sockets
{
/// <summary>
/// 數據集中管理類
/// </summary>
public class CommDataMgr
{
static int index = 0;
int id;
/// <summary>
/// 無參數構造方法
/// </summary>
public CommDataMgr()
{
id = index ++;
dnFlag = new Parm(this);
Console.WriteLine("JH data distributor {0} constructed",id);
}
Thread t = null;
public void Start()
{
if (dnFlag.Status != JhThreadStatus.Running)
{
dnFlag.Status = JhThreadStatus.Running;
t = new Thread (new ThreadStart(DataNotiyfyThread));
t.Name = "JH data distributing " + id.ToString();
t.Start();
Console.WriteLine("JH data distributing thread of JH data distributor {0} started",id);
}
}
public void Stop()
{
if ( dnFlag.Status == JhThreadStatus.Running )
{
lock (this)
{
dnFlag.Status = JhThreadStatus.Stop;
}
}

}
/// <summary>
/// 析構方法
/// </summary>
~CommDataMgr()
{
Stop();
Console.WriteLine("JH data distributor {0} unconstructed",id);
}
public void DataNotiyfyThread()
{
try
{
while (dnFlag.Status == JhThreadStatus.Running)
{
DealData();
Thread.Sleep(100);
// Console.WriteLine("分發線程{0}工作中",id);
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
finally
{
lock(this)
{
dnFlag.Status = JhThreadStatus.Exit;
}
Console.WriteLine("JH data distributing thread of JH data distributor {0} exited",id);
}
}
Parm dnFlag = null;
ArrayList aData = new ArrayList();
InnerObserver root = new InnerObserver();
/// <summary>
/// 觀察者根節點類 定義
/// </summary>
internal class InnerObserver : Observer
{
}
public void DealData()
{
if (DataCount > 0)
{
lock(this)
{
if (root.Next != null)
{
root.Next.Deal((CommData)aData[0]);
}
RemoveAt(0);
}
}
}
/// <summary>
/// 未處理數據個數
/// </summary>
public int DataCount
{
get
{
return aData.Count;
}
}
/// <summary>
/// 根據索引返回未處理數據
/// </summary>
internal CommData this[int Index]
{
get
{
return (CommData)aData[Index];
}
}
/// <summary>
/// 根據索引刪除數據
/// </summary>
/// <param name="Index">索引</param>
public void RemoveAt(int Index)
{
if (Index >= 0 && Index < DataCount)
{
lock (this)
{
aData.RemoveAt(Index);
}
}
}
/// <summary>
/// 接收到新的數據提交
/// </summary>
/// <param name="client">客戶端連接</param>
/// <param name="s">數據流</param>
public void AddData(JhClient client,MemoryStream s,int len)
{
CommData cd = new CommData(client,s,len,this);
lock(this)
{
aData.Add(cd);
}
}
/// <summary>
/// 添加觀察者
/// </summary>
/// <param name="observer"></param>
public void Add(IObserver observer)
{
lock (this)
{
root.Add(observer);
}
}
/// <summary>
/// 刪除觀察者
/// </summary>
/// <param name="observer"></param>
public void Remove(IObserver observer)
{
lock (this)
{
root.Remove(observer);
}
}
/// <summary>
/// 在最前面插入觀察者
/// </summary>
/// <param name="observer"></param>
public void Insert(IObserver observer)
{
lock (this)
{
root.Insert(observer);
}
}
// 取觀察者個數
// int GetObserverCount()
// {
// return (int)m_aObservers.GetCount();
// }

}


}
using System;
using System.Threading;
using System.Net.Sockets;
using System.IO;
using System.Collections;
using System.Windows.Forms;
using System.Net;

namespace Jh.Sockets
{
/// <summary>
/// 內部通信消息
/// </summary>
enum JhCommMessages
{
MessageStart = 9909,//消息起始
DataTransfer, //數據傳輸
Disconnected, //連接將要斷開
ConnectSignal, //連接檢查信號
ConnectCheck, //啟動連接信號
StopCheck, //停止連接信號
Unknown = 9999 //未知
}
/// <summary>
/// 通信數據
/// </summary>
public class CommData
{
public CommData(JhClient client,MemoryStream stream,int len,CommDataMgr dm)
{
jhClient = client;
Data = new MemoryStream();
stream.WriteTo(Data);
dataLen = len;
adm = dm;
}
JhClient jhClient;
MemoryStream data;
int dataLen;
CommDataMgr adm;
/// <summary>
/// tcp連接
/// </summary>
public JhClient Socket
{
get
{
return jhClient;
}
}
/// <summary>
/// 內存數據流
/// </summary>
public MemoryStream Data
{
get
{
return data;
}
set
{
data = value;
}
}
/// <summary>
/// 數據長度
/// </summary>
public int DataLen
{
get
{
return dataLen;
}
}
};


public delegate void CommEventHandler(object sender,CommEventArgs e);

public class CommEventArgs : EventArgs
{
public CommEventArgs(string msg):base()
{
Message = msg;
}
string message;
public string Message
{
get
{
return message;
}
set
{
message = value;
}
}
}
/// <summary>
/// Tcp通信客戶類
/// </summary>
public class JhClient
{
/// <summary>
/// 連接成功事件
/// </summary>
public event CommEventHandler OnConnected;
/// <summary>
/// 連接關閉事件
/// </summary>
public event CommEventHandler OnClosed;
/// <summary>
/// 連接失敗事件
/// </summary>
public event CommEventHandler OnConnectFailed;
/// <summary>
/// 構造方法
/// </summary>
/// <param name="dm">外部植入的數據管理類</param>
/// <param name="ob">觀察者</param>
/// <param name="tcpClient">通信連接</param>
public JhClient(CommDataMgr dm,IObserver ob,TcpClient tcpClient)
{
//
// TODO: 在此處添加構造函數邏輯
//
status = new Parm(this);
checkStatus = new Parm(this);
autoConnectStatus = new Parm(this);
if (dm == null)
{
adm = new CommDataMgr();
}
else adm = dm;
if (ob != null) adm.Add(ob);
if (tcpClient == null)
{
client = new TcpClient();
}
else client = tcpClient;
ID = index ++;
OnClosed += new CommEventHandler(OnConnectClosed);
Console.WriteLine("JH tcp client {0} constructed",ID);
}
static int index = 0;
/// <summary>
/// 無參數構造函數
/// </summary>
public JhClient(TcpClient tcpClient) : this(null,null,tcpClient)
{}

public JhClient(CommDataMgr dm,TcpClient tcpClient) : this(dm,null,tcpClient)
{}

public JhClient(IObserver ob,TcpClient tcpClient):this(null,ob,tcpClient)
{}

public JhClient() : this(null,null,null)
{}

public JhClient(CommDataMgr dm) : this(dm,null,null)
{}

public JhClient(IObserver ob):this(null,ob,null)
{}
/// <summary>
/// 析構方法
/// </summary>
~JhClient()
{
AutoConnect = false;
ConnectCheck = false;
Close();
Console.WriteLine("JH tcp client {0} unconstructed",ID);
}
Parm status = null;
/// <summary>
/// 唯一標誌符
/// </summary>
int id = -1;
public int ID
{
get
{
return id;
}
set
{
id = value;
}
}
/// <summary>
/// 連接狀態
/// </summary>
bool connected = false;
public bool Connected
{
get
{
return connected;
}
set
{
connected = value;
if (connected == true)
{
adm.Start();
if (status.Status != JhThreadStatus.Running)
{
status.Status = JhThreadStatus.Running;
readThread = new Thread(new ThreadStart(this.DataReadThread));
readThread.Name = "Data reader of JH tcp client " + ID.ToString();
readThread.Start();
Console.WriteLine("Data reader of JH tcp client {0} started",ID);
LastReceivedTime = DateTime.Now;
if (ConnectCheck == true)
{
SendMessage(JhCommMessages.ConnectCheck,(Int32)CheckTimeout.Ticks);
StartConnectCheckThread();
}
}
}
else
{
status.Status = JhThreadStatus.Stop;
if (OnClosed != null) OnClosed(this,new CommEventArgs("連接已經斷開!"));
}
}
}
/// <summary>
/// 嘗試連接次數
/// </summary>
int connectTimes = 0;
/// <summary>
/// 讀取數據線程
/// </summary>
Thread readThread = null;
/// <summary>
/// 自動斷線重連標誌
/// </summary>
bool autoConnect = false;
/// <summary>
/// 自動斷線重連標誌
/// </summary>
public bool AutoConnect
{
get
{
return autoConnect;
}
set
{
autoConnect = value;
if (autoConnect != true)
{
lock(this)
{
autoConnectStatus.Status = JhThreadStatus.Stop;
}
}
}
}

/// <summary>
/// 自動連接間隔毫秒數
/// </summary>
int autoConnectInterval = 3000;
/// <summary>
/// 自動連接間隔毫秒數
/// </summary>
public int AutoConnectInterval
{
get
{
return autoConnectInterval;
}
set
{
autoConnectInterval = value;
}
}
/// <summary>
/// 連接檢測的狀態控制
/// </summary>
Parm checkStatus = null;
/// <summary>
/// 自動連接的狀態控制
/// </summary>
Parm autoConnectStatus = null;
/// <summary>
/// 連接監測標誌
/// </summary>
bool connectCheck = false;
/// <summary>
/// 連接監測標誌
/// </summary>
public bool ConnectCheck
{
get
{
return connectCheck;
}
set
{
bool b = value;
if (connectCheck != b)
{
if (connectCheck != true)//啟動檢測
{
lock(this)
{
checkStatus.Status = JhThreadStatus.Stop;
}
if (Connected == true)
{
SendMessage(JhCommMessages.StopCheck);
}
}
else
{
if (Connected == true) StartConnectCheckThread();
}
}
}
}
/// <summary>
/// 啟動連接檢測線程
/// </summary>
void StartConnectCheckThread()
{
if (checkStatus.Status != JhThreadStatus.Running)
{
checkStatus.Status = JhThreadStatus.Running;
Thread t = new Thread(new ThreadStart(ConnectCheckThread));
t.Name = "JH tcp client connecting checker of JH tcp client " + this.ID.ToString();
t.Start();
Console.WriteLine(t.Name + " started.");
}
}
/// <summary>
/// 連接關閉事件響應
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public virtual void OnConnectClosed(object sender,CommEventArgs e)
{
if (AutoConnect == true)//是否自動重連
{
StartAutoConnectThread();
}
}
/// <summary>
/// 啟動自動重連線程
/// </summary>
void StartAutoConnectThread()
{
if (autoConnectStatus.Status != JhThreadStatus.Running)
{
connectTimes = 0;
autoConnectStatus.Status = JhThreadStatus.Running;
Thread t = new Thread(new ThreadStart(AutoConnectThread));
t.Name = "JH tcp client auto-connector of JH tcp client " + this.ID.ToString();
t.Start();
Console.WriteLine(t.Name + " started.");
}
}
/// <summary>
/// 最近一次通訊時間
/// </summary>
DateTime lastReceivedTime = DateTime.Now;
/// <summary>
/// 最近一次通訊時間
/// </summary>
public DateTime LastReceivedTime
{
get
{
return lastReceivedTime;
}
set
{
lastReceivedTime = value;
}
}

/// <summary>
/// 連接檢測斷開判斷的最大允許毫秒數
/// </summary>
TimeSpan checkTimeout = new TimeSpan(1800000000);//3 minutes
/// <summary>
/// 連接檢測斷開判斷的最大允許毫秒數
/// </summary>
public TimeSpan CheckTimeout
{
get
{
return checkTimeout;
}
set
{
TimeSpan ts = value;
if (ts.Minutes > 2) checkTimeout = ts;//檢查時間間隔不小於2分鐘
}
}
/// <summary>
/// 自動連接線程
/// </summary>
void AutoConnectThread()
{
try
{
while (autoConnectStatus.Status == JhThreadStatus.Running && AutoConnect == true)
{
if (Connected != true)
{
DoConnect();
Thread.Sleep(AutoConnectInterval);
}
else
{
break;
}
}
}
catch (Exception e3)
{
MessageBox.Show(e3.Message);
}
finally
{
lock (this)
{
autoConnectStatus.Status = JhThreadStatus.Exit;
}
}
}
/// <summary>
/// 連接檢測線程
/// </summary>
void ConnectCheckThread()
{
try
{
while (checkStatus.Status == JhThreadStatus.Running)
{
if (Connected == true)
{
TimeSpan ts = DateTime.Now - lastReceivedTime;
TimeSpan ts2 = CheckTimeout + CheckTimeout;
if (ts > ts2 )//超過兩倍間隔時間,認為已經斷開
{
Close();
break;
}
else
{
SendMessage(JhCommMessages.ConnectSignal,(Int32)CheckTimeout.Ticks);
}
}
else
{
LastReceivedTime = DateTime.Now;
break;
}
Thread.Sleep(checkTimeout);
}
}
catch (Exception e3)
{
MessageBox.Show(e3.Message);
}
finally
{
lock(this)
{
checkStatus.Status = JhThreadStatus.Exit;
}
Console.WriteLine("JH tcp client connecting checker of JH tcp client " + this.ID.ToString() + " exited.") ;
}
}
/// <summary>
/// 讀取數據的線程
/// </summary>
void DataReadThread()
{
try
{
while (status.Status == JhThreadStatus.Running)
{
if (Connected == true)
{
NetworkStream ns = Client.GetStream();
int readCount,totalRead = 0;
while (ns.DataAvailable == true)//讀取數據,轉存到s中,因為NetworkStream的數據只能向前讀取一次
{
readCount = ns.Read(buffer, 0, bufferSize);
if (readCount > 0)
{
buf.Write(buffer, 0, readCount);
totalRead += readCount;
}
else
{
break;
}
} ;
if (totalRead > 0)//有數據
{
DealData();//處理
}
}
Thread.Sleep(50);
}
}
catch(IOException e3)
{
MessageBox.Show(e3.Message);
}
catch (ObjectDisposedException e2)
{
MessageBox.Show(e2.Message);
}
catch (InvalidOperationException e1)
{
MessageBox.Show(e1.Message);
}
catch (Exception e3)
{
MessageBox.Show(e3.Message);
}
finally
{
lock(this)
{
status.Status = JhThreadStatus.Exit;
}
Console.WriteLine("Data reader thread of JH tcp client {0} exited.",ID);
}
}
/// <summary>
/// 服務器ip
/// </summary>
string ipString;
/// <summary>
/// 服務器端口
/// </summary>
int tcpPort;
/// <summary>
/// 根據當前設置的ip和 port參數進行連接
/// </summary>
void DoConnect()
{
try
{
if (Connected == false)
{
if (Client == null)
{
Client = new TcpClient();
}
++ connectTimes ;
Client.Connect(ipString,tcpPort);
Connected = true;
autoConnectStatus.Status = JhThreadStatus.Stop;
if (OnConnected != null) OnConnected(this,new CommEventArgs("已經與服務器建立連接!"));
}
}
catch(Exception le)
{
if (OnConnectFailed != null) OnConnectFailed(this,new CommEventArgs("第" + connectTimes.ToString() + "次與服務器建立連接失敗!" + le.Message));
}
}
/// <summary>
/// 連接服務器
/// </summary>
/// <param name="ip"></param>
/// <param name="port"></param>
public void Connect(string ip,int port)
{
ipString = ip;
tcpPort = port;
if (this.AutoConnect == true)
{
StartAutoConnectThread();
}
else
{
DoConnect();
}
}
/// <summary>
/// 發送數據
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public void Send(string data)
{
Send( data, System.Text.Encoding.Default);
}
/// <summary>
/// 發送數據
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public void Send(string data, System.Text.Encoding encodingway)
{
byte[] dt = encodingway.GetBytes(data);
Send(dt);
}
/// <summary>
/// 發送數據
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public void Send(byte[] data)
{
if (Connected == true)
{
CommHead ch = new CommHead();
ch.WParam = (short)JhCommMessages.DataTransfer;
ch.Add(data);
client.GetStream().Write(ch.ToBytes(),0,ch.Length);
}
else
{
MessageBox.Show("尚未建立連接或者連接已經斷開!");
}
}

/// <summary>
/// 關閉連接
/// </summary>
public void Close()
{
if (Connected == true)
{
SendMessage(JhCommMessages.Disconnected);
Connected = false;
adm.Stop();
Client.Close();
Client = null;
}
}
/// <summary>
/// 程序退出時調用,或者設置AutoConnect = false
/// </summary>
public void Exit()
{
AutoConnect = false;
ConnectCheck = false;
Close();
}
/// <summary>
/// TCP客戶對像
/// </summary>
TcpClient client = null;
/// <summary>
/// TCP客戶對像
/// </summary>
public TcpClient Client
{
get
{
return client;
}
set
{
client = value;
}
}
/// <summary>
/// 緩存未處理的數據
/// </summary>
MemoryStream buf = new MemoryStream();
/// <summary>
/// 讀取接收到的數據的緩衝區的大小
/// </summary>
const int bufferSize = 1024;
/// <summary>
/// 讀取接收到的數據的緩衝區
/// </summary>
byte[] buffer = new byte[bufferSize];
/// <summary>
/// 數據分發管理者
/// </summary>
CommDataMgr adm ;
/// <summary>
/// 數據分發管理者
/// </summary>
public CommDataMgr DataMgr
{
set
{
adm = value;
}
}
/// <summary>
/// 接收到的數據的處理
/// </summary>
private void DealData()
{
// if (buf.Length > 0) //有數據需要處理
{
CommHead chio = new CommHead(buf,(int)buf.Position);
if (chio.IsValid())
{
LastReceivedTime = DateTime.Now;
if (chio.DataLen > 0)//有效數據
{
adm.AddData(this,chio.GetData(),chio.DataLen);//可處理數據
}
else//純內部消息
{
switch ((JhCommMessages)chio.WParam)
{
case JhCommMessages.Disconnected: //對方將要斷開連接消息
Close();
break;
case JhCommMessages.ConnectCheck:
if (CheckTimeout.Ticks != chio.DWParam)
{
CheckTimeout = new TimeSpan(chio.DWParam);
}
ConnectCheck = true;
break;
case JhCommMessages.StopCheck:
ConnectCheck = false;
break;
case JhCommMessages.ConnectSignal:
if (CheckTimeout.Ticks != chio.DWParam)
{
CheckTimeout = new TimeSpan(chio.DWParam);
}
break;
default:
break;
}
}
buf.Position = 0;
chio.GetLeftData(ref buf);//剩下未處理完數據
}
}
}
/// <summary>
/// 不帶參數的消息
/// </summary>
/// <param name="message"></param>
private void SendMessage(JhCommMessages message)
{
SendMessage(message,0);
}
/// <summary>
/// 帶參數的消息
/// </summary>
/// <param name="message"></param>
private void SendMessage(JhCommMessages message,Int32 parm)
{
CommHead ch = new CommHead();
ch.WParam = (short)message;
ch.DWParam = parm;
Client.GetStream().Write(ch.ToBytes(),0,16);
}
}
/// <summary>
/// Tcp通信服務器類
/// </summary>
public class JhTcpServer
{
public JhTcpServer(int port)
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");//Dns.Resolve("localhost").AddressList[0];
server = new TcpListener(ipAddress,port);
adm = new CommDataMgr();
status = new Parm(this);
}

~JhTcpServer()
{
Stop();
}

/// <summary>
/// Tcp監聽對像
/// </summary>
TcpListener server = null;

/// <summary>
/// 客戶端序號
/// </summary>
int clientindex = 0;

/// <summary>
/// 開始監聽
/// </summary>
public void Start()
{
clients.Clear();
clientindex = 99999999;
adm.Start();
server.Start();
status.Status = JhThreadStatus.Running;
listenThread = new Thread(new ThreadStart(this.ListenThread));
listenThread.Name = "JH tcp listenor";
listenThread.Start();
Console.WriteLine("JH tcp listenor started.");
}

/// <summary>
/// 監聽線程
/// </summary>
Thread listenThread = null;

/// <summary>
/// 停止接受連接
/// </summary>
public void Stop()
{
int i;
for (i = 0; i < this.clients.Count; ++i)
{
StopClient(i);
}
adm.Stop();
if (status.Status == JhThreadStatus.Running)
{
lock(this)
{
status.Status = JhThreadStatus.Stop;
}
while (status.Status != JhThreadStatus.Exit)
{
Thread.Sleep(100);
}
}
server.Stop();
}

/// <summary>
/// 斷開指定索引的客戶
/// </summary>
/// <param name="index">客戶端索引</param>
public void StopClient(int index)
{
GetClient(index).Exit();
}

/// <summary>
/// 發送數據
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public void Send(JhClient client,string data)
{
if (client != null)
{
byte[] dt = System.Text.Encoding.Default.GetBytes(data);
client.Send(dt);
}
}

/// <summary>
/// 用最後一個客戶端發送數據
/// </summary>
/// <param name="data"></param>
public void Send(string data)
{
Send(GetClient(clients.Count - 1),data);
}

/// <summary>
/// 數據分發管理者
/// </summary>
CommDataMgr adm ;

Parm status = null;

/// <summary>
/// 客戶連接線程
/// </summary>
void ListenThread()
{
try
{
while (status.Status == JhThreadStatus.Running)
{
if (server.Pending() == true)
{
TcpClient client = server.AcceptTcpClient();//偵聽到連接後創建客戶端
JhClient jhClient = new JhClient(adm,client);
jhClient.ID = clientindex--;
SetClient(jhClient);
jhClient.Connected = true;
}
Thread.Sleep(100);
}
}
catch (ObjectDisposedException e2)
{
MessageBox.Show(e2.Message);
}
catch (InvalidOperationException e1)
{
MessageBox.Show(e1.Message);
}
catch (Exception e3)
{
MessageBox.Show(e3.Message);
}
finally
{
lock(this)
{
status.Status = JhThreadStatus.Exit;
}
Console.WriteLine("JH tcp listenor exited");
}
}

/// <summary>
/// 添加觀察者
/// </summary>
/// <param name="ob"></param>
public void AddOb(IObserver ob)
{
adm.Add(ob);
}

Hashtable clients = new Hashtable();
/// <summary>
/// 根據內部id獲取客戶端
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public JhClient GetClient(int id)
{
return (JhClient)clients[id];
}

/// <summary>
/// 設置客戶端對像
/// </summary>
/// <param name="client"></param>
public void SetClient(JhClient client)
{
int i;
for (i = 0 ; i < clients.Count; ++i)
{
if (((JhClient)clients[i]).ID == client.ID)
{
break;
}
}
clients[i] = client;
}
}

/// <summary>
/// 通信頭處理類
/// </summary>
class CommHead
{
Int16 wHeadSize;// 頭結構長度
Int16 wFlag;//合法數據包特徵字
Int16 wVer;// 用版本號表示標識符
Int16 wParm;// 參數一
Int32 dwParm;// 參數二
Int32 dwDataLen;// 後續數據長度

/// <summary>
/// 新建頭構造方法
/// </summary>
public CommHead() : this(System.Text.Encoding.Default)
{
Init();
}

/// <summary>
/// 新建頭構造方法
/// </summary>
public CommHead(System.Text.Encoding enCoding)
{
encoding = enCoding;
Init();
}

System.Text.Encoding encoding;
/// <summary>
/// 解析數據構造方法
/// </summary>
/// <param name="s">數據流</param>
public CommHead(MemoryStream s,int len) : this(s,len,System.Text.Encoding.Default)
{
}

/// <summary>
/// 解析數據構造方法
/// </summary>
/// <param name="s">數據流</param>
/// <param name="encoding">字符編碼方案</param>
public CommHead(MemoryStream s,int len,System.Text.Encoding encoding)
{
Init();
if (s != null)
{
s.Position = 0;
BinaryReader r = new BinaryReader(s,encoding);
wHeadSize = r.ReadInt16();
if (len >= wHeadSize)
{
wFlag = r.ReadInt16();
if (IsValid())
{
wVer = r.ReadInt16();
wParm = r.ReadInt16();
dwParm = r.ReadInt32();
dwDataLen = r.ReadInt32();
if (dwDataLen > 0)
{
byte[] dt = r.ReadBytes(dwDataLen);
if (dt != null) recvData = new MemoryStream(dt);
else
{
recvData = null;
dwDataLen = 0;
}
}
if (len > wHeadSize + dwDataLen)
{
byte[] dt = r.ReadBytes(len - wHeadSize - dwDataLen);
if (dt != null) moreData = new MemoryStream(dt);
else moreData = null;
}
}
}
}

}

MemoryStream recvData;

MemoryStream moreData;

void Init() {wFlag = 0x4a48; wVer = 1; wHeadSize = 16; }

// 當前頭數據是否有效
public bool IsValid() {return wFlag == 0x4a48 && wHeadSize == 16; }

// 返回雙字節參數
public Int32 DWParam
{
get
{
return dwParm;
}
set
{
dwParm = value;
}
}

// 返回單字節參數
public Int16 WParam
{
get
{
return wParm;
}
set
{
wParm = value;
}
}

// 返回頭結構大小
public Int16 HeadSize
{
get
{
return wHeadSize;
}
}

// 返回版本標識符
public virtual Int16 Ver
{
get
{
return wVer;
}
}

// 返回後續數據長度
public virtual Int32 DataLen
{
get
{
return dwDataLen;
}
set
{
dwDataLen = value;
}
}

/// <summary>
/// 返回未處理數據
/// </summary>
/// <returns></returns>
public void GetLeftData(ref MemoryStream s)
{
if (moreData != null)
{
moreData.WriteTo(s);
moreData.Close();
}
}

/// <summary>
/// 返回完整數據
/// </summary>
/// <returns></returns>
public MemoryStream GetData()
{
return recvData;
}

/// <summary>
/// 添加數據
/// </summary>
/// <param name="pszData"></param>
public void Add(byte[] pszData)
{
data.Write(pszData,0,pszData.Length);
dwDataLen += pszData.Length;
}

MemoryStream data = new MemoryStream();

/// <summary>
/// 需要發送的數據轉為字節數組
/// </summary>
/// <returns></returns>
public byte[] ToBytes()
{
MemoryStream s = new MemoryStream();
BinaryWriter w = new BinaryWriter(s,encoding);
w.Write(wHeadSize);
w.Write(wFlag);
w.Write(wVer);
w.Write(wParm);
w.Write(dwParm);
w.Write(dwDataLen);
// w.Close();
data.WriteTo(s);
return s.ToArray();
}

/// <summary>
/// 需要發送的數據的長度
/// </summary>
public int Length
{
get
{
return (int)data.Length + wHeadSize;
}
}
}


}

namespace Jh.Sockets
{
/// <summary>
/// 字符串特性常量存放類
/// </summary>
public class JhStringConst
{
public const int SHORT_STRING_LEN = 16;
public const int NORMAL_STRING_LEN = 32;
public const int MIDD_STRING_LEN = 64;
public const int LONG_STRING_LEN = 128;
public const int LONGER_STRING_LEN = 256;
public const int EXLONG_STRING_LEN = 1024;
}
}



webasp.net