简体   繁体   中英

Asynchronous Sockets blocking UI thread

See my previous question for some context: Asynchronous socket calls freezing UI Thread

The issue is with the client, there is no problem connecting to the server or sending but when 'OnReceive' method is called the whole client stops responding.(It doesn't stop 100% it occasionally responds but after a ridiculous response time of 30 seconds+). The rest of the calls operate fine but the UI wont respond. The server responds fine as well.

StateObject Class:

 class StateObject
    {
        // Client socket.
        public Socket workSocket = null;
        // Size of receive buffer.
        public const int BufferSize = 256;
        // Receive buffer.
        public byte[] buffer = new byte[BufferSize];
        // Received data string.
        public StringBuilder sb = new StringBuilder();
    }

OnConnect Method:

private void OnConnect(IAsyncResult ar)
        {
            StateObject state = new StateObject();
            try
            {
                Socket client = (Socket)ar.AsyncState;
                client.EndConnect(ar);
               // StateObject state = new StateObject();
                state.workSocket = client;
                //We are connected so we login into the server
                Data msgToSend = new Data();
                msgToSend.cmdCommand = Command.Login;
                msgToSend.strName = textBox2.Text;
                msgToSend.strMessage = null;

                byte[] b = msgToSend.ToByte();

                //Send the message to the server
                //HERE - Starts freezing the UI thread, continues to do background operations
                state.workSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend), state.workSocket);

                //byte[] byteBuffer = new byte[1024];
                state.workSocket.BeginReceive(state.buffer,
                                       0,
                                       state.buffer.Length,
                                       SocketFlags.None,
                                       new AsyncCallback(OnReceive),
                                       state);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            panel4.Visible = false;
            panel1.Visible = true;
        }

OnReceive Method:

public void OnReceive(IAsyncResult ar)
        {
            try
            {
                StateObject state = (StateObject)ar.AsyncState;
                Socket client = state.workSocket;
                client.EndReceive(ar);

                Data msgReceived = new Data(state.buffer);
                //Accordingly process the message received
                switch (msgReceived.cmdCommand)
                {
                    case Command.Login:
                        //lstChatters.Items.Add(msgReceived.strName);
                        break;

                    case Command.Logout:
                        //lstChatters.Items.Remove(msgReceived.strName);
                        break;

                    case Command.Message:
                        break;

                    case Command.List:
                        MessageBox.Show(msgReceived.strName);
                        //contacts.Add(msgReceived.strName);
                        needUpdate = true;
                        //lstChatters.Items.AddRange(msgReceived.strMessage.Split('*'));
                        //lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1);
                        //txtChatBox.Text += "<<<" + strName + " has joined the room>>>\r\n";

                        break;
                }

                state.buffer = new byte[256];

               /* client.BeginReceive(byteData,
                                          0,
                                          byteData.Length,
                                          SocketFlags.None,
                                          new AsyncCallback(OnReceive),
                                          client);*/

            }
            catch (ObjectDisposedException)
            { }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "SGSclientTCP: " + strName, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

        }

Whenever you try modifying something on the gui use Invoke or BeginInvoke. I tried to update your code, maybe i left something commented while I edited in vs.

private void OnConnect(IAsyncResult ar)
    {
        StateObject state = new StateObject();
        try
        {
            Socket client = (Socket)ar.AsyncState;
            client.EndConnect(ar);
            // StateObject state = new StateObject();
            state.workSocket = client;
            //We are connected so we login into the server
            Data msgToSend = new Data();
            msgToSend.cmdCommand = Command.Login;
            msgToSend.strName = textBox2.Text;
            msgToSend.strMessage = null;

            byte[] b = msgToSend.ToByte();

            //Send the message to the server
            //HERE - Starts freezing the UI thread, continues to do background operations
            state.workSocket.BeginSend(b, 0, b.Length, SocketFlags.None, new AsyncCallback(OnSend),
                state.workSocket);

            state.workSocket.BeginReceive(state.buffer,
                0,
                state.buffer.Length,
                SocketFlags.None,
                new AsyncCallback(OnReceive),
                state);
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "SGSclient", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

        //use this when you want to update the gui
        this.BeginInvoke(new MethodInvoker(() =>
        {
            //panel4.Visible = false;
            //panel1.Visible = true;
        }));

    }

    public void OnReceive(IAsyncResult ar)
    {
        String content = String.Empty;
        try
        {
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;

            // Read data from the client socket. 
            int bytesRead = handler.EndReceive(ar);

            if (bytesRead > 0)
            {
                // There  might be more data, so store the data received so far.
                state.sb.Append(Encoding.ASCII.GetString(
                    state.buffer, 0, bytesRead));

                // Check for end-of-file tag. If it is not there, read 
                // more data.
                content = state.sb.ToString();
                if (content.IndexOf("<EOF>") > -1)
                {
                    // All the data has been read from the 
                    // client. Display it on the console.
                    //do something with the data, if you update gui use BeginInvoke:

                    //all your bytes are in state.sb


                    Data msgReceived = new Data(state.buffer);
                    //Accordingly process the message received
                    switch (msgReceived.cmdCommand)
                    {
                        case Command.Login:
                            //lstChatters.Items.Add(msgReceived.strName);
                            break;

                        case Command.Logout:
                            //lstChatters.Items.Remove(msgReceived.strName);
                            break;

                        case Command.Message:
                            break;

                        case Command.List:
                            MessageBox.Show(msgReceived.strName);
                            //contacts.Add(msgReceived.strName);
                            needUpdate = true;

//Here you can use BeginInvoke or invoke   
//lstChatters.Items.AddRange(msgReceived.strMessage.Split('*'));
                    //        //lstChatters.Items.RemoveAt(lstChatters.Items.Count - 1);
                    //        //txtChatBox.Text += "<<<" + strName + " has joined the room>>>\r\n";

                    //        break;
                    //}
                }
            } else {
            // Not all data received. Get more.
            handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(OnReceive), state);
        }

        }
        catch (ObjectDisposedException)
        { }
        catch (Exception ex)
        {
            MessageBox.Show(ex.Message, "SGSclientTCP: " + strName, MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM