Baal的专栏

魔力小宝蓝---IBM---I BELIEVE MONEY

原创 socket 多线程 异步编程收藏

最近写了个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...)

新一篇: 为MMC编写服务器控制管理单元。插件方式 (MMC3.0 , installutil ,c#,KB907265,Enterprise Library) | 旧一篇: GC是如何工作的,不同的代的大小是多少

用户操作
[即时聊天] [发私信] [加为好友]
baal
订阅我的博客
XML聚合  FeedSky
订阅到鲜果
订阅到Google
订阅到抓虾
baal的公告
新势力海报网
新势力论坛
男人找乐子的网站
伟大的操作系统linux

Google


[ 新浪ViVi ] [ Poco网摘 ] [ 365KEY ] [ 博采 ] [ 亿友响享 ] [ 你摘 ] [ YouNote ] [ 天极网摘 ] [ 和讯网摘 ]

文章分类
收藏
    SEO
    SEO(RSS)
    SEO探索
    好东西
    baal自己的东西
    google相关的一个blog
    微软官方安全摘要
    民兵的家园
    存档
    软件项目交易
    Csdn Blog version 3.1a
    Copyright © baal