1

Sorry for my poor English.

But I have some questions when I use the UdpClient in C#:

  1. In the Task function ReceiveMessage(), could I lock the udpClient for the thread safe? As the udpClient being locked, could SendMessage() run correctly in main thread?
  2. Should I refactor SendMessage() in async way to improve the performance? (I plan to send about 30 tiny msg per second)
  3. Did I stop the udpClient in the right way? udpClient.ReceiveAsync() did not provide a CancellationToken which I usually used to stop a task. Now in my code, when I close the udpClient, this task can be aborted finally. I don't know is it right or not.

Here is the code:

public class ClientSocket
{
    IPEndPoint serverEndPoint;// ServerEP
    UdpClient udpClient;// UDPSocket
    byte[] msg_buff;//buff
    Task receiveTask; //the receive Task
    bool isWait2Receiving;//is waiting
    Action<byte[]> receiveAction; //after receive callback, must be called in main thread

    /// <summary>
    /// Create One Client
    /// </summary>
    public ClientSocket(Action<byte[]> receiveAction, int buffSize = 1024)
    {
        this.receiveAction = receiveAction;
        msg_buff = new byte[buffSize];
    }

    /// <summary>
    /// Init UDP Socket
    /// </summary>
    public void StartUDP(string hostName, int port)
    {
        if (isWait2Receiving)
        {
            return;
        }

        serverEndPoint = new IPEndPoint(IPAddress.Parse(hostName), port);

        udpClient = new UdpClient();
        udpClient.Connect(serverEndPoint);
        isWait2Receiving = true;
        receiveTask = ReceiveMessage();
    }

    /// <summary>
    /// stop UDP Socket
    /// </summary>
    public void StopUDP()
    {
        if (!isWait2Receiving)
        {
            return;
        }

        udpClient.Close();
        udpClient = null;

        isWait2Receiving = false;
    }

    /// <summary>
    /// send message call in main thread
    /// </summary>
    public void SendMessage(UDPHead head, IMessage message)
    {
        byte[] headData = head.ToByteArray();
        byte[] data = message.ToByteArray();
        int size = UDPHead.headByteNum + data.Length;

        if (size > msg_buff.Length)
        {
            Debug.LogError("SendMessage prefix size or buff overflow error");
            return;
        }

        headData.CopyTo(msg_buff, 0);
        data.CopyTo(msg_buff, UDPHead.headByteNum);
        udpClient?.Send(msg_buff, size);
    }

    /// <summary>
    /// Receive Task
    /// </summary>
    private async Task ReceiveMessage()
    {
        while (isWait2Receiving)
        {
            try
            {
                UdpReceiveResult result = await udpClient?.ReceiveAsync();
                //it's a thread safe queue
                XXX.Add2OtherThreadWaitUpdateCall(() => receiveAction?.Invoke(result.Buffer));
            }
            catch (Exception e)
            {
                XXX.Add2OtherThreadWaitUpdateCall(() => Debug.LogError("ReceiveMessage Error" + e + e.StackTrace));
            }
        }
    }
}
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
子昂张
  • 11
  • 1

0 Answers0