none
Server Socket Keep-Alive封包問題 RRS feed

  • 問題

  • 各位好,小弟初次接觸C#程式語言,再開發C# SOCKET程式。

    目前透過微軟的非同步範例,Server和Client可以正常連線。

    現在我要讓Server可以知道Client是否已經斷線了,我做法是Client正常斷線時會發送一個訊息跟Server說斷線了。

    但是如果Client是不正常斷線時(例如:拔網路線),Server會不知道對方已經斷線。

    經網路查詢之後,大家推薦用keep-alive方法,但我在Server設置keep-alive之後,用wireshark看封包時確定有再發送keep-alive,可是我Server寫了一個Receive來收這個封包,卻無法讀取到這個封包。

    想請問一下是兩端都要設置keep-alive才有辦法收到嗎?

    另外想問一個問題是,我要如何知道keep-alive這個封包是誰送的? 需要把它封包解析出來?

    附上我Server的程式:

    namespace AsynServer
    {
        public static class AsynchronousSocketListener
        {
        	
    
        	private static int port;
        	private static byte[] buffer = new byte[128];
    	private const int BufferSize = 128;
    
        	private static ManualResetEvent allDone = new ManualResetEvent(false);
        	public static Socket handle;
        	public static IList<Socket> Clients = new List<Socket>();
        	public static List<byte> Reply = new List<byte>();
    
        	public static void StartListening()
            {
                IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, port);
                Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
                try
                {
                    listener.Bind(localEndPoint);
                }
                catch (SocketException ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }
    
                listener.Listen(100);
                listener.IOControl(IOControlCode.KeepAliveValues, KeepAliveSetting(1, 10000, 10000), null);
                
                while (true)
                {
                    allDone.Reset();
                    listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
                    allDone.WaitOne();
                }
            }
            private static byte[] KeepAliveSetting(int onOff, int keepAliveTime, int keepAliveInterval)
            {
                byte[] buffer = new byte[12];
                BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
                BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
                BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
                return buffer;
            }
    
            private static void AcceptCallback(IAsyncResult ar)
            {
                Socket listener = (Socket)ar.AsyncState;
                handle = listener.EndAccept(ar);
                handle.BeginReceive(buffer2, 0, BufferSize, 0, new AsyncCallback(ReceiveCallBack), handle);                    
                Clients.Add(handle);            
                allDone.Set();
            }
    
            private static void ReceiveCallBack(IAsyncResult ar)
            {
                Socket state = (Socket)ar.AsyncState;           
                if (state.Connected == true)
                {
                    try
                    {
                        int byteRead = state.EndReceive(ar);
                        if(byteRead > 0)
                        {                                             
                            for(int i = 0;i< byteRead; i++)
                            {
                                Reply.Add(buffer[i]);                            
                            }                        
                            state.BeginReceive(buffer, 0, BufferSize, 0, new AsyncCallback(ReceiveCallBack), handle);
                        }                    
                    }
                    catch
                    {
                        state.Shutdown(SocketShutdown.Both);
                       	state.Close();
                    }
                }            
            }
        }
    }    

    2017年8月7日 上午 07:20

