Сокеты C# (TCP и UDP)

Я перейду к делу, я застрял на этом уже несколько часов. Тонны Google и тонны исследований, но пока нет прямого ответа.

У меня есть клиент и сервер, закодированные для TCP, которые отлично работают, однако я хочу, чтобы клиент также мог использовать UDP с сервером для неважных пакетов, таких как местоположение игрока.

На данный момент это мой код подключения для подключенных клиентов.

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);
}

Теперь клиент — это не то, с чем у меня были проблемы, потому что, когда я использую udp.Send(byteArray), он, кажется, отправляет, поскольку он не генерирует никаких исключений, но сам сервер не отвечает ни на какие полученные данные.

Обратите внимание, что это НЕ стопроцентное копирование/вставка кода. Измените, чтобы показать, в чем проблема.

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...");
        }
    }
}

person Matthew D Auld    schedule 23.10.2017    source источник
comment
Я правильно понимаю, что вы не можете заставить UDP-клиент и сервер работать вместе?   -  person Artavazd Balayan    schedule 23.10.2017
comment
Насколько я знаю, невозможно одновременно запускать прослушивание TCP и UDP на одном и том же порту. Как правило, на одном порту можно запустить только один протокол. Изменить, например. ваш номер порта UDP для прослушивания и отправки, тогда он должен работать.   -  person KBO    schedule 23.10.2017
comment
@KBO Видите ли, я не был уверен, потому что, если вы посмотрите на правила переадресации портов, они допускают вариант «Оба», поэтому я делаю предположение, что один порт может использоваться для UDP и TCP.   -  person Matthew D Auld    schedule 23.10.2017
comment
@Mattew: Извините, моя вина, смотрите мой ответ ниже.   -  person KBO    schedule 25.10.2017


Ответы (1)


Вы можете использовать как TCP, так и UDP на одном и том же порту. Смотрите также:

Могут ли сокеты TCP и UDP использовать один и тот же порт?

Пример ниже демонстрирует, что вы можете одновременно отправлять и получать сообщения UDP и TCP.

Возможно, проблема заключается в создании вашего UdpClient для прослушивания входящих дейтаграмм. Я рекомендую создать его один раз, как ваш TcpListener.

Серверы:

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");
    }
  }
}

Клиенты:

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();
    }
  }
}
person KBO    schedule 25.10.2017
comment
Итак, вы говорите, что UDP не может быть назначен конкретному клиенту? - person Matthew D Auld; 27.10.2017
comment
Рекомендую провести несколько экспериментов. Используйте, например. Wireshark, чтобы проверить, действительно ли отправляются дейтаграммы UDP. Без вызова UdpClient.Connect вы можете использовать возвращенную удаленную конечную точку из вызова UdpClient.Receive для проверки/пропуска нежелательных удаленных клиентов. Вы можете хранить разрешенных удаленных клиентов в принятых соединениях сокета TCP или около того. - person KBO; 27.10.2017