user1965626
user1965626

Reputation:

Asynchronous TCPClient C# messages arent sending?

basically What I need is a p2p connection, right now I have a asynchronous server and client which is communicating between each other via TcpClients. Problem is the server rarely detects incoming messages, and usually only recieves the first message. My server code is here :

    public void RecieveAsync()
    {

        if (netStream == null) netStream = Server.GetStream();

        netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);
    }


    public void recieveCallBack(IAsyncResult ar)
    {
        //try
        //{
        int rec = netStream.EndRead(ar);
        if (rec == 0)
        {
            if (Disconnected != null)
            {
                Disconnected(this);
                return;
            }
        }
        else
        {
            if (DataRecieved != null)
            {
                string RecievedData = Encoding.ASCII.GetString(ReadBuffer, 0, rec);
                DataRecieved(RecievedData);
            }

            ReadBuffer = new byte[1024];

        }

    }

and the client code sending the data is here (Which is wrapped into a while loop sending data over and over with a Thread.Sleep(1), to update the players position )

    public void Send(byte[] data, int index, int length)
    {
        //add data as state

        //socket.NoDelay = true;

        Buffer.BlockCopy(data, 0, writeBuffer, index, length);

        if (netStream == null) netStream = TcpClient.GetStream();

        netStream.BeginWrite(writeBuffer, 0, writeBuffer.Length, sendCallback, netStream);



    }

    private void sendCallback(IAsyncResult ar)
    {
        //try
        //{
           netStream.EndWrite(ar);

            //if (ar.AsyncState != null)
            //{
            //    byte[] buffer = (byte[])ar.AsyncState;
            //    socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, sendCallback, null);
            //    return;
            //}

            if (OnSend != null)
            {
                OnSend(this);
            }

        //catch (Exception ex)
        //{
        //    System.Windows.Forms.MessageBox.Show(ex.ToString());
        //    return;
        //}
    }

The default buffer size is 1024, and RecieveAsync is only called when netStream.DataAvailible is true, which is constantly checking in the server loop.

Edit ::

This is the code which calls the server

            while (true)
            {

                byte[] playerData = NormalText(PreparePlayerData());

                server.Send(playerData, 0, playerData.Length);

                if (server.Server.Connected)
                {

                    server.netStream = server.Server.GetStream();

                    while (server.netStream.DataAvailable)
                    {
                        server.RecieveAsync();
                        server.netStream = server.Server.GetStream();
                    }

                }


                Thread.Sleep(1);

            }

Upvotes: 0

Views: 2614

Answers (1)

MarcF
MarcF

Reputation: 3299

When it comes to network programming it helps to know what is going on behind the various method. In the case of your receive method you correctly configure the callback using

netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);

This will trigger recieveCallBack() when data is received but the following line is where it starts to get interesting. It's also worth noting that a single call to netStream.BeginRead will only trigger the callback once. Should you want to continue listening for data you need to call netStream.BeginRead again.

string RecievedData = Encoding.ASCII.GetString(ReadBuffer, 0, rec);

The framework does not guarantee you will receive all of the data you write in the send. Once you have received some data you need to decide it you have everything before you try to convert it back to a string. If you have not received everything you need to make another call to

netStream.BeginRead(ReadBuffer, 0, ReadBuffer.Length, recieveCallBack, netStream);

and then wait for more.

This is a tricky aspect of programming but you are obviously well on your way. If it helps to work backwards from a working example checkout the method IncomingTCPPacketHandler() (equivalent of your recieveCallBack method) here which is from the open source network library networkcomms.net.

Upvotes: 1

Related Questions