解答

  • 試看看下面的範例

    public class ServerSocketObject
    {
        public  Socket ClientToServerSocket;
        private Socket ListenSocket;
        private IPEndPoint ServerIPEndPoint;
        public ManualResetEvent BeginAccpetControl=new ManualResetEvent(false);
        //==========================
        private Boolean IsBeginAccept = true ;
        public List<byte> Reply_Message = new List<byte>();

        public ServerSocketObject()
        {
            string LocalIP = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
            ServerIPEndPoint = new IPEndPoint(IPAddress.Parse(LocalIP), 2266); 
            ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ListenSocket.Bind(ServerIPEndPoint);
            ListenSocket.Listen(1);
            ListenSocket.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 1000, 1000), null);  

        }

        private byte[] KeepAlive(int onOff, int keepAliveTime, int keepAliveInterval)
        {
            byte[] buffer = new byte[12];
            BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
            BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
            BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
            return buffer;
        }

        public void BeginAccept()
        {
            while (IsBeginAccept)
            {
                BeginAccpetControl.Reset();
                ListenSocket.BeginAccept(new AsyncCallback(BeginAcceptCallBack), ListenSocket);
                BeginAccpetControl.WaitOne();
            }
        }

        private void BeginAcceptCallBack(IAsyncResult state)
        {
            Socket Listener = (Socket)state.AsyncState;
            ClientToServerSocket = Listener.EndAccept(state);
            ClientToServerSocket.BeginReceive(buffer, 0, BufferSize, 0, new AsyncCallback(ReceivedCallBack), ClientToServerSocket);  
            BeginAccpetControl.Set();
        }

        private void ReceivedCallBack(IAsyncResult ar)
        {
            Socket state = (Socket)ar.AsyncState;
            if (state.Connected == true)
            {
                try
                {
                    int bytesRead = state.EndReceive(ar);
                    if (bytesRead > 0)
                    {
                        for (int num = 0; num < bytesRead; num++)
                        {
                            Reply_Message.Add(buffer[num]);
                        }
                        state.BeginReceive(buffer, 0, BufferSize, 0, new AsyncCallback(ReceivedCallBack), ClientToServerSocket);
                    }
                    else
                    {
                        //處理Client端斷線的事件
                    }
                }
                catch (Exception ee)
                {
                    state.Shutdown(SocketShutdown.Both);
                    state.Close();
                }
            }
            else
            {
                IsConntect = false;
                state.Close();
            }
        }
    }

    2017年8月8日 上午 10:42

所有回覆

  • Keep-alive只有在沒有傳送任何資料時才會傳送, 請參考:

    How to detect a Socket Disconnect in C#

    2017年8月8日 上午 12:32
  • 試看看下面的範例

    public class ServerSocketObject
    {
        public  Socket ClientToServerSocket;
        private Socket ListenSocket;
        private IPEndPoint ServerIPEndPoint;
        public ManualResetEvent BeginAccpetControl=new ManualResetEvent(false);
        //==========================
        private Boolean IsBeginAccept = true ;
        public List<byte> Reply_Message = new List<byte>();

        public ServerSocketObject()
        {
            string LocalIP = Dns.GetHostByName(Dns.GetHostName()).AddressList[0].ToString();
            ServerIPEndPoint = new IPEndPoint(IPAddress.Parse(LocalIP), 2266); 
            ListenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            ListenSocket.Bind(ServerIPEndPoint);
            ListenSocket.Listen(1);
            ListenSocket.IOControl(IOControlCode.KeepAliveValues, KeepAlive(1, 1000, 1000), null);  

        }

        private byte[] KeepAlive(int onOff, int keepAliveTime, int keepAliveInterval)
        {
            byte[] buffer = new byte[12];
            BitConverter.GetBytes(onOff).CopyTo(buffer, 0);
            BitConverter.GetBytes(keepAliveTime).CopyTo(buffer, 4);
            BitConverter.GetBytes(keepAliveInterval).CopyTo(buffer, 8);
            return buffer;
        }

        public void BeginAccept()
        {
            while (IsBeginAccept)
            {
                BeginAccpetControl.Reset();
                ListenSocket.BeginAccept(new AsyncCallback(BeginAcceptCallBack), ListenSocket);
                BeginAccpetControl.WaitOne();
            }
        }

        private void BeginAcceptCallBack(IAsyncResult state)
        {
            Socket Listener = (Socket)state.AsyncState;
            ClientToServerSocket = Listener.EndAccept(state);
            ClientToServerSocket.BeginReceive(buffer, 0, BufferSize, 0, new AsyncCallback(ReceivedCallBack), ClientToServerSocket);  
            BeginAccpetControl.Set();
        }

        private void ReceivedCallBack(IAsyncResult ar)
        {
            Socket state = (Socket)ar.AsyncState;
            if (state.Connected == true)
            {
                try
                {
                    int bytesRead = state.EndReceive(ar);
                    if (bytesRead > 0)
                    {
                        for (int num = 0; num < bytesRead; num++)
                        {
                            Reply_Message.Add(buffer[num]);
                        }
                        state.BeginReceive(buffer, 0, BufferSize, 0, new AsyncCallback(ReceivedCallBack), ClientToServerSocket);
                    }
                    else
                    {
                        //處理Client端斷線的事件
                    }
                }
                catch (Exception ee)
                {
                    state.Shutdown(SocketShutdown.Both);
                    state.Close();
                }
            }
            else
            {
                IsConntect = false;
                state.Close();
            }
        }
    }

    2017年8月8日 上午 10:42