Why am I receiving data when my Socket has disconnected? [duplicate]

左心房为你撑大大i 提交于 2021-01-29 11:58:27

问题


I'm having an issue with my Sockets. Basically I have a few listeners that listen on all the available ports on my pc. When a socket connects to one of the listeners, I open a new Socket-connection to handle that connection and my listener goes back to listening.

However when a client disconnects I keep on receiving empty data. As you can see in the code below, I have put a Console.WriteLine to check the length of the received message. When the connection closes, it's showing me well over a 100 lines with charLen: 0. Meaning it's receiving something but I don't know where it's coming from.

And then I will also receive a System.ObjectDisposedException error in the WaitData-method

        ClientSocketClass tmpClient = (ClientSocketClass)asyn.AsyncState;
        try
        {

            // END THE BeginReceive() ASYNCHRONOUS CALL BY CALLING THE EndReceive() METHOD FOR THAT SOCKET
            // THIS WILL RETURN THE NUMBER OF CHARACTER WHICH HAS BEEN RECEIVED BY THE CLIENT
            int byteMessage = tmpClient.Socket.EndReceive(asyn);

            char[] chars = new char[byteMessage + 1];

            // EXTRACT THE CHARACTERS INTO A BUFFER
            System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
            int charLen = d.GetChars(tmpClient.BufferSize, 0, byteMessage, chars, 0);

            Console.WriteLine("charlen: " + charLen.ToString());

            // START WAITING AGAIN FOR NEW DATA FROM THE CLIENT
            WaitForData(tmpClient);

            Array.Resize(ref chars, charLen);

            // PROCESS THE CURRENT MESSAGE
            string tempData = new string(chars).Replace("\0", string.Empty);

            // LOG THE RECEPTION OF NEW DATA
            string log = string.Format("{0}{1}Received: {2}", DateTime.Now.ToString("HH:mm:ss.fff"), "\t", tempData);
            Log(LoggingType.Data, LoggingLevel.Debug, log);


            // ADD THE MESSAGE TO THE MESSAGE QUEUE
            if (MessageQueue != null)
            {
                if (tempData != null && tempData != string.Empty)
                {
                    MessageQueue.Add(tempData);
                }
            }
        }
        catch (ObjectDisposedException)
        {
            // THIS CODE WILL BE EXECUTED IF THE SOCKET WAS DISCONNECTED
            if (tmpClient != null)
            {
                // GET THE ID OF THE CLIENT
                int clientId = tmpClient.Id;

                // REMOVE THE CLIENT FROM THE CONNECTED CLIENTS LISTS
                removeClient(clientId);

                string log = string.Format("{0}{1}Client {2} disconnected", DateTime.Now.ToString("HH:mm:ss.fff"), "\t", clientId);
                Log(LoggingType.Status, LoggingLevel.Notification, log);
            }

            return;
        }

Below you see the WaitForData-method:

    public void WaitForData(ClientSocketClass selectedClient)
    {
        try
        {
            if (pfnWorkerCallBack == null)
            {
                // SPECIFY THE CALL BACK FUNCTION WHICH SHOULD BE RUN
                // WHEN DATA IS RECEIVED FROM THE CLIENT
                pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
            }

            // START RECEIVING THE MESSAGE INTO THE DATA BUFFER
            selectedClient.Socket.BeginReceive(selectedClient.BufferSize, 0, selectedClient.BufferSize.Length, SocketFlags.None, pfnWorkerCallBack, selectedClient);
        }
        catch (SocketException ex)
        {
            string log = string.Format("{0}\t<WaitForData>\tAn error occured while waiting for data: {1}{2}", DateTime.Now.ToString("HH:mm:ss.fff"), ex.Message, Environment.NewLine);
            Log(LoggingType.Error, LoggingLevel.Debug, log);
        }
    }

Now I'm beginning to think that something is wrong in the way I'm handling the data in the OnDataReceived. I have been combining different tutorials I found online to get to this code, which in itself is working, only when the client disconnects I'm getting this error.

I'm hoping somebody knows why.

