Search code examples
c#socketsc#-4.0tcpudpclient

C# Sockets (TCP & UDP)


I'll cut to the point, I've been stuck on this for a few hours now. Tons of Google and tons of research but not straight answer as of yet.

I have a client and a server coded for TCP which functions perfectly fine, however, I want the client to also be able to use UDP with the server for none-important packets such as player location.

As of right now, this is my connect code for connected clients.

public void ConnectToServer(){
    tcp_client = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
    tcp_client.Connect(server_ip, server_port);
    tcp_stream = new NetworkStream(this.tcp_client);

    this.udp_client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    this.udp_client.BeginConnect(IPAddress.Parse(server_ip), server_port,new AsyncCallback(udp_connected), null);
}

Now the client isn't what I've had issues with for when I use udp.Send(byteArray) it appears to be sending as it's not throwing any exceptions but the server itself isn't responding to any data received.

Please Note this is NOT 100% copy/pasted code. Alter to show just what's being an issue.

private Socket c;
private UdpClient udp;
private isRunning = true;

public Client(Socket c){
    // This was accepted from TcpListener on Main Server Thread.
    this.c = c;
    this.networkStream = new NetworkStream(this.c);

    udp = new UdpClient();
    udp.Connect((IPEndPoint)c.RemoteEndPoint);

    // Then starts 2 thread for listening, 1 for TCP and 1 for UDP.
}

private void handleUDPTraffic(){
    IPEndPoint groupEP = (IPEndPoint)c.RemoteEndPoint;
    while (isRunning){
        try{
            byte[] udp_received = udp.Receive(ref groupEP);
            Console.WriteLine("Received UDP Packet Data: " + udp_received.Length);
        }catch{
            log.ERROR("UDP", "Couldn't Receive Data...");
        }
    }
}

Solution

  • You can use both TCP and UDP on the same port. See also:

    Can TCP and UDP sockets use the same port?

    The sample below demonstrates that, you can simultaneously send and receive UDP and TCP messages.

    Maybe, your UdpClient creation to listen for incoming datagrams is the problem. I recommend to create it once like your TcpListener.

    The servers:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace TCPUDPServer
    {
      class Program
      {
        static void Main(string[] args)
        {
          TcpListener tcpServer = null;
          UdpClient   udpServer = null;
          int         port      = 59567;
    
          Console.WriteLine(string.Format("Starting TCP and UDP servers on port {0}...", port));
    
          try
          {
            udpServer = new UdpClient(port);
            tcpServer = new TcpListener(IPAddress.Any, port);
    
            var udpThread          = new Thread(new ParameterizedThreadStart(UDPServerProc));
            udpThread.IsBackground = true;
            udpThread.Name         = "UDP server thread";
            udpThread.Start(udpServer);
    
            var tcpThread          = new Thread(new ParameterizedThreadStart(TCPServerProc));
            tcpThread.IsBackground = true;
            tcpThread.Name         = "TCP server thread";
            tcpThread.Start(tcpServer);
    
            Console.WriteLine("Press <ENTER> to stop the servers.");
            Console.ReadLine();
          }
          catch (Exception ex)
          {
            Console.WriteLine("Main exception: " + ex);
          }
          finally
          {
            if (udpServer != null)
              udpServer.Close();
    
            if (tcpServer != null)
              tcpServer.Stop();
          }
    
          Console.WriteLine("Press <ENTER> to exit.");
          Console.ReadLine();
        }
    
        private static void UDPServerProc(object arg)
        {
          Console.WriteLine("UDP server thread started");
    
          try
          {
            UdpClient server = (UdpClient)arg;
            IPEndPoint remoteEP;
            byte[] buffer;
    
            for(;;)
            {
              remoteEP = null;
              buffer   = server.Receive(ref remoteEP);
    
              if (buffer != null && buffer.Length > 0)
              {
                Console.WriteLine("UDP: " + Encoding.ASCII.GetString(buffer));
              }
            }
          }
          catch (SocketException ex)
          {
            if(ex.ErrorCode != 10004) // unexpected
              Console.WriteLine("UDPServerProc exception: " + ex);
          }
          catch (Exception ex)
          {
            Console.WriteLine("UDPServerProc exception: " + ex);
          }
    
          Console.WriteLine("UDP server thread finished");
        }
    
        private static void TCPServerProc(object arg)
        {
          Console.WriteLine("TCP server thread started");
    
          try
          {
            TcpListener server = (TcpListener)arg;
            byte[]      buffer = new byte[2048];
            int         count; 
    
            server.Start();
    
            for(;;)
            {
              TcpClient client = server.AcceptTcpClient();
    
              using (var stream = client.GetStream())
              {
                while ((count = stream.Read(buffer, 0, buffer.Length)) != 0)
                {
                  Console.WriteLine("TCP: " + Encoding.ASCII.GetString(buffer, 0, count));
                }
              }
              client.Close();
            }
          }
          catch (SocketException ex)
          {
            if (ex.ErrorCode != 10004) // unexpected
              Console.WriteLine("TCPServerProc exception: " + ex);
          }
          catch (Exception ex)
          {
            Console.WriteLine("TCPServerProc exception: " + ex);
          }
    
          Console.WriteLine("TCP server thread finished");
        }
      }
    }
    

    The clients:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading.Tasks;
    
    namespace TCPUDPClient
    {
      class Program
      {
        static void Main(string[] args)
        {
          UdpClient      udpClient = null;
          TcpClient      tcpClient = null;
          NetworkStream  tcpStream = null;
          int            port      = 59567;
          ConsoleKeyInfo key;
          bool           run = true;
          byte[]         buffer;
    
          Console.WriteLine(string.Format("Starting TCP and UDP clients on port {0}...", port));
    
          try
          {
            udpClient = new UdpClient();
            udpClient.Connect(IPAddress.Loopback, port);
    
            tcpClient = new TcpClient();
            tcpClient.Connect(IPAddress.Loopback, port);
    
            while(run)
            {
              Console.WriteLine("Press 'T' for TCP sending, 'U' for UDP sending or 'X' to exit.");
              key = Console.ReadKey(true);
    
              switch (key.Key)
              {
                case ConsoleKey.X:
                  run = false;
                  break;
    
                case ConsoleKey.U:
                  buffer = Encoding.ASCII.GetBytes(DateTime.Now.ToString("HH:mm:ss.fff"));
                  udpClient.Send(buffer, buffer.Length);
                  break;
    
                case ConsoleKey.T:
                  buffer = Encoding.ASCII.GetBytes(DateTime.Now.ToString("HH:mm:ss.fff"));
    
                  if (tcpStream == null)
                    tcpStream = tcpClient.GetStream();
    
                  tcpStream.Write(buffer, 0, buffer.Length);
                break;
              }
            }
          }
          catch (Exception ex)
          {
            Console.WriteLine("Main exception: " + ex);
          }
          finally
          { 
            if(udpClient != null)
              udpClient.Close();
    
            if(tcpStream != null)
              tcpStream.Close();
    
            if(tcpClient != null)
              tcpClient.Close();
          }
    
          Console.WriteLine("Press <ENTER> to exit.");
          Console.ReadLine();
        }
      }
    }