1

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...");
        }
    }
}
Matthew Auld
  • 388
  • 1
  • 3
  • 18
  • 1
    Am I right understand that you cannot make UDP client and server work together? – Artavazd Balayan Oct 23 '17 at 06:27
  • 2
    From my knowledge it is not possible to run TCP and UDP listening simultaneously on the same port. Generally, you can run only one protocol on a port. Change e.g. your UDP port number for listening and sending, then it should work. – KBO Oct 23 '17 at 06:39
  • @KBO See I wasn't sure because if you look at port-forwarding rules it allows the option of "Both" so I make the assumption that a single port can be used for UDP and TCP. – Matthew Auld Oct 23 '17 at 13:55
  • @Mattew: Sorry, my fault, see my answer below. – KBO Oct 25 '17 at 08:25

1 Answers1

2

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();
    }
  }
}
KBO
  • 653
  • 7
  • 17
  • So what you're saying is that UDP cannot be assigned to a specific client? – Matthew Auld Oct 26 '17 at 21:25
  • I recommend to do several experiments. Use e.g. Wireshark to check, whether the UDP datagrams are really sent. Without the `UdpClient.Connect` call, you can use the returned remote endpoint from the `UdpClient.Receive` call to check/skip unwanted remote clients. You can store the allowed remote clients on the accepted TCP socket connections or so. – KBO Oct 27 '17 at 09:20