To be complete, below you will find the ClientSocketClass which I'm using to organise my connected clients.

    public class ClientSocketClass
    {
        private int tmpId;
        private string tmpIp;
        private byte[] tmpBuffer;
        public event PropertyChangedEventHandler PropertyChanged;

        public int Id
        {
            get { return tmpId; }
            set
            {
                tmpId = value;
                this.NotifyPropertyChanged("Id");
            }
        }


        public string Ip
        {
            get { return tmpIp; }
            set
            {
                tmpIp = value;
                this.NotifyPropertyChanged("Ip");
            }
        }

        [Browsable(false)]
        public Socket Socket { get; set; }

        [Browsable(false)]
        public byte[] BufferSize
        {
            get { return tmpBuffer; }
            set
            {
                tmpBuffer = value;
                this.NotifyPropertyChanged("BufferSize");
            }
        }

        private void NotifyPropertyChanged(string name)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }

This class is being used in a BindingList which is displayed in a DataGridView to show the connected clients. But I'm only showing the Id and the IP Address, hence the [Browsable(false)]


回答1:


I was able to find the answer here on StackOverflow (https://stackoverflow.com/a/9546493/4425684)

What I didn't realize was that WaitForData actually generated a loop and I needed to escape the loop when I was receiving NULL.

So by just adding the below code, the problem was solved.

    if (byteMessage <= 0)
    {
        // LEAVE THE LOOP
        return;
    }

After some cleanup, the new code looks like this:

    public void OnDataReceived(IAsyncResult asyn)
    {
        ClientSocketClass tmpClient = (ClientSocketClass)asyn.AsyncState;
        try
        {
            // END THE BeginReceive() ASYNCHRONOUS CALL BY CALLING THE EndReceive() METHOD FOR THAT SOCKET
            // THIS WILL RETURN THE NUMBER OF CHARACTER WHICH HAS BEEN RECEIVED BY THE CLIENT
            int byteMessage = tmpClient.Socket.EndReceive(asyn);

            // READ THE CONTENT
            string tmpContent = Encoding.UTF8.GetString(tmpClient.BufferSize, 0, byteMessage);

            // CHECK IF WE HAVE REACHED THE END OF THE RECEIVED MESSAGE
            if (byteMessage <= 0)
            {
                // LEAVE THE LOOP
                return;
            }

            // START WAITING AGAIN FOR NEW DATA FROM THE CLIENT
            WaitForData(tmpClient);


            // PROCESS THE CURRENT MESSAGE
            string tempData = tmpContent.Replace("\0", string.Empty);

            // LOG THE RECEPTION OF NEW DATA
            string log = string.Format("{0}{1}Received: {2}", DateTime.Now.ToString("HH:mm:ss.fff"), "\t", tempData);
            Log(LoggingType.Data, LoggingLevel.Debug, log);


            // ADD THE MESSAGE TO THE MESSAGE QUEUE
            if (MessageQueue != null)
            {
                if (tempData != null && tempData != string.Empty)
                {
                    MessageQueue.Add(tempData);
                }
            }
        }
        catch (ObjectDisposedException)
        {
            // THIS CODE WILL BE EXECUTED IF THE SOCKET WAS DISCONNECTED
            if (tmpClient != null)
            {
                // GET THE ID OF THE CLIENT
                int clientId = tmpClient.Id;

                // REMOVE THE CLIENT FROM THE CONNECTED CLIENTS LISTS
                removeClient(clientId);

                string log = string.Format("{0}{1}Client {2} disconnected", DateTime.Now.ToString("HH:mm:ss.fff"), "\t", clientId);
                Log(LoggingType.Status, LoggingLevel.Notification, log);
            }

            return;
        }            
    }

I do think that there's still an issue with this code, because I think that when a message is received which is larger than my buffer, the message will not be completely parsed since I'm only processing the message after the WaitForData, but I'm not completely sure.

For now the problem is solved because I have made my buffer very large, but if someone wants to correct it, please feel free.



来源:https://stackoverflow.com/questions/60695596/why-am-i-receiving-data-when-my-socket-has-disconnected

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!