2008-08-25
FC 1.0 開發記錄
速度也調上來了,一開始速度被拖下來是程式上的缺失,C#的速度跟VB6差不多。
優點是真正的多執行緒,因此很容易的將掃描報告傳回來。
VB要做的話一定要寫成兩隻exe,不然只要開始測試就會看到程式死在那邊。
因為VB沒有真正的多執行緒,我記得之前寫的時候第二個執行緒的程式連物件都不能用。
要傳掃描報告回主控端的話有三個方法。
1. 記憶體共用。 -- 這個真的超複雜的
2. 事件中夾帶參數傳遞。 -- 程式不好寫
3. 寫到硬碟。 -- 這個速度會慢一點點 重點是感覺好鳥 = =|||
C#的話輕鬆過關,叫第二個執行緒出來就好。
2008-08-18
使用Socket完成FTP檔案存取
這隻程式用了Barakbbn.Freeware.Net.Sockets。
使用時總共要加入兩個.cs檔(Barakbbn.Freeware.Net.Sockets、Kelp.Opensource.FTPClient)。
相關說明有打在註解上,如果還是不清楚的話可以留言發問。
Barakbbn.Freeware.Net.Sockets相關文章
Kelp.Opensource.FTPClient | 複製程式碼(Copy to clipboard) |
using System;
using System.Net;
using System.IO;
using System.Text;
using Barakbbn.Freeware.Net.Sockets;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// 本程式需要使用額外的socket Barakbbn.Freeware.Net.Sockets
//
// 在程式碼上方加入 using Kelp.Opensource.FTPClient;
//
//
// P.S.下達ftp.Gep()後不會等抓完檔案才執行ftp.DisConnect()
// 檔案上傳及下載是透過事件觸發的
// "//檔案下載完成"搜尋此字串可以找到下載完成程式位置 事件為GetFileComplete
// "//檔案上傳完成"搜尋此字串可以找到上傳完成程式位置 事件為PutFileComplete
//
//
// FTPClient ftp = new FTPClient(); //宣告
//
// void Connect() //連線
// void DisConnect() //關閉連線
// void SetTransferType(TransferType ttType) //設定傳輸模式
// TransferType GetTransferType() //取得傳輸模式
// string[] Dir(string strMask) //取得文件列表 (文件名稱~可用*)
// void Delete(string strFileName) //刪除
// void Rename(string strOldFileName, string strNewFileName) //Rename(如果要改的名稱已存在將會覆蓋)
// void Get(string strRemoteFileName, string strLocalFileName) //下載文件
// void Put(string strFileName) //上傳文件
// void MkDir(string strDirName) //建立目錄
// void RmDir(string strDirName) //刪除目錄
// void ChDir(string strDirName) //改變目錄
//
// 來源:打奈特(.net)
// 修改:Kelp
//
// 修改記錄
// 2008/08/16
// 因為要使用.net framework2.0來完成FTP傳輸因此到處尋找利用socket進行FTP的程式碼
//
// 2008/08/18
// 原程式因為不斷掃描socket的緩衝區造成錯誤
// 將System.Net.Socket換成Barakbbn.Freeware.Net.Sockets
//
// 2008/08/19
// 修正不穩定因素
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/* 下載範例程式
string[] sdata;
FTPClient ftp = new FTPClient(); 宣告
ftp.GetFileComplete += new EventHandler<LocalGFileAddressData>(ftp_GetFileComplete);
ftp.RemoteHost = "www.test.com"; 設定HOST
ftp.RemoteUser = "XXXXX"; 設定使用者帳號
ftp.RemotePass = "XXXXX"; 設定密碼
ftp.Connect(); 連線
ftp.ChDir("/www/"); 切換目錄
sdata = ftp.Dir(""); 取得目前位置內的資料夾及檔案名稱
ftp.Get("1.jpg", "D:\\1.jpg"); 下載1.jpg另存為F:\\1.jpg
ftp.DisConnect(); 結束連線
private void ftp_GetFileComplete(object sender, LocalGFileAddressData e)
{
MessageBox.Show("Finish " + e.LocalFileAddress);
}
*/
/* 上傳範例程式
string[] sdata;
FTPClient ftp = new FTPClient();
ftp.PutFileComplete += new EventHandler<LocalPFileAddressData>(ftp_PutFileComplete);
ftp.RemoteHost = "www.test.com"; 設定HOST
ftp.RemoteUser = "XXXXX"; 設定使用者帳號
ftp.RemotePass = "XXXXX"; 設定密碼
ftp.Connect(); 連線
ftp.Put("F:\\2.jpg"); 上傳檔案
private void ftp_PutFileComplete(object sender, LocalPFileAddressData e)
{
MessageBox.Show("Finish " + e.LocalFileAddress);
}
*/
namespace Kelp.Opensource.FTPClient
{
public class FTPClient
{
//////////////////////////記憶體宣告/////////////////////////////////////////////////////////////////////////////
#region Field
private bool Received = false; //當基礎連接socket回應結束後為true
private bool DataReceived = false; //當資料連接socket回應結束後為true
private string strMsg; //伺服器回應的訊息
private string strReply; //伺服器回應的答應碼
private int iReplyCode; //伺服器回應的答應碼
private TcpClient socketControl; //socket物件
private TransferType trType; //傳輸模式
byte[] buffer = new byte[0];
Encoding ASCII = Encoding.GetEncoding("big5"); //編碼方式
public enum TransferType { Binary, ASCII }; //傳輸模式
bool Downloading = false;
bool Uploading = false;
string SOutputAddress = ""; //檔案下載路徑
FileStream output; //檔案下載串流
string SInputAddress = ""; //檔案上傳路徑
FileStream input; //檔案上傳串流
int iBytes = 0; //檔案上傳指標
TcpClient socketGetData;
TcpClient socketSendData;
#endregion
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////Client/////////////////////////////////////////////////////////////////////////////////
#region FTPClient
public FTPClient()
{
strRemoteHost = "";
strRemotePath = "";
strRemoteUser = "";
strRemotePass = "";
strRemotePort = 21;
bConnected = false;
}
public FTPClient(string remoteHost, string remotePath, string remoteUser, string remotePass, int remotePort)
{
strRemoteHost = remoteHost;
strRemotePath = remotePath;
strRemoteUser = remoteUser;
strRemotePass = remotePass;
strRemotePort = remotePort;
Connect();
}
#endregion
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////屬性更改對應程式///////////////////////////////////////////////////////////////////////
#region Loging Property
private string strRemoteHost;
public string RemoteHost
{
get
{
return strRemoteHost;
}
set
{
strRemoteHost = value;
}
}
private int strRemotePort;
public int RemotePort
{
get
{
return strRemotePort;
}
set
{
strRemotePort = value;
}
}
private string strRemotePath;
public string RemotePath
{
get
{
return strRemotePath;
}
set
{
strRemotePath = value;
}
}
private string strRemoteUser;
public string RemoteUser
{
set
{
strRemoteUser = value;
}
}
private string strRemotePass;
public string RemotePass
{
set
{
strRemotePass = value;
}
}
private Boolean bConnected;
public bool Connected
{
get
{
return bConnected;
}
}
#endregion
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////事件///////////////////////////////////////////////////////////////////////////////////
public virtual event EventHandler<LocalGFileAddressData> GetFileComplete;
public virtual event EventHandler<LocalPFileAddressData> PutFileComplete;
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////Class函數//////////////////////////////////////////////////////////////////////////////
public void Connect() //連線
{
socketControl = new TcpClient();
socketControl.Key = "Bace"; //設定Key為基礎連接socket
WireTcpClient(socketControl); //設定socket對應事件
try
{
Received = false;
socketControl.Connect(RemoteHost, Convert.ToInt32(strRemotePort));
}
catch (Exception)
{
throw new IOException("Couldn't connect to remote server");
}
// 取得回應
while (!Received) ;
if (iReplyCode != 220)
{
DisConnect();
throw new IOException(strReply.Substring(4));
}
// 登入
SendCommand("USER " + strRemoteUser);
if (!(iReplyCode == 331 || iReplyCode == 230))
{
CloseSocketConnect();//如果有錯誤就關閉連線
throw new IOException(strReply.Substring(4));
}
if (iReplyCode != 230)
{
SendCommand("PASS " + strRemotePass);
if (!(iReplyCode == 230 || iReplyCode == 202))
{
CloseSocketConnect();
throw new IOException(strReply.Substring(4));
}
}
bConnected = true;
// 切換到所選的目錄
ChDir(strRemotePath);
}
public void DisConnect() //關閉連線
{
if (socketControl != null)
{
SendCommand("QUIT");
}
if (socketSendData != null)
socketSendData.Close();
if (socketSendData != null)
socketSendData.Close();
CloseSocketConnect();
}
public void SetTransferType(TransferType ttType) //設定傳輸模式
{
if (ttType == TransferType.Binary)
{
SendCommand("TYPE I");//binary
}
else
{
SendCommand("TYPE A");//ASCII
}
if (iReplyCode != 200)
{
throw new IOException(strReply.Substring(4));
}
else
{
trType = ttType;
}
}
public TransferType GetTransferType() //取得傳輸模式
{
return trType;
}
public string[] Dir(string strMask) //取得文件列表 (文件名稱~可用*)
{
if (!bConnected) // 先確定是否已連線
Connect();
DataReceived = false;
TcpClient socketData = CreateDataSocket(); //建立並行數據連接的socket
socketData.Key = "Data";
SendCommand("NLST " + strMask); //傳送指令
//分析回應碼
if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226))
{
throw new IOException(strReply.Substring(4));
}
//取得結果
while (!DataReceived) ; //等待傳輸結束
while (true)
{
int iBytes = socketData.Receive(buffer, 0, buffer.Length);
if (iBytes < 0)
break;
strMsg += ASCII.GetString(buffer, 0, iBytes);
}
char[] seperator = { '\n' };
string[] strsFileList = strMsg.Split(seperator);
for (int ILoop = 0; ILoop < strsFileList.GetUpperBound(0); ILoop++)
{
strsFileList[ILoop] = strsFileList[ILoop].TrimEnd();
}
socketData.Close();
return strsFileList;
}
public void Delete(string strFileName) //刪除
{
if (!bConnected)
Connect();
SendCommand("DELE " + strFileName);
if (iReplyCode != 250)
{
throw new IOException(strReply.Substring(4));
}
}
public void Rename(string strOldFileName, string strNewFileName) //Rename(如果要改的名稱已存在將會覆蓋)
{
if (!bConnected)
{
Connect();
}
SendCommand("RNFR " + strOldFileName);
if (iReplyCode != 350)
{
throw new IOException(strReply.Substring(4));
}
SendCommand("RNTO " + strNewFileName);
if (iReplyCode != 250)
{
throw new IOException(strReply.Substring(4));
}
}
public void Get(string strRemoteFileName, string strLocalFileName) //下載文件
{
if (!bConnected)
Connect();
SetTransferType(TransferType.Binary);
if (strLocalFileName.Equals(""))
{
strLocalFileName = strRemoteFileName;
}
if (!File.Exists(strLocalFileName))
{
Stream st = File.Create(strLocalFileName);
st.Close();
}
SOutputAddress = strLocalFileName;
Downloading = true;
socketGetData = CreateDataSocket();
socketGetData.Key = "GetFile";
output = new FileStream(SOutputAddress, FileMode.Append);
SendCommand("RETR " + strRemoteFileName);
if (!(iReplyCode == 150 || iReplyCode == 125 || iReplyCode == 226 || iReplyCode == 250))
{
throw new IOException(strReply.Substring(4));
}
}
public void Put(string strFileName) //上傳文件
{
if (!bConnected)
Connect();
socketSendData = CreateDataSocket();
socketSendData.Key = "SendFile";
SendCommand("STOR " + Path.GetFileName(strFileName));
if (!(iReplyCode == 125 || iReplyCode == 150))
{
throw new IOException(strReply.Substring(4));
}
SInputAddress = strFileName;
Uploading = true;
input = new FileStream(strFileName, FileMode.Open);
iBytes = input.Read(buffer, 0, buffer.Length);
socketSendData.Send(buffer, 0, iBytes);
}
public void MkDir(string strDirName) //建立目錄
{
if (!bConnected)
{
Connect();
}
SendCommand("MKD " + strDirName);
if (iReplyCode != 257)
{
throw new IOException(strReply.Substring(4));
}
}
public void RmDir(string strDirName) //刪除目錄
{
if (!bConnected)
{
Connect();
}
SendCommand("RMD " + strDirName);
if (iReplyCode != 250)
{
throw new IOException(strReply.Substring(4));
}
}
public void ChDir(string strDirName) //改變目錄
{
if (strDirName.Equals(".") || strDirName.Equals(""))
{
return;
}
if (!bConnected)
{
Connect();
}
SendCommand("CWD " + strDirName);
if (iReplyCode != 250)
{
throw new IOException(strReply.Substring(4));
}
this.strRemotePath = strDirName;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////內部函數///////////////////////////////////////////////////////////////////////////////
private TcpClient CreateDataSocket() //建立並行數據連接的Socket
{
SendCommand("PASV");
if (iReplyCode != 227)
{
throw new IOException(strReply.Substring(4));
}
int index1 = strReply.IndexOf('(');
int index2 = strReply.IndexOf(')');
string ipData = strReply.Substring(index1 + 1, index2 - index1 - 1);
int[] parts = new int[6];
int len = ipData.Length;
int partCount = 0;
string buf = "";
for (int i = 0; i < len && partCount <= 6; i++)
{
char ch = Char.Parse(ipData.Substring(i, 1));
if (Char.IsDigit(ch))
buf += ch;
else if (ch != ',')
{
throw new IOException("Malformed PASV strReply: " + strReply);
}
if (ch == ',' || i + 1 == len)
{
try
{
parts[partCount++] = Int32.Parse(buf);
buf = "";
}
catch (Exception)
{
throw new IOException("Malformed PASV strReply: " + strReply);
}
}
}
string ipAddress = parts[0] + "." + parts[1] + "." + parts[2] + "." + parts[3];
int port = (parts[4] << 8) + parts[5];
TcpClient s = new TcpClient();
WireTcpClient(s);
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress), port);
try
{
s.Connect(ep);
}
catch (Exception)
{
throw new IOException("Can't connect to remote server");
}
return s;
}
private void CloseSocketConnect() //關閉Socket的連線(用在登入以前)
{
if (socketControl != null)
{
socketControl.Close();
socketControl = null;
}
bConnected = false;
}
private void SendCommand(String strCommand) //傳送命令並取得回應碼和最後一行的回應字串
{
Encoding e = Encoding.GetEncoding("big5");
Byte[] cmdBytes = e.GetBytes((strCommand + "\r\n").ToCharArray());
Received = false;
socketControl.Send(cmdBytes, 0, cmdBytes.Length);
if (strCommand != "QUIT")
while (!Received) ;
}
void WireTcpClient(TcpClient tcpClient) //建立Socket事件
{
tcpClient.Error += new EventHandler<SocketErrorEventArgs>(socket_Error);
tcpClient.SendCompleted += new EventHandler(socket_SendCompleted);
tcpClient.Disconnected += new EventHandler<SocketDisconnectedEventArgs>(socket_Disconnected);
tcpClient.DataAvailable += new EventHandler(socket_DataAvailable);
tcpClient.DataArrived += new EventHandler<SocketDataArrivedEventArgs>(socket_DataArrived);
tcpClient.Connected += new EventHandler(socket_Connected);
tcpClient.DataLost += new EventHandler<SocketDataArrivedEventArgs>(socket_DataLost);
tcpClient.SendProgressChanged += new EventHandler<SocketDataSendProgressChangedEventArgs>(socket_SendProgressChanged);
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////Socket事件/////////////////////////////////////////////////////////////////////////////
void socket_DataLost(object sender, SocketDataArrivedEventArgs e)
{
}
void socket_DataArrived(object sender, SocketDataArrivedEventArgs e)
{
TcpClient Socket = sender as TcpClient;
int iBytes;
switch (Socket.Key)
{
case "Bace":
try
{
buffer = (byte[])ReDim(buffer, e.ReceivedSize);
iBytes = socketControl.Receive(buffer, 0, buffer.Length);
strReply = ASCII.GetString(buffer, 0, iBytes);
iReplyCode = Int32.Parse(strReply.Substring(0, 3));
}
catch
{
break;
}
if (iReplyCode == 226)
{
if (Downloading)
{
//檔案下載完成
Downloading = false;
output.Close();
LocalGFileAddressData g = new LocalGFileAddressData(SOutputAddress);
GetFileComplete(socketGetData, g);
}
else if (Uploading)
{
//檔案上傳完成
Uploading = false;
input.Close();
LocalPFileAddressData h = new LocalPFileAddressData(SInputAddress);
PutFileComplete(socketSendData, h);
}
}
Received = true;
break;
case "Data":
DataReceived = true;
break;
case "GetFile":
while (true)
{
iBytes = Socket.Receive(buffer, 0, buffer.Length);
if (iBytes < 0)
{
break;
}
output.Write(buffer, 0, iBytes);
}
break;
}
}
void socket_Connected(object sender, EventArgs e)
{
}
void socket_DataAvailable(object sender, EventArgs e)
{
}
void socket_Disconnected(object sender, SocketDisconnectedEventArgs e)
{
TcpClient Socket = sender as TcpClient;
switch (Socket.Key)
{
case "GetFile":
if (Socket.IsConnected)
{
Received = false;
Socket.Close();
}
break;
}
}
void socket_SendCompleted(object sender, EventArgs e)
{
TcpClient Socket = sender as TcpClient;
switch (Socket.Key)
{
case "SendFile":
iBytes = input.Read(buffer, 0, buffer.Length);
if (iBytes > 0)
Socket.Send(buffer, 0, iBytes);
else
{
if (Socket.IsConnected)
{
Received = false;
Socket.Close();
}
}
break;
}
}
void socket_Error(object sender, SocketErrorEventArgs e)
{
}
void socket_SendProgressChanged(object sender, SocketDataSendProgressChangedEventArgs e)
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////通用副程式區域/////////////////////////////////////////////////////////////////////////
public static Array ReDim(Array origArray, Int32 desiredSize) //重新宣告記憶體
{
Type t = origArray.GetType().GetElementType();
Array newArray = Array.CreateInstance(t, desiredSize);
Array.Copy(origArray, 0, newArray, 0, Math.Min(origArray.Length, desiredSize));
return newArray;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}
public class LocalGFileAddressData : EventArgs
{
private string sLocalFileAddress;
public LocalGFileAddressData(string sLocalFileAddress)
{
this.sLocalFileAddress = sLocalFileAddress;
}
public string LocalFileAddress
{
get { return this.sLocalFileAddress; }
}
}
public class LocalPFileAddressData : EventArgs
{
private string sLocalFileAddress;
public LocalPFileAddressData(string sLocalFileAddress)
{
this.sLocalFileAddress = sLocalFileAddress;
}
public string LocalFileAddress
{
get { return this.sLocalFileAddress; }
}
}
}
Barakbbn.Freeware.Net.Sockets
他比System.Net.Sockets好的地方在於有提供事件。
範例程式載點
Barakbbn.Freeware.Net.Sockets | 複製程式碼(Copy to clipboard) |
using System;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Threading;
//////////////////////////使用方法///////////////////////////////////////////////////////////////////////////////
//
// 在程式碼上方加入 using Barakbbn.Freeware.Net.Sockets;
//
// private TcpClient socketControl; //宣告
// private TcpListener socketControl; //宣告
//
// 使用範例請參考TCP_Socket19438810272005.zip 這個是原始版本沒做修改
//
//
// 原作:Barakbbn
//
// 修改記錄
// 2008/08/18
// TcpClient及TcpListener底下新增 string Key
// 用來方便陣列化後的事件來源判別
//
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Barakbbn.Freeware.Net.Sockets
{
public class SocketErrorEventArgs : EventArgs
{
Exception ex;
public SocketErrorEventArgs(Exception ex)
{
this.ex = ex;
}
public bool IsSocketException
{
get { return (this.ex is SocketException); }
}
public Exception Error
{
get { return this.ex; }
}
}
public class SocketDisconnectedEventArgs : EventArgs
{
public enum DisconnectReason { LocalDisconnect, RemoteDisconnected, ConnectionLost }
DisconnectReason reason;
public SocketDisconnectedEventArgs(DisconnectReason reason)
{
this.reason = reason;
}
public DisconnectReason Reason
{
get { return this.reason; }
}
}
public class SocketDataArrivedEventArgs : EventArgs
{
private int recvSize;
private int lostSize;
public SocketDataArrivedEventArgs(int recvSize, int lostSize)
{
this.recvSize = recvSize;
this.lostSize = lostSize;
}
public int ReceivedSize
{
get { return this.recvSize; }
}
public int LostSize
{
get { return this.lostSize; }
}
}
public class SocketDataSendProgressChangedEventArgs : EventArgs
{
private int sentSize;
private int totalSize;
public SocketDataSendProgressChangedEventArgs(int sentSize, int totalSize)
{
this.sentSize = sentSize;
this.totalSize = totalSize;
}
public int SentSize
{
get { return this.sentSize; }
internal protected set { this.sentSize = value; }
}
public int TotalSize
{
get { return this.totalSize; }
internal protected set { this.totalSize = value; }
}
}
public class TcpClient : System.Net.Sockets.TcpClient
{
public string Key;
private delegate int BeginReceiveDelegate(ref byte[] buffer, int offset, int size, bool allSizeOrNothing);
private delegate void BeginDisconnectDelegate();
private delegate int SendWithProgressDelegate(byte[] buffer, int offset, int size, SocketFlags socketFlags);
public class SendProgressConstraints
{
private int minMillisecondsBetweenEvents;
private int chunkSize;
public SendProgressConstraints(int minMilliseconds, int chunkSize)
{
this.minMillisecondsBetweenEvents = minMilliseconds;
this.chunkSize = chunkSize;
}
public int MinMillisecondsBetweenEvents
{
get
{
lock (this)
{
return this.minMillisecondsBetweenEvents;
}
}
set
{
lock (this)
{
if (value < 0) throw new ArgumentOutOfRangeException("MinMillisecondsBetweenEvents", "Value can't be negative");
this.minMillisecondsBetweenEvents = value;
}
}
}
public int ChunkSize
{
get
{
lock (this)
{
return this.chunkSize;
}
}
set
{
lock (this)
{
if (value < 0) throw new ArgumentOutOfRangeException("ChunkSize", "Value can't be negative");
this.chunkSize = value;
}
}
}
}
#region Member Fields
protected const int recvBufferMinimumSize = 8 * 1024;
private bool disposed;
private Barakbbn.Freeware.Collections.CyclicQueue<Byte> recvBuffer;
private AutoResetEvent dataAvailableEvent;
private int recvTimeout;
private int dataAvailableMinimumCount;
private Exception socketAsyncRecvError;
private Thread socketPumpThread;
private UInt32 keepAliveInterval;
private DateTime userLastRecvTime;
private SendProgressConstraints sendProgressAttributes;
private TcpClientStream ownerStream;
#endregion
#region Events
public virtual event EventHandler DataAvailable;
public virtual event EventHandler<SocketDataArrivedEventArgs> DataArrived;
public virtual event EventHandler<SocketDataArrivedEventArgs> DataLost;
new public virtual event EventHandler Connected;
public virtual event EventHandler<SocketDisconnectedEventArgs> Disconnected;
public virtual event EventHandler<SocketDataSendProgressChangedEventArgs> SendProgressChanged;
public virtual event EventHandler SendCompleted;
public virtual event EventHandler<SocketErrorEventArgs> Error;
#endregion
#region Lifetime
public TcpClient()
: base()
{
InitInstance();
}
public TcpClient(AddressFamily family)
: base(family)
{
InitInstance();
}
public TcpClient(IPEndPoint localEP)
: base(localEP)
{
InitInstance();
}
public TcpClient(string hostname, int port)
: base(hostname, port)
{
InitInstance();
}
private void InitInstance()
{
this.recvBuffer = new Barakbbn.Freeware.Collections.CyclicQueue<Byte>(Math.Max(base.ReceiveBufferSize, TcpClient.recvBufferMinimumSize));
this.disposed = false;
this.dataAvailableEvent = new AutoResetEvent(false);
dataAvailableMinimumCount = 1; //1 Byte
this.recvTimeout = base.ReceiveTimeout;
//base.ReceiveTimeout = this.recvTimeout = 5000;
this.socketAsyncRecvError = null;
this.userLastRecvTime = DateTime.Now;
this.ownerStream = null;
//Set keep alive for 10 seconds
this.KeepAliveInterval = 10000;
this.sendProgressAttributes = new SendProgressConstraints(100, 8 * 1024);
}
override protected void Dispose(bool disposing)
{
if (!this.disposed)
{
// If disposing equals true, dispose all managed and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
StopSocketPumpThread();
bool isConnectd = this.IsConnected;
ReleaseSocket();
this.dataAvailableEvent.Close();
this.dataAvailableEvent = null;
if (isConnectd) OnDisconnected(new SocketDisconnectedEventArgs(SocketDisconnectedEventArgs.DisconnectReason.LocalDisconnect));
((IDisposable)this.recvBuffer).Dispose();
}
// Release unmanaged resources. (If disposing is false, only the following code is executed.)
this.disposed = true;
}
base.Dispose(disposing);
}
#endregion
#region Events Raising
protected virtual void OnDataAvailable(EventArgs e)
{
if (this.DataAvailable != null) this.DataAvailable(this, e);
}
protected virtual void OnDataArrived(SocketDataArrivedEventArgs e)
{
this.OnDataArrived(e, false);
}
protected virtual void OnDataArrived(SocketDataArrivedEventArgs e, bool async)
{
if (this.DataArrived == null) return;
if (async)
this.DataArrived.BeginInvoke(this, e, null, null);
else
this.DataArrived(this, e);
}
protected virtual void OnDataLost(SocketDataArrivedEventArgs e)
{
if (this.DataLost != null) this.DataLost(this, e);
}
protected virtual void OnConnected(EventArgs e)
{
if (this.Connected != null) this.Connected(this, e);
}
protected virtual void OnDisconnected(SocketDisconnectedEventArgs e)
{
if (this.Disconnected != null) this.Disconnected(this, e);
}
protected virtual void OnSendProgressChanged(SocketDataSendProgressChangedEventArgs e)
{
if (this.SendProgressChanged != null) this.SendProgressChanged(this, e);
}
protected virtual void OnSendCompleted(EventArgs e)
{
if (this.SendCompleted != null) this.SendCompleted(this, e);
}
protected virtual void OnError(SocketErrorEventArgs e)
{
this.OnError(e, false);
}
protected virtual void OnError(SocketErrorEventArgs e, bool async)
{
if (this.Error == null) return;
if (async)
this.Error.BeginInvoke(this, e, null, null);
else
this.Error(this, e);
}
#endregion
#region Properties
protected new virtual bool Active
{
get { return base.Active; }
set { base.Active = value; }
}
#region Public Properties
public new virtual int Available
{
get
{
lock (this.recvBuffer)
{
return this.recvBuffer.Count;
}
}
}
public new virtual Socket Client
{
get { return base.Client; }
set
{
if (base.Client == value) return;
StopSocketPumpThread();
ReleaseSocket();
base.Client = value;
if (value.Connected)
{
this.Active = true;
StartSocketPumpThread();
}
}
}
public virtual bool IsConnected
{
get { return base.Connected; }
}
public new virtual bool ExclusiveAddressUse
{
get { return base.ExclusiveAddressUse; }
set { base.ExclusiveAddressUse = value; }
}
public new virtual LingerOption LingerState
{
get { return base.LingerState; }
set { base.LingerState = value; }
}
public new virtual bool NoDelay
{
get { return base.NoDelay; }
set { base.NoDelay = value; }
}
public new virtual int ReceiveBufferSize
{
get { return this.Client.ReceiveBufferSize; }
set
{
lock (this.recvBuffer)
{
this.Client.ReceiveBufferSize = value;
}
}
}
public new virtual int ReceiveTimeout
{
get { return this.recvTimeout; }
set { this.recvTimeout = value; }
}
public new virtual int SendBufferSize
{
get { return base.SendBufferSize; }
set { base.SendBufferSize = value; }
}
public new virtual int SendTimeout
{
get { return base.SendTimeout; }
set { base.SendTimeout = value; }
}
public virtual UInt32 KeepAliveInterval
{
get
{
return this.keepAliveInterval;
}
set
{
byte[] inBuffer = new byte[12];
if (value == 0)
{
BitConverter.GetBytes((UInt32)0).CopyTo(inBuffer, 0);
BitConverter.GetBytes((UInt32)75000).CopyTo(inBuffer, 4);
BitConverter.GetBytes((UInt32)7200000).CopyTo(inBuffer, 8);
}
else
{
BitConverter.GetBytes((UInt32)1).CopyTo(inBuffer, 0);
BitConverter.GetBytes(value).CopyTo(inBuffer, 4); //Interval
BitConverter.GetBytes((UInt32)200).CopyTo(inBuffer, 8); //keepalive mechanism will kick in xxx ms after last send/receive or connected
}
this.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, value != 0);
this.Client.IOControl(IOControlCode.KeepAliveValues, inBuffer, null);
this.keepAliveInterval = value;
}
}
public virtual IPEndPoint LocalEndPoint
{
get { return this.Client.LocalEndPoint as IPEndPoint; }
}
public virtual IPEndPoint RemoteEndPoint
{
get { return this.Client.RemoteEndPoint as IPEndPoint; }
}
public SendProgressConstraints SendProgressAttributes
{
get { return this.sendProgressAttributes; }
}
#endregion
#endregion
#region Methods
private void StartSocketPumpThread()
{
this.socketPumpThread = new System.Threading.Thread(new System.Threading.ThreadStart(this.SocketPumpThreadProc));
this.socketPumpThread.IsBackground = true;
this.socketPumpThread.Start();
}
private void StopSocketPumpThread()
{
if (this.socketPumpThread != null && this.socketPumpThread.IsAlive)
{
this.socketPumpThread.Abort();
}
this.socketPumpThread = null;
}
private void SocketPumpThreadProc()
{
int recvCount, beforeRecvCount, lostCount, idleCount = 0, errCount = 0;
ArraySegment<byte>[] recvBuffers;
bool becomeAvailable = false;
ResetReceiveBuffer();
//---------------------------------------------
while (this.IsConnected)
{
#region try
try
{
if (!this.Client.Poll(7000000, SelectMode.SelectRead))
{
//Do some maintenance on the recvBuffer
idleCount = (DoMaintenanceOnRecvIdle(idleCount * 7000, (int)Math.Min((long)(DateTime.Now - this.userLastRecvTime).TotalMilliseconds, (long)int.MaxValue))) ? 0 : idleCount + 1;
continue;
}
//-------------------------------------
//increase receive buffer if needed
errCount = idleCount = lostCount = recvCount = 0; //Reset some variables
lock (this.recvBuffer)
{
ResizeRecvBuffer(true); //Increase internal recvieve buffer if needed
beforeRecvCount = this.recvBuffer.Count; //Remeber current size of available data
recvBuffers = this.recvBuffer.AcquireInternalBufferForWriting(false); //Get receive buffer internal buffer, locked for writing
try
{
recvCount = this.Client.Receive(recvBuffers);
}
finally
{
if (this.recvBuffer.ReleaseAcquiredInternalBuffer(recvCount))
{
lostCount = recvCount + beforeRecvCount - this.recvBuffer.Count;
}
}
}
if (recvCount == 0)
{
InternalDisconnect(SocketDisconnectedEventArgs.DisconnectReason.RemoteDisconnected);
}
else if (this.IsConnected && recvCount > 0)
{
becomeAvailable = (beforeRecvCount == 0);
lock (this.dataAvailableEvent)
{
if (this.dataAvailableMinimumCount <= recvCount + beforeRecvCount) this.dataAvailableEvent.Set();
}
if (becomeAvailable) OnDataAvailable(EventArgs.Empty);
HandleArrivedDataEvents(recvCount, lostCount);
}
}
#endregion
//-------------------------------------------------------
#region catch
catch (System.Threading.ThreadInterruptedException ex)
{
continue;
}
catch (SocketException ex)
{
switch (ex.SocketErrorCode)
{
case SocketError.TimedOut:
break;
case SocketError.ConnectionReset:
InternalDisconnect(SocketDisconnectedEventArgs.DisconnectReason.ConnectionLost); //Will also stop this thread
break;
default:
if (errCount > 0) throw;
errCount++;
this.socketAsyncRecvError = ex;
OnError(new SocketErrorEventArgs(ex), true);
break;
}
}
catch (ThreadAbortException ex)
{
//Terminating
}
catch (Exception ex)
{
throw;
}
#endregion
}
}
private void ResetReceiveBuffer()
{
lock (this.recvBuffer)
{
this.recvBuffer.Clear();
this.recvBuffer.Capacity = TcpClient.recvBufferMinimumSize;
this.dataAvailableEvent.Reset();
}
}
private bool ResizeRecvBuffer(bool increase)
{
if (increase)
{
if (this.recvBuffer.Capacity < this.ReceiveBufferSize && base.Available > this.recvBuffer.FreeSpace)
{
this.recvBuffer.Capacity = (int)Math.Min((long)this.ReceiveBufferSize, 2 * (long)this.recvBuffer.Capacity);
return true;
}
}
else
{
if (this.recvBuffer.Capacity / 2 >= this.recvBuffer.Count && this.recvBuffer.Capacity > TcpClient.recvBufferMinimumSize)
{
this.recvBuffer.Capacity = Math.Max(this.recvBuffer.Count, TcpClient.recvBufferMinimumSize);
return true;
}
}
return false;
}
private bool DoMaintenanceOnRecvIdle(int socketRecvIdleMilliseconds, int userRecvIdleMilliseconds)
{
if (Math.Min(socketRecvIdleMilliseconds, userRecvIdleMilliseconds) > 20000)
{
return ResizeRecvBuffer(false);
}
return false;
}
private void HandleArrivedDataEvents(int dataSize, int lostDataSize)
{
if (this.DataLost == null && this.DataArrived == null) return;
SocketDataArrivedEventArgs e = new SocketDataArrivedEventArgs(dataSize, lostDataSize);
if (lostDataSize > 0) OnDataLost(e);
OnDataArrived(e, true);
}
private void ReleaseSocket()
{
//Using base instead of this to access the wrapped socket, is used to avoid another call to ReleaseSocket
if (base.Client != null)
{
if (base.Client.Connected) this.Client.Shutdown(SocketShutdown.Both);
base.Client.Close();
base.Client = null;
base.Active = false;
}
}
private void RecreateSocket()
{
Socket newSocket = CloneSocket(base.Client);
//Using 'base' instead of 'this' to access the wrapped socket, is used to avoid another call to ReleaseSocket
ReleaseSocket();
base.Active = false; //indicates to the base TcpClient that it's not connected
base.Client = newSocket;
this.KeepAliveInterval = this.keepAliveInterval;
}
private Socket CloneSocket(Socket sock)
{
Socket newSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newSocket.Blocking = sock.Blocking;
newSocket.DontFragment = sock.DontFragment;
newSocket.ExclusiveAddressUse = sock.ExclusiveAddressUse;
newSocket.LingerState.Enabled = sock.LingerState.Enabled;
newSocket.LingerState.LingerTime = sock.LingerState.LingerTime;
newSocket.NoDelay = sock.NoDelay;
newSocket.ReceiveBufferSize = sock.ReceiveBufferSize;
newSocket.ReceiveTimeout = sock.ReceiveTimeout;
newSocket.SendBufferSize = sock.SendBufferSize;
newSocket.SendTimeout = sock.SendTimeout;
newSocket.Ttl = sock.Ttl;
newSocket.UseOnlyOverlappedIO = sock.UseOnlyOverlappedIO;
return newSocket;
}
private void SetRecvDataAvailableMinimumSize(int size)
{
lock (this.dataAvailableEvent)
{
this.dataAvailableMinimumCount = size;
if (this.Available < this.dataAvailableMinimumCount)
{
this.dataAvailableEvent.Reset();
}
else
{
this.dataAvailableEvent.Set();
}
}
}
private void InternalDisconnect(SocketDisconnectedEventArgs.DisconnectReason reason)
{
//Methods which wants to prevent the event raising and operation done here (OnDisconnected),
//incase the socket is not connected, should check IsConnected before calling this method
try
{
if (Thread.CurrentThread != this.socketPumpThread) StopSocketPumpThread(); //prevent call from the pump thread to kill itself
RecreateSocket();
OnDisconnected(new SocketDisconnectedEventArgs(reason));
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
}
private int InternalReceive(ref byte[] buffer, int offset, int size, bool allSizeOrNothing)
{
int res = 0;
if (this.socketAsyncRecvError != null)
{
try
{
throw this.socketAsyncRecvError;
}
finally { this.socketAsyncRecvError = null; }
}
try
{
//If disconnected, and not enough data to read, throw exception
if (!this.IsConnected && (this.Available == 0 || allSizeOrNothing && size > this.Available))
{
throw new SocketException((int)SocketError.NotConnected);
}
SetRecvDataAvailableMinimumSize((allSizeOrNothing) ? size : 1);
if (this.dataAvailableEvent.WaitOne(this.recvTimeout, true))
{
lock (this.recvBuffer)
{
if (buffer == null)
{
buffer = this.recvBuffer.Dequeue(size);
res = buffer.Length;
}
else
{
res = this.recvBuffer.Dequeue(buffer, size);
}
this.userLastRecvTime = DateTime.Now;
}
if (this.Available > 0) this.dataAvailableEvent.Set();
return res;
}
throw new SocketException((int)SocketError.TimedOut);
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
return (-1);
//throw;
}
}
protected virtual int SendWithProgress(byte[] buffer, int offset, int size, SocketFlags socketFlags)
{
SocketDataSendProgressChangedEventArgs e = new SocketDataSendProgressChangedEventArgs(0, size);
TimeSpan ellapsedTime;
DateTime time1, time2;
int sendSize;
time1 = DateTime.Now;
while (size > 0)
{
sendSize = Math.Min(this.sendProgressAttributes.ChunkSize, size);
sendSize = this.Client.Send(buffer, offset, sendSize, socketFlags);
offset += sendSize;
size -= sendSize;
e.SentSize += sendSize;
ellapsedTime = (time2 = DateTime.Now) - time1;
if (ellapsedTime.TotalMilliseconds >= this.sendProgressAttributes.MinMillisecondsBetweenEvents || size == 0)
{
OnSendProgressChanged(e);
time1 = time2;
}
}
return e.SentSize;
}
private void PostConnect()
{
StartSocketPumpThread();
OnConnected(EventArgs.Empty);
}
#region Public Methods
public new virtual TcpClientStream GetStream()
{
if (this.ownerStream == null)
{
this.ownerStream = new TcpClientStream(this, true);
}
return this.ownerStream;
}
public new virtual IAsyncResult BeginConnect(IPAddress address, int port, AsyncCallback requestCallback, object state)
{
return base.BeginConnect(address, port, requestCallback, state);
}
public new virtual IAsyncResult BeginConnect(IPAddress[] addresses, int port, AsyncCallback requestCallback, object state)
{
return base.BeginConnect(addresses, port, requestCallback, state);
}
public new virtual IAsyncResult BeginConnect(string host, int port, AsyncCallback requestCallback, object state)
{
return base.BeginConnect(host, port, requestCallback, state);
}
public new virtual void Connect(IPEndPoint remoteEP)
{
try
{
base.Connect(remoteEP);
PostConnect();
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
}
public new virtual void Connect(IPAddress address, int port)
{
try
{
base.Connect(address, port);
PostConnect();
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
}
public new virtual void Connect(IPAddress[] ipAddresses, int port)
{
try
{
base.Connect(ipAddresses, port);
PostConnect();
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
}
public new virtual void Connect(string hostname, int port)
{
try
{
base.Connect(hostname, port);
PostConnect();
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
}
public new virtual void EndConnect(IAsyncResult asyncResult)
{
base.EndConnect(asyncResult);
//this.Client.BeginReceive(this.tempRecvBuffer, 0, this.tempRecvBuffer.Length, SocketFlags.None, new AsyncCallback(this.PumpInSocket), this.tempRecvBuffer);
StartSocketPumpThread();
OnConnected(EventArgs.Empty);
}
public virtual IAsyncResult BeginReceive(AsyncCallback callback, object state)
{
byte[] buffer = null;
return (new BeginReceiveDelegate(this.InternalReceive)).BeginInvoke(ref buffer, 0, int.MaxValue, false, callback, state);
}
public virtual IAsyncResult BeginReceive(byte[] buffer, AsyncCallback callback, object state)
{
return this.BeginReceive(buffer, 0, (buffer == null) ? 0 : buffer.GetLength(0), false, callback, state);
}
public virtual IAsyncResult BeginReceive(byte[] buffer, int offset, int size, AsyncCallback callback, object state)
{
return this.BeginReceive(buffer, offset, size, false, callback, state);
}
public virtual IAsyncResult BeginReceive(byte[] buffer, int offset, int size, bool allSizeOrNothing, AsyncCallback callback, object state)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if ((offset < 0) || (offset > buffer.Length))
{
throw new ArgumentOutOfRangeException("offset");
}
if ((size < 0) || (size > (buffer.Length - offset)))
{
throw new ArgumentOutOfRangeException("size");
}
return (new BeginReceiveDelegate(this.InternalReceive)).BeginInvoke(ref buffer, offset, size, allSizeOrNothing, callback, state);
}
public virtual int Receive(byte[] buffer)
{
return this.Receive(buffer, 0, (buffer == null) ? 0 : buffer.GetLength(0), false);
}
public virtual int Receive(byte[] buffer, int offset, int size)
{
return Receive(buffer, offset, size, false);
}
public virtual int Receive(byte[] buffer, int offset, int size, bool allSizeOrNothing)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
if ((offset < 0) || (offset > buffer.Length))
{
throw new ArgumentOutOfRangeException("offset");
}
if ((size < 0) || (size > (buffer.Length - offset)))
{
throw new ArgumentOutOfRangeException("size");
}
return InternalReceive(ref buffer, offset, size, allSizeOrNothing);
}
public virtual byte[] Receive()
{
byte[] buffer = null;
InternalReceive(ref buffer, 0, int.MaxValue, false);
return buffer;
}
public virtual int EndReceive(IAsyncResult asyncResult)
{
byte[] buffer = null;
System.Runtime.Remoting.Messaging.AsyncResult delegateAsyncResult = asyncResult as System.Runtime.Remoting.Messaging.AsyncResult;
if (delegateAsyncResult == null) throw new ArgumentException("Incorrect type of Async Result");
return ((BeginReceiveDelegate)delegateAsyncResult.AsyncDelegate).EndInvoke(ref buffer, asyncResult);
}
public virtual Byte[] EndReceive(out int count, IAsyncResult asyncResult)
{
byte[] buffer = null;
System.Runtime.Remoting.Messaging.AsyncResult delegateAsyncResult = asyncResult as System.Runtime.Remoting.Messaging.AsyncResult;
if (delegateAsyncResult == null) throw new ArgumentException("Incorrect type of Async Result");
count = ((BeginReceiveDelegate)delegateAsyncResult.AsyncDelegate).EndInvoke(ref buffer, asyncResult);
return buffer;
}
public virtual IAsyncResult BeginSend(byte[] buffer, AsyncCallback callback, object state)
{
if (this.SendProgressChanged != null)
{
return (new SendWithProgressDelegate(this.SendWithProgress)).BeginInvoke(buffer, 0, (buffer != null) ? buffer.GetLength(0) : 0, SocketFlags.None, callback, state);
}
else
{
return this.Client.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, callback, state);
}
}
public virtual IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback callback, object state)
{
if (this.SendProgressChanged != null)
{
return (new SendWithProgressDelegate(this.SendWithProgress)).BeginInvoke(buffer, offset, size, socketFlags, callback, state);
}
else
{
return this.Client.BeginSend(buffer, offset, size, socketFlags, callback, state);
}
}
public virtual int Send(byte[] buffer)
{
int res;
try
{
if (this.SendProgressChanged != null)
{
res = SendWithProgress(buffer, 0, (buffer != null) ? buffer.GetLength(0) : 0, SocketFlags.None);
}
else
{
res = this.Client.Send(buffer);
}
OnSendCompleted(EventArgs.Empty);
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
return res;
}
public virtual int Send(byte[] buffer, int offset, int size)
{
int res;
try
{
if (this.SendProgressChanged != null)
{
res = SendWithProgress(buffer, offset, size, SocketFlags.None);
}
else
{
res = this.Client.Send(buffer, offset, size, SocketFlags.None);
}
OnSendCompleted(EventArgs.Empty);
}
catch (SocketException e)
{
this.OnError(new SocketErrorEventArgs(e), true);
throw;
}
return res;
}
public virtual int EndSend(IAsyncResult asyncResult)
{
int res;
if (asyncResult is System.Runtime.Remoting.Messaging.AsyncResult
&& ((System.Runtime.Remoting.Messaging.AsyncResult)asyncResult).AsyncDelegate is SendWithProgressDelegate)
{
res = ((SendWithProgressDelegate)((System.Runtime.Remoting.Messaging.AsyncResult)asyncResult).AsyncDelegate).EndInvoke(asyncResult);
}
else
{
res = this.Client.EndSend(asyncResult);
}
OnSendCompleted(EventArgs.Empty);
return res;
}
public virtual void Disconnect()
{
if (!this.IsConnected) return;
InternalDisconnect(SocketDisconnectedEventArgs.DisconnectReason.LocalDisconnect);
}
public virtual IAsyncResult BeginDisconnect(AsyncCallback callback, object state)
{
return (new BeginDisconnectDelegate(this.Disconnect)).BeginInvoke(callback, state);
}
public virtual void EndDisconnect(IAsyncResult asyncResult)
{
System.Runtime.Remoting.Messaging.AsyncResult delegateAsyncResult = asyncResult as System.Runtime.Remoting.Messaging.AsyncResult;
if (delegateAsyncResult == null) throw new ArgumentException("Incorrect type of Async Result");
((BeginDisconnectDelegate)delegateAsyncResult.AsyncDelegate).EndInvoke(asyncResult);
}
#endregion
#endregion
}
public class TcpListener : IDisposable
{
public string Key;
private bool disposed;
private System.Net.Sockets.Socket socket;
private IPEndPoint localEndPoint;
private bool exclusiveAddressUse;
#region Events
public event EventHandler ConnectionRequest;
#endregion
public TcpListener() : this(0) { }
public TcpListener(int port) : this(IPAddress.Any, port) { }
public TcpListener(IPAddress localaddr, int port) : this(new IPEndPoint(localaddr, port)) { }
public TcpListener(IPEndPoint localEP)
{
InitInstance(localEP);
}
private void InitInstance(IPEndPoint localEP)
{
this.disposed = false;
this.localEndPoint = localEP;
this.socket = new System.Net.Sockets.Socket(localEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.exclusiveAddressUse = false;
}
virtual protected void Dispose(bool disposing)
{
if (!this.disposed)
{
// If disposing equals true, dispose all managed and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
this.socket.Close();
}
// Release unmanaged resources. (If disposing is false, only the following code is executed.)
this.disposed = true;
}
}
private void MonitorConnectionRequests()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(this.ConnectionRequestsMonitorProc), this.socket);
}
private void ConnectionRequestsMonitorProc(object state)
{
try
{
while (this.IsListening && !this.socket.Poll(7000000, SelectMode.SelectRead)) ;
if (this.IsListening && this.socket == (System.Net.Sockets.Socket)state) OnConnectionRequest(EventArgs.Empty);
}
catch (SocketException ex)
{
}
catch (ThreadInterruptedException ex)
{
}
catch (ThreadAbortException ex)
{
}
catch (Exception ex)
{
}
}
#region Events Raising
protected virtual void OnConnectionRequest(EventArgs e)
{
if (this.ConnectionRequest != null) this.ConnectionRequest(this, e);
}
#endregion
#region Public Properties
virtual public bool ExclusiveAddressUse
{
get { return this.socket.ExclusiveAddressUse; }
set
{
this.socket.ExclusiveAddressUse = value;
this.exclusiveAddressUse = value;
}
}
virtual public IPEndPoint LocalEndPoint
{
get { return this.localEndPoint; }
protected set { this.localEndPoint = value; }
}
virtual public System.Net.Sockets.Socket Server
{
get { return this.socket; }
}
virtual public bool IsListening
{
get { return ((int)this.socket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.AcceptConnection) != 0) ? true : false; }
}
virtual public bool Pending
{
get
{
if (!this.IsListening) return false;
return this.socket.Poll(0, SelectMode.SelectRead);
}
}
#endregion
#region Public Methods
virtual public System.Net.Sockets.Socket AcceptSocket()
{
System.Net.Sockets.Socket res = this.socket.Accept();
MonitorConnectionRequests();
return res;
}
virtual public TcpClient AcceptTcpClient()
{
System.Net.Sockets.Socket socket = this.AcceptSocket();
TcpClient res = new TcpClient();
res.Client = socket;
return res;
}
virtual public IAsyncResult BeginAcceptSocket(AsyncCallback callback, object state)
{
return this.socket.BeginAccept(callback, state);
}
virtual public IAsyncResult BeginAcceptTcpClient(AsyncCallback callback, object state)
{
return this.BeginAcceptSocket(callback, state);
}
virtual public System.Net.Sockets.Socket EndAcceptSocket(IAsyncResult asyncResult)
{
System.Net.Sockets.Socket res = this.socket.EndAccept(asyncResult);
MonitorConnectionRequests();
return res;
}
virtual public TcpClient EndAcceptTcpClient(IAsyncResult asyncResult)
{
System.Net.Sockets.Socket socket = this.EndAcceptSocket(asyncResult);
TcpClient res = new TcpClient();
res.Client = socket;
return res;
}
private void InternalStart()
{
if (this.IsListening)
{
if (this.localEndPoint.Equals(this.socket.LocalEndPoint)) return; //Already listening on the requested end point
this.Stop();
}
this.socket.Bind(this.LocalEndPoint);
this.socket.Listen(5);
MonitorConnectionRequests();
}
virtual public void Start()
{
InternalStart();
}
virtual public void Start(int port)
{
this.localEndPoint.Port = port;
InternalStart();
}
virtual public void Start(IPAddress localaddr, int port)
{
this.localEndPoint.Address = localaddr;
this.localEndPoint.Port = port;
InternalStart();
}
virtual public void Start(IPEndPoint localEP)
{
this.localEndPoint = localEP;
InternalStart();
}
virtual public void Stop()
{
this.socket.Close();
this.socket = new System.Net.Sockets.Socket(this.localEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
this.socket.ExclusiveAddressUse = this.exclusiveAddressUse;
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
public class TcpClientStream : Stream
{
#region Member Fields
private TcpClient tcpClient;
bool ownsSocket;
bool disposed;
#endregion
#region Lifetime
public TcpClientStream(TcpClient tcpClient)
: this(tcpClient, false)
{
}
public TcpClientStream(TcpClient tcpClient, bool ownsSocket)
{
InitInstance(tcpClient, ownsSocket);
}
private void InitInstance(TcpClient tcpClient, bool ownsSocket)
{
if (tcpClient == null) throw new ArgumentNullException("tcpClient");
this.tcpClient = tcpClient;
this.ownsSocket = ownsSocket;
this.disposed = false;
}
protected override void Dispose(bool disposing)
{
if (!this.disposed)
{
// If disposing equals true, dispose all managed and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
if (this.ownsSocket)
{
this.TcpClient.Close();
}
}
// Release unmanaged resources. (If disposing is false, only the following code is executed.)
this.disposed = true;
}
base.Dispose(disposing);
}
#endregion
#region Public Properties
public virtual TcpClient TcpClient
{
get { return this.tcpClient; }
}
#endregion
#region Public Methods
public virtual IAsyncResult BeginRead(AsyncCallback callback, object state)
{
return this.TcpClient.BeginReceive(callback, state);
}
public virtual IAsyncResult BeginRead(byte[] buffer, AsyncCallback callback, object state)
{
return this.BeginRead(buffer, 0, (buffer == null) ? 0 : buffer.GetLength(0), callback, state);
}
public virtual IAsyncResult BeginRead(byte[] buffer, int offset, int count, bool allCountOrNothing, AsyncCallback callback, object state)
{
return this.TcpClient.BeginReceive(buffer, offset, count, allCountOrNothing, callback, state);
}
public virtual int Read(byte[] buffer)
{
return this.Read(buffer, 0, (buffer == null) ? 0 : buffer.GetLength(0), false);
}
public virtual int Read(byte[] buffer, int offset, int count, bool allCountOrNothing)
{
try
{
return this.TcpClient.Receive(buffer, offset, count, allCountOrNothing);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut) throw new TimeoutException("Timeout while reading from socket", ex);
throw;
}
}
public virtual byte[] Read()
{
try
{
return this.TcpClient.Receive();
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut) throw new TimeoutException("Timeout while reading from socket", ex);
throw;
}
}
public virtual Byte[] EndRead(out int count, IAsyncResult asyncResult)
{
try
{
return this.TcpClient.EndReceive(out count, asyncResult);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut) throw new TimeoutException("Timeout while reading from socket", ex);
throw;
}
}
public virtual IAsyncResult BeginWrite(byte[] buffer, AsyncCallback callback, object state)
{
return this.BeginWrite(buffer, 0, (buffer != null) ? buffer.GetLength(0) : 0, callback, state);
}
public virtual void Write(byte[] buffer)
{
this.Write(buffer, 0, (buffer != null) ? buffer.GetLength(0) : 0);
}
#region Stream overrides
public override bool CanRead
{
get { return true; }
}
public override bool CanSeek
{
get { return false; }
}
public override bool CanWrite
{
get { return true; }
}
public override void Flush()
{
}
public override long Length
{
get { throw new NotSupportedException(); }
}
public override long Position
{
get
{
throw new NotSupportedException();
}
set
{
throw new NotSupportedException();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
return this.Read(buffer, offset, count, false);
}
public override long Seek(long offset, SeekOrigin origin)
{
throw new NotSupportedException();
}
public override void SetLength(long value)
{
throw new NotSupportedException();
}
public override void Write(byte[] buffer, int offset, int count)
{
try
{
this.TcpClient.Send(buffer, offset, count);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut) throw new TimeoutException("Timeout while writing to socket", ex);
throw;
}
}
public override bool CanTimeout
{
get { return true; }
}
public override int ReadTimeout
{
get
{
return this.TcpClient.ReceiveTimeout;
}
set
{
this.TcpClient.ReceiveTimeout = value;
}
}
public override int WriteTimeout
{
get
{
return this.TcpClient.SendTimeout;
}
set
{
this.TcpClient.SendTimeout = value;
}
}
#endregion
#endregion
}
} //namespace System.Net.Sockets.Customized
namespace Barakbbn.Freeware.Collections
{
public class CyclicQueue<T> : IDisposable
{
#region Member Fields
private bool disposed;
private T[] data;
private int readIndex, writeIndex;
private bool isFull;
private Mutex dataLock;
#endregion
#region Lifetime
public CyclicQueue(int capacity)
{
InitInstance(capacity);
}
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
// If disposing equals true, dispose all managed and unmanaged resources.
if (disposing)
{
// Dispose managed resources.
this.dataLock.Close();
}
// Release unmanaged resources. (If disposing is false, only the following code is executed.)
this.disposed = true;
}
}
private void InitInstance(int capacity)
{
this.disposed = false;
this.readIndex = this.writeIndex = 0;
this.isFull = false;
this.data = new T[capacity];
this.dataLock = new Mutex(false);
}
#endregion
protected virtual int CalcCyclicIndex(int fromIndex, int offset)
{
int res = (int)((fromIndex + (long)offset) % this.Capacity);
if (res < 0) res += this.Capacity;
return res;
}
//private void AlignQueue()
//{
// RotateQueue(this.readIndex, false);
//}
//private void RotateQueue(int count, bool rightSide)
//{
// count = Math.Abs(count) % this.Capacity;
// if (count == 0) return;
// T[] tmp = new T[Math.Min(count, this.Capacity - count)];
// if (rightSide) count = this.Capacity - count; //adjust to left rotation
// if (count < this.Capacity - count)
// {
// LockInternalQueue();
// try
// {
// Array.Copy(this.data, 0, tmp, 0, count);
// Array.Copy(this.data, count, this.data, 0, this.Capacity - count);
// Array.Copy(tmp, 0, this.data, this.Capacity - count, count);
// }
// finally
// {
// UnlockInternalQueue();
// }
// }
// else
// {
// LockInternalQueue();
// try
// {
// Array.Copy(this.data, count, tmp, 0, tmp.Length);
// Array.Copy(this.data, 0, this.data, tmp.Length, count);
// Array.Copy(tmp, 0, this.data, 0, tmp.Length);
// }
// finally
// {
// UnlockInternalQueue();
// }
// }
// this.readIndex = CalcCyclicIndex(this.readIndex, -count);
// this.writeIndex = CalcCyclicIndex(this.writeIndex, -count);
//}
private ArraySegment<T>[] InternalGetWriteSegments(bool allowOverwrite)
{
ArraySegment<T>[] res = new ArraySegment<T>[2];
if (allowOverwrite)
{
res[0] = new ArraySegment<T>(this.data, this.writeIndex, this.Capacity - this.writeIndex);
res[1] = new ArraySegment<T>(this.data, 0, this.writeIndex);
}
else
{
if (this.IsFull)
{
res[0] = new ArraySegment<T>(this.data, 0, 0);
res[1] = new ArraySegment<T>(this.data, this.writeIndex, 0);
}
else if (this.writeIndex >= this.readIndex)
{
res[0] = new ArraySegment<T>(this.data, this.writeIndex, this.Capacity - this.writeIndex);
res[1] = new ArraySegment<T>(this.data, 0, this.readIndex);
}
else
{
res[0] = new ArraySegment<T>(this.data, this.writeIndex, this.readIndex - this.writeIndex);
res[1] = new ArraySegment<T>(this.data, this.readIndex, 0);
}
}
return res;
}
protected virtual void ResizeBuffer(int newCapacity)
{
if (newCapacity < 0) throw new ArgumentOutOfRangeException("newCapacity");
lock (this)
{
int count = this.Count;
T[] res = new T[newCapacity];
LockInternalQueue();
try
{
if (count > newCapacity) this.Remove((count = count - newCapacity)); //The logic here, is to discard older data, incase new capacity is smaller
this.Dequeue(res, count);
}
finally
{
UnlockInternalQueue();
}
this.IsFull = (count == newCapacity);
this.writeIndex = count;
this.readIndex = 0;
this.data = res;
}
}
protected virtual void LockInternalQueue()
{
if (!this.dataLock.WaitOne(5000, true)) throw new TimeoutException("Previous call to AcquireInternalBufferForWriting wasn't released using ReleaseAcquiredInternalBuffer");
}
protected virtual void UnlockInternalQueue()
{
this.dataLock.ReleaseMutex();
}
#region Public Properties
public virtual int Capacity
{
get
{
lock (this)
{
return this.data.GetLength(0);
}
}
set
{
if (this.data.GetLength(0) != value)
{
ResizeBuffer(value);
}
}
}
public virtual int Count
{
get
{
int res;
lock (this)
{
res = this.writeIndex - this.readIndex;
if (res < 0 || this.IsFull) res += this.Capacity;
}
return res;
}
}
public virtual bool IsFull
{
get
{
lock (this)
{
return this.isFull;
}
}
protected set { this.isFull = value; }
}
public virtual bool IsEmpty
{
get
{
lock (this)
{
return (this.readIndex == this.writeIndex && !this.isFull);
}
}
}
public virtual int FreeSpace
{
get
{
int res;
lock (this)
{
res = this.readIndex - this.writeIndex;
if (res <= 0 && !this.IsFull) res += this.Capacity;
}
return res;
}
}
#endregion
#region Public Methods
public virtual bool Enqueue(T item)
{
return this.Enqueue(new T[] { item });
}
public virtual bool Enqueue(T[] items)
{
return this.Enqueue(items, (items != null) ? items.GetLength(0) : 0);
}
public virtual bool Enqueue(T[] items, int count) //return: data overwritten?
{
if (count <= 0) return false;
int newFreeSpace;
bool res, isFull;
lock (this)
{
if (items.GetLength(0) < count) count = items.GetLength(0);
newFreeSpace = this.FreeSpace - count;
res = (newFreeSpace < 0); //Is going to overwrite data
isFull = (newFreeSpace <= 0); //Is going to be full
if (count >= this.Capacity)
{
LockInternalQueue();
try
{
Array.Copy(items, count - this.Capacity, this.data, 0, this.Capacity);
}
finally
{
UnlockInternalQueue();
}
this.writeIndex = this.readIndex = 0;
this.IsFull = isFull;
return res;
}
if (count <= this.Capacity - this.writeIndex)
{
LockInternalQueue();
try
{
Array.Copy(items, 0, this.data, this.writeIndex, count);
}
finally
{
UnlockInternalQueue();
}
}
else
{
int size = this.Capacity - this.writeIndex;
LockInternalQueue();
try
{
Array.Copy(items, 0, this.data, this.writeIndex, size);
Array.Copy(items, size, this.data, 0, count - size);
}
finally
{
UnlockInternalQueue();
}
}
this.writeIndex = CalcCyclicIndex(this.writeIndex, count);
if (isFull) this.IsFull = true;
if (res) this.readIndex = this.writeIndex;//Data lost
}
return res;
}
public virtual T Dequeue() { return default(T); }
public virtual T[] Dequeue(int count)
{
if (count < 0) throw new ArgumentOutOfRangeException("count", "Value must be positive");
if (count > this.Count) count = this.Count;
T[] res = new T[count];
this.Dequeue(res, count);
return res;
}
public virtual int Dequeue(T[] items)
{
return this.Dequeue(items, (items != null) ? items.GetLength(0) : 0);
}
public virtual int Dequeue(T[] items, int count)
{
lock (this)
{
count = this.Peek(items, count);
if (count > 0) this.Remove(count);
}
return count;
}
public virtual T Peek()
{
lock (this)
{
if (this.Count == 0) throw new InvalidOperationException("Queue is empty");
return this.Peek(1)[0];
}
}
public virtual T[] Peek(int count)
{
if (count < 0) throw new ArgumentOutOfRangeException("count", "Value must be positive");
if (count > this.Count) count = this.Count;
T[] res = new T[count];
this.Peek(res, count);
return res;
}
public virtual int Peek(T[] items)
{
return this.Peek(items, (items != null) ? items.GetLength(0) : 0);
}
public virtual int Peek(T[] items, int count)
{
if (items == null) throw new ArgumentNullException("items");
if (items.GetLength(0) < count) throw new ArgumentOutOfRangeException("count");
lock (this)
{
if (count > this.Count) count = this.Count;
if (this.Capacity - this.readIndex >= count)
{
LockInternalQueue();
try
{
Array.Copy(this.data, this.readIndex, items, 0, count);
}
finally
{
UnlockInternalQueue();
}
}
else
{
int size = this.Capacity - this.readIndex;
LockInternalQueue();
try
{
Array.Copy(this.data, this.readIndex, items, 0, size);
Array.Copy(this.data, 0, items, size, count - size);
}
finally
{
UnlockInternalQueue();
}
}
}
return count;
}
public virtual void Clear()
{
lock (this)
{
this.writeIndex = this.readIndex = 0;
this.IsFull = false;
}
}
public virtual void Remove(int count)
{
if (count < 0) throw new ArgumentOutOfRangeException("count");
if (count == 0) return;
lock (this)
{
if (count >= this.Count)
{
this.readIndex = this.writeIndex = 0;
}
else
{
this.readIndex = CalcCyclicIndex(this.readIndex, count);
}
this.IsFull = false;
}
}
public virtual ArraySegment<T>[] AcquireInternalBufferForWriting(bool onlyFreeSpace)
{
ArraySegment<T>[] res = null;
lock (this)
{
LockInternalQueue();
try
{
res = InternalGetWriteSegments(!onlyFreeSpace);
}
catch (Exception ex)
{
UnlockInternalQueue();
}
}
return res;
}
public virtual bool ReleaseAcquiredInternalBuffer(int itemsWrittenCount)
{
lock (this)
{
int newFreeSpace;
bool res;
UnlockInternalQueue();
newFreeSpace = this.FreeSpace - itemsWrittenCount; //calc new free space before new writeIndex
this.writeIndex = CalcCyclicIndex(this.writeIndex, itemsWrittenCount);
if (newFreeSpace <= 0) this.IsFull = true;
res = (newFreeSpace < 0);
if (res) this.readIndex = this.writeIndex;//Data lost
return res;
}
}
#endregion
#region IDisposable Members
void IDisposable.Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}