Search code examples
c#socketsunity-game-enginenetworkingudpclient

Send UDP data from client (Unity) and send data back to same client from server


I am making a game in Unity and i'm trying to send data from client to server and back to the client (trying to save the instances), but when i receive data and try to send data back to the client it says the udp client is not connected.

It succesfully sends data from my Unity client to the server, but once it gets there the socket gets disconnected and I cannot send anything back. As you can see i've tried to set some multicasting options but it doesn't seem to work properly.

Client:

 private void SetupConnection()
{
    try
    {
        _thread = new Thread(ReceiveData);
        _thread.IsBackground = true;
        udpClient = new UdpClient();
        udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpClient.ExclusiveAddressUse = false;
        udpClient.Client.Bind(new IPEndPoint(IPAddress.Parse(serverAdress), 32212));
        udpClient.BeginReceive(new AsyncCallback(ReceiveUdpCallback), udpClient);

        _client = new TcpClient(serverAdress, port);
        _stream = _client.GetStream();
        _thread.Start();
        isConnected = true;
    }
    catch(Exception e)
    {
        CloseConnection();
        connectionError = true;
        Debug.Log(e.ToString());
    }

}


public void ReceiveUdpCallback(IAsyncResult ar)
{
    UdpClient c = (UdpClient)ar.AsyncState;
    IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
    Byte[] receivedBytes1 = c.EndReceive(ar, ref receivedIpEndPoint);
    Debug.Log("coming in receiveudpcallback!: " + receivedBytes1);
    Dictionary<string, string> values = new Dictionary<string, string>();

    Byte[] receivedBytes;
    try
    {
        receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.StackTrace);
        return;
    }

    if (receivedBytes != null)
    {
        //byte[] dataBuffer = new byte[receivedBytesInt];
        // Array.Copy(_buffer, dataBuffer, receivedBytesInt);
        string textReceived = Encoding.ASCII.GetString(receivedBytes);
        Dictionary<string, string> data = GetDicValues(textReceived);

        HandleInputMessage(c, data);
    }
    udpClient.BeginReceive(ReceiveUdpCallback, ar.AsyncState);

}

Server:

 private void SetupServer()
    {
        Console.WriteLine("Setting up Server...");
        _serverSocket.Bind(new IPEndPoint(IPAddress.Any, 32211));
        _serverSocket.Listen(1);
        Console.WriteLine("Server is running...");
        _serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);

        IPEndPoint localpt = new IPEndPoint(IPAddress.Any, 32212);


        udpServer = new UdpClient();
        udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
        udpServer.ExclusiveAddressUse = false; // only if you want to send/receive on same machine.
        udpServer.Client.Bind(new IPEndPoint(IPAddress.Any, 32212));
        udpServer.BeginReceive(new AsyncCallback(ReceiveUdpCallback), udpServer);

public void ReceiveUdpCallback(IAsyncResult ar)
    {
        UdpClient c = (UdpClient)ar.AsyncState;
        IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
        //Byte[] receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);
        Console.WriteLine("coming in receiveudpcallback!");
        Dictionary<string, string> values = new Dictionary<string, string>();

        Byte[] receivedBytes;
        try
        {
            receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);
        }
        catch (Exception e)
        {

            Console.WriteLine(e.StackTrace);
            return;
        }

        if (receivedBytes != null)
        {
            string textReceived = Encoding.ASCII.GetString(receivedBytes);
            HandleInputMessage(c, textReceived);
        }
        else
        {

        }
        c.BeginReceive(ReceiveUdpCallback, ar.AsyncState);

    }

So the instance of the UdpClient in the server gets saved to the player, and later on in my code i try to send back to the client with the following method:

public void FlushUdp()
    {
        string msgToSend = "<opcode:" + opcode + ">";
        msgToSend += "<username:" + player.username + ">";

        foreach (KeyValuePair<string, string> entry in values)
        {
            msgToSend += "<" + entry.Key + ":" + entry.Value + ">";
        }

        byte[] bytesToSend = Encoding.ASCII.GetBytes(msgToSend);


        udpClient.Send(bytesToSend, bytesToSend.Length);

    }

EDIT:

I fixed it, I solved it by reconnecting to the server/client everytime i received a message.


Solution

  • You should call the c.EndReceive(...) only ones:

    public void ReceiveUdpCallback(IAsyncResult ar)
    {
        UdpClient c = (UdpClient)ar.AsyncState;
        IPEndPoint receivedIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
        Byte[] receivedBytes1 = c.EndReceive(ar, ref receivedIpEndPoint);   // <----------------
        Debug.Log("coming in receiveudpcallback!: " + receivedBytes1);
        Dictionary<string, string> values = new Dictionary<string, string>();
    
        Byte[] receivedBytes;
        try
        {
            receivedBytes = c.EndReceive(ar, ref receivedIpEndPoint);       // <----------------
        }
        catch (Exception e)
        {
            Console.WriteLine(e.StackTrace);
            return;
        }
    
        if (receivedBytes != null)
        {
            //byte[] dataBuffer = new byte[receivedBytesInt];
            // Array.Copy(_buffer, dataBuffer, receivedBytesInt);
            string textReceived = Encoding.ASCII.GetString(receivedBytes);
            Dictionary<string, string> data = GetDicValues(textReceived);
    
            HandleInputMessage(c, data);
        }
        udpClient.BeginReceive(ReceiveUdpCallback, ar.AsyncState);
    
    }
    

    Also the EndReceive() probably never returns null but an empty array. (receivedBytes.Length == 0). And 0 bytes return will indicate a disconnect (same like TCP)