SimpleCoder
SimpleCoder

Reputation: 33

C# - Asynchronous server vs Synchronous server - sockets

I have some weird problem with two c# server sockets.

I have 2 servers. One is asynchronous and second is synchronous. I have also client in android which sends picture to this servers.

Synchronous Server:

Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

public void Start()
{
    byte[] bytes = new Byte[1024000];
    String content = String.Empty;

    IPAddress ipAddress = IPAddress.Parse("192.168.1.2");
    IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 53100);

    try
    {
        listener.Bind(localEndPoint);
        listener.Listen(10);

        while (true)
        {
            //// Program is suspended while waiting for an incoming connection.
            Socket handler = listener.Accept();
            data = null;

            // An incoming connection needs to be processed.
            while (true)
            {
                bytes = new byte[1024000];
                int bytesRec = handler.Receive(bytes);
                strBuilder.Append(Encoding.ASCII.GetString(bytes, 0, bytesRec));
                if (strBuilder.Length > 1)
                {
                    content = strBuilder.ToString();
                    byte[] xdata = Convert.FromBase64String(content);
                    using (var mStream = new MemoryStream(xdata, 0, xdata.Length))
                    {
                        pictureBox1.Image = Image.FromStream(mStream, true);
                    }
                }
            }
            byte[] msg = Encoding.ASCII.GetBytes(data);

            handler.Send(msg);
            handler.Shutdown(SocketShutdown.Both);
            handler.Close();
        }

    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

private void Form1_Load(object sender, EventArgs e)
{
    thr = new Thread(new ThreadStart(Start));
    thr.Start();
}

Asynchronous Server:

public void StartListening()
        {
            listener.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 53100));
            listener.Listen(1);
            allDone.Reset();
            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
        }

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

            StateObject stateObj = new StateObject();
            stateObj.clientSocket = handler;
            handler.BeginReceive(stateObj.buffer, 0, StateObject.buffSize, 0, 
                new AsyncCallback(ReadCallback), stateObj);

            listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
        }

        public void ReadCallback(IAsyncResult ar)
        {
            String content = String.Empty;

            StateObject stateObj = (StateObject)ar.AsyncState;
            Socket handler = stateObj.clientSocket;

            SocketError errorCode;
            int bytesRead = handler.EndReceive(ar, out errorCode);
            if (errorCode != SocketError.Success)
            {
                bytesRead = 0;
            }

            if (bytesRead > 0)
            {
                stateObj.strBuilder.Append(Encoding.ASCII.GetString(stateObj.buffer, 0, bytesRead));
                handler.BeginReceive(stateObj.buffer, 0, stateObj.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), stateObj);
            }
            else
            {
                if (stateObj.strBuilder.Length > 1)
                {
                    content = stateObj.strBuilder.ToString();

                    Debug.WriteLine(content);
                    byte[] data = Convert.FromBase64String(content);
                    using (var mStream = new MemoryStream(data, 0, data.Length))
                    {
                        pictureBox1.Image = Image.FromStream(mStream, true);
                    }

                    recImage = (Bitmap)pictureBox1.Image;
                    imgImage = new Image<Bgr, Byte>(recImage);
                    imageBox1.Image = imgImage;

                    while (imageBox1.Image != null)
                    {
                        SURFDetectionAndGUIUpdate(this, new EventArgs());
                    }
                    string xname = name.ToString();
                    Send(handler, xname);
                }
            }
        }

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

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

        private void SendCallback(IAsyncResult ar)
        {
            try
            {
                Socket handler = (Socket)ar.AsyncState;
                int bytesSent = handler.EndSend(ar);
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

The problem is that when I send picture from client to synchronous server everything works and server receives it, but if I send picture from the same client to asynchronous server it doesn't receive it.

Upvotes: 1

Views: 1554

Answers (1)

C.Evenhuis
C.Evenhuis

Reputation: 26436

Currently your synchronous server attempts to create a bitmap from the data of the first Receive, and the asynchronous server waits until the client disconnects before trying to create a bitmap from the data.

TCP streams data, which means that you can read data as it arrives, in the order it was sent, but sending 1000 bytes doesn't mean you'll receive 1000 bytes at once. You could even receive data from two different message in a single Receive operation. The more data you send, and the more times you send data, the bigger the chance that this effect will occur.

In the comments you mention that the client is going to send multiple images, so before you continue you should decide how you want to determine when the first image is received and when data for the second image starts:

  • You could choose to let the client disconnect after sending each image, as the asynchronous server currently expects
  • You could choose to first send the number of bytes of an image, before sending the image data itself. Make sure the size itself is encoded at a fixed length. This prevents you from having to reconnect all the time, and also allows you to predetermine the size of the receive buffers
  • Or you could delimit the data using a byte outside the base64 range, but this requires scanning through the received data

Upvotes: 2

Related Questions