一步一步實現用c#編寫異步socket服務端監聽程序

此爲測試用例,正式工程中包應有包頭包尾包長crc效驗等

第一步 編輔助類

public class StateObject
    {
        public const int BUFFER_SIZE = 10240;
        public Socket workSocket;
        public byte[] buffer;
        public ArrayList tmpAl;

        public StateObject()
        {
            this.workSocket = null;
            this.buffer = new byte[BUFFER_SIZE];
        }

        ~StateObject()
        {
            this.tmpAl = null;
            this.workSocket = null;
        }
    }

 

第二步 定義變量

public static ManualResetEvent allDone = new ManualResetEvent(false);
public List<StateObject> list = new List<StateObject>();---------------------客戶端列表
private Socket serverSocket;
private SocketError errorCode;

(ManualResetEvent 允許線程通過發信號互相通信。通常,此通信涉及一個線程在其他線程進行之前必須完成的任務。當一個線程開始一個活動(此活動必須完成後,其他線程才能開始)時,它調用 Reset 以將 ManualResetEvent 置於非終止狀態,此線程可被視爲控制 ManualResetEvent。調用 ManualResetEvent 上的 WaitOne 的線程將阻止,並等待信號。當控制線程完成活動時,它調用 Set 以發出等待線程可以繼續進行的信號。並釋放所有等待線程。一旦它被終止,ManualResetEvent 將保持終止狀態(即對 WaitOne 的調用的線程將立即返回,並不阻塞),直到它被手動重置。可以通過將布爾值傳遞給構造函數來控制 ManualResetEvent 的初始狀態,如果初始狀態處於終止狀態,爲 true;否則爲 false。)

 

第三步 啓動程序

IPAddress[] addrIP = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress ip = addrIP[0];
int myprot = 36829;
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

serverSocket.Bind(new IPEndPoint(ip, myprot));
serverSocket.Listen(1000);

 

第四步 開始監聽

while (true)
{
       allDone.Reset();

       serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), serverSocket);

       allDone.WaitOne();

}

 

第五步 等待接受

public void AcceptCallback(IAsyncResult ar)
        {
                allDone.Set();
                Socket listener = (Socket)ar.AsyncState;
                Socket handler = listener.EndAccept(ar);

                uint dummy = 0;--------------------------------------------------------------------------------------判斷客戶端失去連接
                byte[] inOptionValues = new byte[Marshal.SizeOf(dummy) * 3];
                BitConverter.GetBytes((uint)1).CopyTo(inOptionValues, 0);
                BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy));
                BitConverter.GetBytes((uint)5000).CopyTo(inOptionValues, Marshal.SizeOf(dummy) * 2);
                handler.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);


                StateObject state = new StateObject();
                state.workSocket = handler;
                state.buffer = new byte[StateObject.BUFFER_SIZE];
                state.tmpAl = new ArrayList(2048);
                //加入客戶端列表
                if (!list.Contains(state))
                {
                    list.Add(state);
                }

                handler.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0, out errorCode, new AsyncCallback(ReadCallback), state);
         }

 

第六步 異步回調

public void ReadCallback(IAsyncResult ar)
       {
           string content = string.Empty;
           StateObject state = (StateObject)ar.AsyncState;
           Socket handler = state.workSocket;
           int bytesRead = 0;
            try
            {             
                bytesRead = handler.EndReceive(ar,out errorCode);
                if (errorCode == SocketError.Success)
                {
                    if (bytesRead > 0)
                    {
                        byte[] tmpbytes = new byte[bytesRead];
                        Array.Copy(state.buffer, 0, tmpbytes, 0, bytesRead);
                        state.tmpAl.AddRange(tmpbytes);


                        //如果此處接收的數據包長度大於BUFFER_SIZE,那麼就會出現數據包不齊,下一個數據包就會粘連!
                        //如果數據超過BUFFER_SIZE的大小則循環取


                        if (handler.Available > 0)
                        {
                            state.buffer = new byte[handler.Available];
                            handler.BeginReceive(state.buffer, 0, handler.Available, 0, out errorCode, new AsyncCallback(ReadCallback), state);                   
                        }
                        else
                        {
                            byte[] endreceive = new byte[state.tmpAl.Count];
                            state.tmpAl.CopyTo(endreceive);
                            state.tmpAl.Clear();
                            content = Encoding.UTF8.GetString(endreceive);
                            Array.Clear(endreceive, 0, endreceive.Length);

                           //省略處理數據

                           //發送給客戶端

                            if (!string.IsNullOrEmpty(senddata))
                                {
                                    Send(handler, senddata);
                                }
                            }
                        }
                        Array.Clear(state.buffer, 0, state.buffer.Length);
                        handler.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0, out errorCode, new AsyncCallback(ReadCallback), state);
                    }
                }
                else
                {
                    if (errorCode == SocketError.ConnectionReset)
                    {
                        if (state != null && !state.workSocket.Connected)
                        {
                            if (list.Contains(state))
                            {
                                list.Remove(state);
                            }
                        }
                    }
                }
            }
            catch(Exception ex)
            {
                handler.BeginReceive(state.buffer, 0, StateObject.BUFFER_SIZE, 0, out errorCode, new AsyncCallback(ReadCallback), state);
            }
        }

 

第七步 發送數據

   private void Send(Socket handler, String data)
        {
             byte[] byteData = Encoding.UTF8.GetBytes(data);                 

             handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
        }

        private void SendCallback(IAsyncResult ar)
        {
                Socket handler = (Socket)ar.AsyncState;
                int bytesSent = handler.EndSend(ar, out errorCode);
                if (errorCode != SocketError.Success)
                {
                }
       }

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章