最近写了个socket的多线程 异步编程的组件。因为以前都是写写asp.net 的东西,这个多线程 和异步 还有 socket 都没有搞过,所以自我感觉写的不是很好。线程安全上不知道会不会有问题。今天把代码发上来,希望可以有高人指点里面的错误。同时,和大家共享一下我的代码。

server端
app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ServerIpAddress" value="10.13.12.15"/>
<add key="ServerSocketPort" value="399"/>
<add key="ServerSocketBufferSize" value="100"/>
</appSettings>
</configuration>
Program.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Diagnostics;
using MySocket;
using System.Windows.Forms;
namespace ServerConsole
{
class Program
{
public static void Main()
{
Server srv = ServerFactory.CreateInstance();
srv.AfterReceivedData += new EventHandler(srv_ReceivedDate);
//srv.BeforeSendData += new BeforeSendDataEventHandler(srv_BeforeSendData);
try
{
//srv.mythread = new Thread(new ThreadStart(srv.BeginListen));
//srv.mythread.Start();
srv.OnStart();
Console.WriteLine("press enter key to end");
Console.ReadLine();
}
catch (System.Exception er)
{
MessageBox.Show(er.Message, "完成", MessageBoxButtons.OK, MessageBoxIcon.Stop);
}
finally
{
//srv.mythread.Abort();//中止线程
srv.OnStop();
}
Thread.Sleep(1500);
}
static byte[] srv_BeforeSendData(object sender, BeforeSendDataEventArgs e)
{
string Igot = "I got: " + Encoding.Default.GetString(e.Data);
return Encoding.Default.GetBytes(Igot);
}
static void srv_ReceivedDate(object sender, AfterReceivedDataEventArgs e)
{
Trace.WriteLine("Program Console got: "+Encoding.Default.GetString(e.Data));
}
}
}
EventArgs.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace MySocket
{
public class AfterReceivedDataEventArgs : EventArgs
{
byte[] data;
public byte[] Data { get { return data; } set { data = value; } }
public AfterReceivedDataEventArgs(byte[] data)
{
this.data = data;
}
}
public class BeforeSendDataEventArgs : EventArgs
{
byte[] data;
public byte[] Data { get { return data; } set { data = value; } }
public BeforeSendDataEventArgs(byte[] data)
{
this.data = data;
}
}
public class SessionTerminateEventArgs : EventArgs
{
Session session;
public Session Session { get { return session; } set { session = value; } }
public SessionTerminateEventArgs(Session session)
{
this.session = session;
}
}
public delegate byte[] BeforeSendDataEventHandler(object sender,BeforeSendDataEventArgs e);
}
Server.cs:
//服务端:
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Diagnostics;
namespace MySocket
{
///
/// Socket Server.Listening incoming.
///
public class Server : IDisposable
{
Socket listener;
Dictionary clientItems; //session list.
private int _currentSessionNumber = 0;
private object _syncObject = new object();
private bool disposed = false;
private string strIpAddress;
private int port;
private int bufferSize;
private IPEndPoint ipEndpoint;
private int backlog;
public Dictionary Sessions { get { return clientItems; } }
//接收事件
public event EventHandler AfterReceivedData;
public event BeforeSendDataEventHandler BeforeSendData;
public string StrIpAddress { get { return strIpAddress; } set { strIpAddress = value; } }
public int Port { get { return port; } set { port = value; } }
public int BufferSize { get { return bufferSize; } set { bufferSize = value; } }
public int Backlog { get { return backlog; } set { backlog = value; } }
///
/// 初始化一个socket server 实例,要指定ip地址,端口号,缓存字节的大小
///
/// ip地址
/// 端口号
/// 预留缓存的大小
public Server(string strIpAddress, int port,int bufferSize)
{
this.strIpAddress = strIpAddress;
this.port = port;
this.bufferSize = bufferSize;
clientItems = new Dictionary();
ipEndpoint = new IPEndPoint(IPAddress.Parse(strIpAddress), port);
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Trace.WriteLine("ipEndpoint :" + ipEndpoint.ToString());
}
///
/// OnStart,start the server to listen
///
public void OnStart()
{
Trace.WriteLine("BeginListen...");
try
{
listener.Bind(ipEndpoint);
listener.Listen(backlog);
listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
}
catch (SocketException ex)
{
Trace.WriteLine("Error:" + ex.ToString());
}
}
///
/// OnConnectRequest,create new session.
///
///
private void OnConnectRequest(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
lock (_syncObject)
{
if (false == disposed)
{//if disposed ,do nothing.otherwise,do something.
//create session ,store it in the list.
CreateNewSession(listener.EndAccept(ar));
listener.BeginAccept(new AsyncCallback(OnConnectRequest), listener);
}
}
}
///
/// CreateNewSession,init the session, delegate.
///
/// new socket that will deal the connection,ie receive the data, send data.
private void CreateNewSession(Socket socket)
{
Trace.WriteLine(string.Format("Client {0}, connected", socket.RemoteEndPoint));
int clientId = Interlocked.Increment(ref _currentSessionNumber);
Session sc = new Session(clientId, socket,this.bufferSize);
sc.AfterReceivedData += new EventHandler(session_AfterReceivedData);
sc.SessionTerminated += new EventHandler(session_SessionTerminated);
// hook the session's BeforeSendData to the server's BeforeSendData
// so in the server code ,you can deal it by your self.
if(BeforeSendData!=null)
sc.BeforeSendData += BeforeSendData;
//session begin to work.
sc.BeginReceiveData();
lock (_syncObject)
{
//add the session to the list.
clientItems.Add(sc.ID, sc);
}
}
///
/// session_SessionTerminated,remove it from list, close the session. dedelegate tht event.
///
///
///
void session_SessionTerminated(object sender, SessionTerminateEventArgs e)
{
lock (_syncObject)
{
clientItems.Remove(e.Session.ID);
}
e.Session.Close();
e.Session.AfterReceivedData -= session_AfterReceivedData;
e.Session.SessionTerminated -= session_SessionTerminated;
e.Session.BeforeSendData -= BeforeSendData;
Trace.WriteLine(string.Format("session:{0} removed from clientItems", e.Session.ID));
//foreach (Session s in clientItems.Values)
//{
// Trace.WriteLine("Client Items is:----");
// Trace.WriteLine(" " + s.ID.ToString());
//}
}
///
/// session_AfterReceivedData,after a received data is got, set the session to begin to receive,
/// and you can do something else by yourself.ie:got the data, print them or store them in your code.
///
/// sender
/// AfterReceivedDataEventArgs info
protected virtual void session_AfterReceivedData(object sender, AfterReceivedDataEventArgs e)
{
lock (_syncObject)
{
if (false == disposed)
{
Session session = sender as Session;
session.BeginReceiveData();
//do yourself thing.ie:got the data, print them or store them in your code.
if (AfterReceivedData != null)
AfterReceivedData(sender, e);
}
}
}
///
/// BeginSendData(Session session,byte[] data)
///
/// session that will got the data
/// data that will be sent
public void BeginSendData(Session session,byte[] data)
{
session.BeginSendData(data);
}
///
/// OnStop , call the dispose.
///
public void OnStop()
{
Dispose();
}
#region IDisposable Members
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
lock (this)
{
disposed = true;
if (disposing)
{
//release managed resource
// clean the session list.close them one by one.
foreach (Session s in clientItems.Values)
{
s.Close();
s.AfterReceivedData -= session_AfterReceivedData;
s.SessionTerminated -= session_SessionTerminated;
s.BeforeSendData -= BeforeSendData;
}
//clean the listener.
if (listener != null && listener.Connected)
{
listener.Shutdown(SocketShutdown.Both);
listener.Close();
listener = null;
}
}
//release unmanaged resource;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Server()
{
Dispose(false);
}
#endregion
}
}
ServerFactory.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace MySocket
{
///
/// ServerFactory
///
public class ServerFactory
{
protected static readonly object _lock = new object();
static protected Server instance = null;
private string strIpAddress;
private int port;
private int bufferSize;
///
/// Server IpAddress
///
public string StrIpAddress { get { return strIpAddress; } set { strIpAddress = value; } }
///
/// Port
///
public int Port { get { return port; } set { port = value; } }
///
/// BufferSize
///
public int BufferSize { get { return bufferSize; } set { bufferSize = value; } }
///
/// ServerFactory
///
private ServerFactory()
{
try
{
strIpAddress = ConfigurationManager.AppSettings["ServerIpAddress"];
port = int.Parse(ConfigurationManager.AppSettings["ServerSocketPort"]);
bufferSize = int.Parse(ConfigurationManager.AppSettings["ServerSocketBufferSize"]);
instance = new Server(strIpAddress, port, bufferSize);
instance.Backlog = 100;
}
catch (Exception e)
{
//AsgwExceptionHandler.Write(tmpEx);
throw new Exception("Socket Server param must be configured in the config file!", e);
}
}
///
/// CreateInstance,return the sington server
///
///
public static Server CreateInstance()
{
if (instance == null)
{
lock (_lock)
{
if (instance == null)
{
new ServerFactory();
}
}
}
return instance;
}
}
}
Session.cs
using System;
using System.Collections.Generic;
using System.Text;
using System.Net.Sockets;
using System.Diagnostics;
using System.Threading;
namespace MySocket
{
public class Session
{
int id;
Socket socket;
private bool _shuttingDown = false;
private object _syncObject = new object();
byte[] buffer ;//pre received data buffer.
private int bufferSize; //pre received data buffer size.
internal Session(int id, Socket socket, int bufferSize)
{
this.socket = socket;
this.id = id;
this.bufferSize=bufferSize;
buffer=new byte[this.bufferSize];
}
public Socket Socket { get { return socket; } set { socket = value; } }
internal byte[] Buffer { get { return buffer; } set { buffer = value; } }
internal int ID { get { return id; } private set { id = value; } }
internal event EventHandler AfterReceivedData;
internal event BeforeSendDataEventHandler BeforeSendData;
internal event EventHandler SessionTerminated;
///
/// BeginReceiveData
///
internal void BeginReceiveData()
{
try
{
lock (_syncObject)
{
if (false == _shuttingDown)
{
AsyncCallback recieveData = new AsyncCallback(RecievedDataCallBack);
socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, recieveData, socket);
Trace.WriteLine("buffer:" + Encoding.Default.GetString(buffer));
}
else
{
//may be here will some error, but i can't test it out.
socket.Close();
}
}
}
catch (Exception ex)
{
Trace.WriteLine("Recieve callback setup failed! {0}", ex.Message);
}
}
internal void RecievedDataCallBack(IAsyncResult ar)
{
if (false == _shuttingDown)
{
//GetReceivedData,call EndReceive
byte[] aryRet = GetReceivedData(ar);
// If no data was recieved then the connection is probably dead
if (aryRet.Length < 1)
{
//call the methos, call the socket.Close(),in the CloseTheSocket() fun, just call the delegate
CloseTheSocket();
return;
}
// data is received
//if BeforeSendData is not null, when a received data is got ,it will send a back msg.
// you can set the send data in your code by set the methos 'BeforeSendData'
if (BeforeSendData != null)
BeginSendData(aryRet);
//if AfterReceivedData is not null,will call the dalegate,in the delegate,it will begin to receive data again.loop.
if (AfterReceivedData != null)
AfterReceivedData(this, new AfterReceivedDataEventArgs(aryRet));
}
}
///
/// call the socket.Close(),in the CloseTheSocket() fun, just call the delegate in server.
///
private void CloseTheSocket()
{
Trace.WriteLine(string.Format("Client {0}, CloseTheSocket", socket.RemoteEndPoint));
if (SessionTerminated != null)
SessionTerminated(this, new SessionTerminateEventArgs(this));
}
///
/// GetReceivedData,
///
///
///
internal byte[] GetReceivedData(IAsyncResult ar)
{
int nBytesRec = 0;
try
{
nBytesRec = socket.EndReceive(ar);
}
catch (Exception e)
{ // if some network problem happen, EndReceive will throw,ie:SocketException. here not care them,just call CloseTheSocket.
Trace.WriteLine("EndReceive:" + e.Message);
CloseTheSocket();
}
// accord to the actual received data length,copy the buffer to new.buffer,then return it.
byte[] byReturn = new byte[nBytesRec];
Array.Copy(buffer, byReturn, nBytesRec);
Trace.WriteLine("byReturn:" + Encoding.Default.GetString(byReturn));
return byReturn;
}
///
/// BeginSendData
///
/// the beginreceived() methos got
internal void BeginSendData(byte[] data)
{
byte[] dataWillSend = data;
lock (_syncObject)
{
if (false == _shuttingDown)
{
if (socket != null & socket.Connected)
{
try
{
//BeforeSendData is not null ,it will set the data before send.
if (BeforeSendData != null)
dataWillSend = BeforeSendData(this, new BeforeSendDataEventArgs(data));
AsyncCallback sendData = new AsyncCallback(SentDataCallBack);
socket.BeginSend(dataWillSend, 0, dataWillSend.Length, SocketFlags.None, sendData, socket);
}
catch (Exception ex)
{
Trace.WriteLine("Send Message Failed! " + ex.Message);
}
}
else
{
Trace.WriteLine("Send message failed, socket is null or nonconnected.");
}
}
else
{
Trace.WriteLine("Send message failed, socket is shutting down.");
}
}
}
///
/// SentDataCallBack
///
///
protected void SentDataCallBack(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
int nBytes = sock.EndSend(ar);
Trace.WriteLine("data is sent,length is" + nBytes);
}
catch (Exception ex)
{
////if Exception happen,ie:SocketException,close the socket.
CloseTheSocket();
Trace.WriteLine("EndSend error" + ex.Message);
}
}
///
/// set the _shuttingDown flag,
/// close the socket.
///
internal void Close()
{
lock (_syncObject)
{
_shuttingDown = true;
}
if (socket != null && socket.Connected)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
}
}
client 段的代码:
app.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="ServerIpAddress" value="10.13.12.15"/>
<add key="ServerSocketPort" value="399"/>
<add key="ClientSocketBufferSize" value="100"/>
<add key="ClientSocketInterval" value="20000"/> <!--以毫秒为单位-->
</appSettings>
</configuration>
Program.cs:
using System;
using System.Collections.Generic;
using System.Text;
using SocketClient;
using System.Diagnostics;
using System.Threading;
namespace ClientConsole
{
class Program
{
public static void Main()
{
Console.WriteLine("Main starting ");
//test();
test2();
Console.ReadLine();
}
public static void test()
{
Client c1 = ClientFacotry.CreateInstance();
c1.AfterReceivedData += new EventHandler(c_AfterReceivedData);
c1.AfterRetyrFailed += new EventHandler(c_AfterRetyrFailed);
while (true)
{
Console.WriteLine("input string(\r\n1:start , \r\n2:send ,\r\n3:close ,\r\n4 nonstop sendata(close the app to stop): ");
string inputstr = "";
inputstr = Console.ReadLine();
if (inputstr == "0")
break;
else if (inputstr == "1")
{
c1.OnStart();
}
else if (inputstr == "2")
{
Console.WriteLine("input send strings: ");
string inputsendstr = Console.ReadLine();
byte[] data = Encoding.Default.GetBytes(inputsendstr);
c1.BeginSendData(data);
}
else if (inputstr == "3")
{
c1.OnStop();
}
else if (inputstr == "4")
{
while (true)
{
Thread.Sleep(1000);
DateTime now=DateTime.Now;
string str= "<" +now.Minute.ToString()+"-"+now.Second.ToString()+"-"+ now.Millisecond + ">";
c1.BeginSendData(Encoding.Default.GetBytes(str));
}
}
}
}
static void test2()
{
for(int i=0;i<10;i++)
{
Thread t = new Thread(setclient);
t.Name = "thread-" + i + "<" + DateTime.Now.ToLongTimeString()+">";
Thread.Sleep(i*1000);
t.Start(" ["+t.Name + "] "+DateTime.Now.ToLongDateString());
}
}
static void setclient(object data)
{
Client c1 = ClientFacotry.CreateInstance();
c1.AfterReceivedData += new EventHandler(c_AfterReceivedData);
c1.AfterRetyrFailed += new EventHandler(c_AfterRetyrFailed);
c1.OnStart();
while (true)
{
int secnd=DateTime.Now.Second;
string str = data.ToString() + " sleep: " + secnd+" ";
Thread.Sleep(secnd * 1000);
c1.BeginSendData(Encoding.Default.GetBytes(str));
}
}
static void c_AfterRetyrFailed(object sender, AfterReTryFailedEventArgs e)
{
//e.Client.Dispose();
Trace.WriteLine("retry failed, object disposed");
}
static void c_AfterReceivedData(object sender, AfterReceivedDataEventArgs e)
{
string s = Encoding.Default.GetString(e.Data);
Trace.WriteLine("Received data:" + s);
}
}
}
ClientFacor
using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
namespace SocketClient
{
///
/// ClientFacotry ,create socket client
///
public class ClientFacotry
{
protected static readonly object _lock = new object();
static protected ClientFacotry instance = null;
private string strServerIpAddress;
private int serverPort;
private int bufferSize;
private int clientInterval;
///
/// StrServerIpAddress
///
public string StrServerIpAddress { get { return strServerIpAddress; } set { strServerIpAddress = value; } }
///
/// ServerPort
///
public int ServerPort { get { return serverPort; } set { serverPort = value; } }
///
/// BufferSize
///
public int BufferSize { get { return bufferSize; } set { bufferSize = value; } }
///
/// ClientInterval
///
public int ClientInterval { get { return clientInterval; } set { clientInterval = value; } }
///
/// ClientFacotry
///
private ClientFacotry()
{
try
{
strServerIpAddress = ConfigurationManager.AppSettings["ServerIpAddress"];
serverPort = int.Parse(ConfigurationManager.AppSettings["ServerSocketPort"]);
bufferSize = int.Parse(ConfigurationManager.AppSettings["ClientSocketBufferSize"]);
clientInterval = int.Parse(ConfigurationManager.AppSettings["ClientSocketInterval"]);
}
catch (Exception e)
{
//AsgwExceptionHandler.Write(tmpEx);
throw new Exception("Socket Client param must be configured in the config file!", e);
}
}
///
/// CreateInstance,return a new client
///
///
public static Client CreateInstance()
{
if (instance == null)
{
lock (_lock)
{
if (instance == null)
{
instance=new ClientFacotry();
}
}
}
if (instance != null)
{
Client client = new Client(instance.strServerIpAddress, instance.serverPort, instance.bufferSize, instance.clientInterval);
return client;
}
return null;
}
}
}
Client.cs
using System.Net;
using System.Net.Sockets;
using System.Text;
using System;
using System.Threading;
namespace SocketClient
{
///
/// Socket client,send data to server.
///
public class Client:IDisposable
{
private Socket socket;
private byte[] byBuff;//this buff is used for received.
int receivedBufferSize; //pre received buffer length.
private string strServerIPAddress;
private int port;
private IPEndPoint epServer;
static AutoResetEvent timerWaitHandle = new AutoResetEvent(false);
private Timer tryTimer;
private int elapsedTime;
private bool tryTimeOutTerminationInitiated = false;
private const int TRY_TIME_OUT = 5;
private int timerInterval = 1000;//毫秒
private bool enableTimeOut = false;
private ManualResetEvent SendDataWaitHandle = new ManualResetEvent(false);
private bool disposed = false;
private object _syncObject = new object();
public event EventHandler AfterReceivedData;
public event EventHandler AfterRetyrFailed;
public Socket Socket { get { return socket; } set { socket = value; } }
public string StrServerIPAddress { get { return strServerIPAddress; } set { strServerIPAddress = value; } }
public int Port { get { return port; } set { port = value; } }
public Timer TryTimer { get { return tryTimer; } set { tryTimer = value; } }
///
/// new a client object
///
/// ipAddress string type
/// port
/// pre receive data buffer size.
/// the timer that loop to connect to server if server is not avalible.(毫秒为单位)
public Client(string ipAddress,int port,int receivedBufferSize,int timerInterval)
{
try
{
this.strServerIPAddress = ipAddress;
this.port = port;
this.receivedBufferSize = receivedBufferSize;
this.byBuff = new byte[receivedBufferSize];
this.timerInterval = timerInterval;
}
catch (Exception ex)
{
Trace.WriteLine("Server Connect failed! error: "+ex.Message);
}
}
///
/// SocketConneted or not
///
private bool IsSocketConneted
{
get
{
lock (_syncObject)
{
return this.socket!=null && this.socket.Connected ;
}
}
}
///
/// OnStart, start the client to connetced.
///
public void OnStart()
{
Timer Timer = null;
AutoResetEvent tmrWtHdlr = null;
lock (_syncObject)
{
tmrWtHdlr = timerWaitHandle;
Timer = tryTimer;
elapsedTime = 0;
tryTimeOutTerminationInitiated = false;
disposed = false;
SendDataWaitHandle.Reset();
}
if (tmrWtHdlr != null)
{
Timer = new Timer(
new TimerCallback(this.TimerCallback), tmrWtHdlr,
0, this.timerInterval);
}
lock (_syncObject)
{
tryTimer = Timer;
timerWaitHandle = tmrWtHdlr;
}
}
///
/// BeginConnectToServer
///
protected void BeginConnectToServer()
{
try
{
//if the socket is open ,then closed it first.
if (socket != null && socket.Connected)
{
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
epServer = new IPEndPoint(IPAddress.Parse(strServerIPAddress), port);
socket.Blocking = true;
AsyncCallback onconnect = new AsyncCallback(OnConnect);
socket.BeginConnect(epServer, onconnect, socket);
}
catch (Exception ex)
{
Trace.WriteLine("Connect error: " + ex.Message);
}
}
protected void OnConnect(IAsyncResult ar)
{
// Socket was the passed in object
Socket sock = (Socket)ar.AsyncState;
Trace.WriteLine("OnConnect called");
// Check if we were sucessfull
try
{
//sock.EndConnect(ar);
if (sock.Connected)
{
//begin to received.
SetupRecieveCallback(sock);
lock (_syncObject)
{
this.elapsedTime = 0;
this.tryTimeOutTerminationInitiated = false;
SendDataWaitHandle.Set();
}
}
else
{
SendDataWaitHandle.Reset();
Trace.WriteLine("Unable to connect to remote machine, Connect Failed!, it will try again");
}
}
catch (SocketException sex)
{
Trace.WriteLine("SocketException:" + sex.Message);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message + " \r\nUnusual error during Connect!");
}
}
///
/// SetupRecieveCallback
///
///
protected void SetupRecieveCallback(Socket sock)
{
try
{
AsyncCallback recieveData = new AsyncCallback(OnRecievedData);
sock.BeginReceive(byBuff, 0, byBuff.Length, SocketFlags.None, recieveData, sock);
Trace.WriteLine("byBuff:" + Encoding.Default.GetString(byBuff));
}
catch (Exception ex)
{
Trace.WriteLine("Setup Recieve Callback failed: "+ex.Message);
}
}
protected void OnRecievedData(IAsyncResult ar)
{
Trace.WriteLine("EndReceive called");
if (false == disposed)
{
// Socket was the passed in object
Socket sock = (Socket)ar.AsyncState;
int nBytesRec = 0;
// Check if we got any data
try
{
try
{
nBytesRec = sock.EndReceive(ar);
}
catch (SocketException ex)
{
//for some network problem,the socket will throw the SocketException,
//if Exception happen,ie:SocketException,close the socket.
CloseSocket();
Trace.WriteLine("EndReceive:" + ex.Message);
}
//Trace.WriteLine("sock.RemoteEndPoint:" + sock.RemoteEndPoint.ToString());
if (nBytesRec < 1)
{
// If no data was recieved then the connection is probably dead
Trace.WriteLine(string.Format("Client {0}, disconnected", sock.RemoteEndPoint));
CloseSocket();
return;
}
byte[] byReturn = new byte[nBytesRec];
Array.Copy(byBuff, byReturn, nBytesRec);
Trace.WriteLine("byReturn:" + Encoding.Default.GetString(byReturn));
OnAfterReceivedData(this, new AfterReceivedDataEventArgs(byReturn));
// If the connection is still usable restablish the callback
SetupRecieveCallback(sock);
}
catch (Exception ex)
{
Console.WriteLine("Unusual error druing Recieve :" + ex.Message);
}
}
}
///
/// OnAfterReceivedData, you can override in your sub class
///
///
///
protected virtual void OnAfterReceivedData(object sender, AfterReceivedDataEventArgs e)
{
if (AfterReceivedData != null)
AfterReceivedData(sender, e);
}
///
/// OnAfterRetryFailed, you can override in your sub class
///
///
///
protected virtual void OnAfterRetryFailed(object sender, AfterReTryFailedEventArgs e)
{
if (AfterRetyrFailed != null)
AfterRetyrFailed(sender, e);
}
///
/// SendData
///
///
public void BeginSendData(byte[] data)
{
//before the connect is establish,wait..
SendDataWaitHandle.WaitOne();
if (null != data && data.Length > 0)
{
if (IsSocketConneted)
{
try
{
// Convert to byte array and send.
AsyncCallback sendData = new AsyncCallback(OnSentData);
Byte[] byteDateLine = data;
socket.BeginSend(byteDateLine, 0, byteDateLine.Length, SocketFlags.None, sendData, socket);
Trace.WriteLine("will send data:" + Encoding.Default.GetString(byteDateLine) + " , length will be: " + byteDateLine.Length);
}
catch (Exception ex)
{
Trace.WriteLine(ex.Message + " \r\nSend Message Failed!");
}
}
else
{
Trace.WriteLine("Must be connected to Send a message");
}
}
}
protected void OnSentData(IAsyncResult ar)
{
Socket sock = (Socket)ar.AsyncState;
try
{
int nBytes = sock.EndSend(ar);
Trace.WriteLine("sent data actual legth:" + nBytes);
}
catch (Exception ex)
{
//if Exception happen,ie:SocketException,close the socket.
CloseSocket();
Trace.WriteLine("EndSend error" + ex.Message);
}
}
///
/// OnStop , call Dispose.
///
public void OnStop()
{
Dispose();
}
///
/// CloseSocket
///
protected void CloseSocket()
{
if (socket != null && socket.Connected)
{
//below will close the socket,first blok the SendData method.
SendDataWaitHandle.Reset();
//close the socket
socket.Shutdown(SocketShutdown.Both);
socket.Close();
Trace.WriteLine("socket shutting down");
//socket = null;
}
//clean the buffer
}
private int tc = 0;
private void TimerCallback(Object obj)
{
bool tryTimeOutTerminationInitiated;
// AutoResetEvent tmrWtHdlr = null;
int elapsedTime = 0;
bool shuttingDown;
bool socketConnected;
lock (_syncObject)
{
elapsedTime = this.elapsedTime;
//tmrWtHdlr = timerWaitHandle;
tryTimeOutTerminationInitiated = this.tryTimeOutTerminationInitiated;
shuttingDown = this.disposed;
socketConnected = IsSocketConneted;
}
int Id = Interlocked.Increment(ref tc);
Trace.WriteLine(Id.ToString()+" : socketConnected:" + socketConnected.ToString());
if (false == shuttingDown)
{
if (!socketConnected)
{
elapsedTime += 1;
Trace.WriteLine("elapsedTime:" + elapsedTime.ToString());
if (!tryTimeOutTerminationInitiated)
{
if (enableTimeOut && elapsedTime >= TRY_TIME_OUT)
{
tryTimeOutTerminationInitiated = true;
//close socket
CloseSocket();
//clean the timer,if time out,stop the timer.
if (tryTimer != null)
tryTimer.Dispose();
//you can do something after time out failed.
OnAfterRetryFailed(this, new AfterReTryFailedEventArgs(this));
}
else
{
// retry connect
BeginConnectToServer();
}
}
}
}
lock (_syncObject)
{
this.elapsedTime = elapsedTime;
//timerWaitHandle = tmrWtHdlr;
this.tryTimeOutTerminationInitiated = tryTimeOutTerminationInitiated;
}
}
#region IDisposable Members
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
lock (this)
{
disposed = true;
if (disposing)
{
Trace.WriteLine("disposing..");
//release managed resource
CloseSocket();
//clean the timer
if (tryTimer != null)
tryTimer.Dispose();
}
//release unmanaged resource;
//...
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
~Client()
{
Dispose(false);
}
#endregion
private class Trace
{
public static void WriteLine(string msg)
{
string threadname = Thread.CurrentThread.Name;
// Console.WriteLine(threadname+"->"+msg);
System.Diagnostics.Trace.WriteLine(msg);
}
}
}
}
EventArgs.cs:
using System;
using System.Collections.Generic;
using System.Text;
namespace SocketClient
{
public class AfterReceivedDataEventArgs:EventArgs
{
byte[] data;
public byte[] Data { get { return data; } set { data = value; } }
public AfterReceivedDataEventArgs(byte[] data)
{
this.data = data;
}
}
public class AfterReTryFailedEventArgs:EventArgs
{
Client client;
public Client Client { get { return client; } set { client = value; } }
public AfterReTryFailedEventArgs(Client client)
{
this.client = client;
}
}
}
下载地址:
http://download.csdn.net/source/479391
个人感觉这个dispose 接口 不知道是否真的把资源释放干净了,代理的 -= 是否把所有的代理都清理了,还有其他很多问题,自己仅仅是很简单的测了一下。 希望高人给点意见。
感觉自己还有很多不足的地方,诚心希望大家给点批评意见。(csdn这个编辑器好垃圾,我插入了c# 代码,怎么还没有变色,全是白底黑字。非要自己开发修改blog,但又搞的这么差劲,就知道到处嵌广告)
发表于 @ 2008年06月02日 10:27:00|评论(loading...)