1
\$\begingroup\$

I'm very new to networking, so I've been trying to develop my own server and client to use with Unity. I did some copy and pasting to learn the basics, but now I'm trying to get a real grasp of how to accomplish what I am looking for. As for now, I just want to connect a client to a server (UDP), and get a confirmation that it is working before I continue.

My current issue is this: Unity crashes immediately upon running the game.

Server:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Server
{
    private const int port = 8080;

    public static int Main()
    {
        //bool done = false;
        UdpClient listener = new UdpClient(port);
        IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port);
        string receivedData;
        byte[] receivedBytes;

        try
        {
                Console.WriteLine("Waiting for broadcast...");
                receivedBytes = listener.Receive(ref groupEP);

                Console.WriteLine("Receiving broadcast from: {0}", groupEP.ToString());

                receivedData = Encoding.ASCII.GetString(receivedBytes, 0, receivedBytes.Length);
                Console.WriteLine("Data follow\n{0}\n\n", receivedData);
        }

        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
        }
        listener.Close();
        return 0;
    }
}

Client:

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;

public class Client
{
    public static void Main()
    {
        //Boolean done = false;
        Boolean exception_Thrown = false;

        Socket sending = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);

        IPAddress sendTo = IPAddress.Parse("192.168.1.127");

        IPEndPoint sendEndPoint = new IPEndPoint(sendTo, 8080);

        Console.WriteLine("Enter text to broadcast");
        Console.WriteLine("Enter a blank line to exit the program");


        string sendText = "Success!";
        /*
        if (sendText.Length == 0)
        {
            done = true;
        }

        else
        {
        */
            byte[] sendBuffer = Encoding.ASCII.GetBytes(sendText);
            Console.WriteLine("Send to address: {0}, port: {1}", sendEndPoint, sendEndPoint.Port);

            try
            {
                sending.SendTo(sendBuffer, sendEndPoint);
            }

            catch (Exception send_Exception)
            {
                exception_Thrown = true;
                Console.WriteLine("Exception {0}", send_Exception);
            }

            if (!(exception_Thrown))
            {
                Console.WriteLine("Message has been sent to the broadcast address");
            }

            else
            {
                exception_Thrown = false;
                Console.WriteLine("The exception indicates the message was not sent");
            }
        //}
    }
}

The script I'm going to use to call the other scripts without MonoBehaviour:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;

public class ServerManager : MonoBehaviour
{
    private GameObject netGameObject;
    private Server serverScript;
    private Client clientScript;
    //private float timer = 0.0f;
    //private float nextServerUpdate = 2.0f;
    //private bool runUpdate = true;
    //private bool s = false;

    // Start is called before the first frame update
    void Start()
    {
        netGameObject = this.gameObject;
        serverScript = new Server();
        clientScript = new Client();
        StartCoroutine(ServerUpdate(2f));
        //Server.Main();
        //Client.Main();
    }
    /*
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKey(KeyCode.Y))
        {
            s = true;
        }
    }
    */
    private IEnumerator ServerUpdate(float waitTime)
    {
        while (true)
        {
            Server.Main();
            Debug.Log("Working");
            yield return new WaitForSeconds(waitTime);
        }
    }
}

I've been toying with various things for a while now, and I really need some help.

Things I've tested:

  1. The coroutine freezes as soon as it hits Server.Main().
  2. DIY timers react the same as coroutine.
  3. while(true) loop in coroutine doesn't appear to make a difference.
  4. Server.Main() freezes even from start or awake, with all loops that I can find removed.
  5. Client.Main() gives me the exact same problems.

Just a note: I have been avoiding Unity's built in systems (UNET and the like) because networking is something I would really like to learn to manage for myself, where I could use it outside of Unity as well.

\$\endgroup\$
1
\$\begingroup\$

Checking the docs on UdpClient.Receive:

The Receive method blocks execution until it receives a message.

From what we can see in this sample, you don't have any code here that sends a message. So Receive will wait forever, halting your game from updating, processing input, rendering - a hard freeze.

You likely want to either:

  • put this on its own thread so your game can continue to update while waiting for the next message (coroutines are not threads: they execute synchronously on the main thread, taking turns with the rest of your code)

    See how not to freeze the main thread in Unity

  • use UdpClient.BeginReceive to listen for messages asynchronously, getting an AsyncCallback call when the next message arrives

There are other issues with this code that I'd recommend reconsidering as you refactor to solve this lock:

  • your Server & Client Main methods construct new listeners / sockets for every message, then immediately discard them, instead of keeping a channel open and reusing it

  • you seem to be missing a call to dispose of your Socket once you're done with it.

  • you construct instances of both Server and Client, but both have only static members

\$\endgroup\$
  • \$\begingroup\$ So far I've: 1. Put both Client and Server on their own threads, as well as used BeginReceive() for the server (I used both by accident but it seems to be working? So ok for now.) 2. I re-evaluated what I need, and took the example from: <docs.microsoft.com/en-us/dotnet/api/…> until I can get a better handle on this. 3. I'm a little unclear about disposing of sockets, but I added a Close() to the Client socket. why is the static members thing an issue? No sarcasm, genuinely curious. \$\endgroup\$ – schnondle Jul 22 at 20:28
  • \$\begingroup\$ There's just no point in constructing an instance that you're not using, that's all. Similarly, there's not necessarily much benefit in having the server listener running on its own thread if you're using an asynchronous receive method anyway. \$\endgroup\$ – DMGregory Jul 22 at 20:43
  • \$\begingroup\$ Thank you, I got it working! I do have a question pertaining to how to close my socket before the application quits (not how to, but I'm having trouble with doing it before OnApplicationQuit finishes I think), but I'm not sure the best way to show you without rewriting the whole question (new to this site, sorry). I don't have twitter or facebook either, is there some other way I could show it to you? Again, thank you for the help! \$\endgroup\$ – schnondle Jul 23 at 7:30
  • \$\begingroup\$ To ask a different question, create a new question post. You don't need to show me specifically — we have thousands of users who might be able to help you. \$\endgroup\$ – DMGregory Jul 23 at 9:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.