Сеть с высоким трафиком C # UDP - PullRequest
2 голосов
/ 13 сентября 2011

Я создаю игру, которая требует большого трафика данных, таких как Positions (2D) и многих других данных.Я использую очень простой класс, чтобы помочь мне прослушивать порт 8080 (UDP), и метод для отправки дейтаграммы:

public static void SendToHostUDP(string Msg)
{
    UdpClient udpClient = new UdpClient();
    udpClient.Connect(Main.HostIP, 8080);
    byte[] sdBytes = Encoding.ASCII.GetBytes(Msg);
    udpClient.BeginSend(sdBytes, sdBytes.Length, CallBack, udpClient);
    Main.UDPout += sdBytes.Length / 1000f;
}
public static void SendToClientUDP(string Msg, IPAddress ip)
{
    UdpClient udpClient = new UdpClient();
    udpClient.Connect(ip, 8080);
    byte[] sdBytes = Encoding.ASCII.GetBytes(Msg);
    udpClient.BeginSend(sdBytes, sdBytes.Length, CallBack, udpClient);
    Main.UDPout += sdBytes.Length / 1000f;
}
public static void CallBack(IAsyncResult ar)
{

}

Класс слушателя очень простой:

public class NetReciever
{
    public TcpListener tcpListener;
    public Thread listenThread;
    private Action actionToPerformTCP;
    private Action actionToPerformUDP;
    public UdpClient udpClient;
    public Thread UDPThread;
    TimerAction UDPPacketsCounter;
    int UDPPacketsCounts;
    private BackgroundWorker bkgUDPListener;
    string msg;
    public NetReciever(IPAddress IP)
    {
        this.tcpListener = new TcpListener(IPAddress.Any, 25565);
        this.udpClient = new UdpClient(8080);
        this.UDPThread = new Thread(new ThreadStart(UDPListen));
        this.listenThread = new Thread(new ThreadStart(ListenForClients));
        this.listenThread.Start();
        UDPPacketsCounter = new TimerAction(CountUDPPackets, 1000, false);
        this.UDPThread.Start();
    }
    public void CountUDPPackets()
    {
        UDPPacketsCounts = 0;
    }
    public void Abort()
    {
        UDPThread.Abort();
        udpClient.Close();
        listenThread.Abort();
        tcpListener.Stop();
    }
    public void UDPListen()
    {
        while (true)
        {
            IPEndPoint RemoteIPEndPoint = new IPEndPoint(IPAddress.Any, 0);
            byte[] receiveBytesUDP = udpClient.Receive(ref RemoteIPEndPoint);
            if (receiveBytesUDP != null)
            {
                UDPPacketsCounts++;
                Main.UDPin += receiveBytesUDP.Length / 1000f;
            }
            if (Main.isHost)
            {
                Main.Server.processUDP(Encoding.ASCII.GetString(receiveBytesUDP), RemoteIPEndPoint.Address.ToString());
            }
            else
            {
                if (RemoteIPEndPoint.Address.ToString() == Main.HostIP)
                {
                    Program.game.ProcessUDP(Encoding.ASCII.GetString(receiveBytesUDP));
                }
            }
        }
    }

Таким образом, в основном, когда есть 1 игрок, будет приблизительно 60 пакетов / с IN и 60 пакетов / с.

Это действует так:

  1. Прослушивание пакетов.
  2. Проверка пакетов.
  3. Обработка данных пакетов -> Как сохранение некоторых позиций, отправление некоторых пакетов ...

Так что это просто циклthis.

И проблемы здесь:

Во-первых, когда будет 2 игрока (Host + 1Client), в какой-то момент произойдет несколько значительных падений FPS, и хост будет испытывать заиканиевсе аудио (как на синем экране) на мгновение.

Во-вторых, когда есть 2+ игрока (Host + 1 + Client), FPS хоста упадет до 5-20, и будет отставать + отставать+ лаг + лаг, но не замораживание.

Я прочитал несколько статей об асинхронности, и это ужеAdy Threadded?

А также BeginRecieve и EndRecieve, я не очень понимаю, как и зачем мне это нужно использовать.

Может кто-то любезно предоставить несколько примеров, чтобы объяснить, какобрабатывать эти виды данных и отправлять / получать пакеты, пожалуйста?Я действительно не хочу использовать библиотеки, потому что я хочу знать, что происходит.

PS: Как работает сетевая система в Terraria?Он использует TCP, но это гладко!Как?
PSS: Что такое буферизация?Зачем мне устанавливать буферизацию и как?Что это меняет?
PSSS: Я думаю, что есть что-то, что нужно настроить и изменить при отправке пакетов, потому что это выглядит просто.

Ответы [ 2 ]

1 голос
/ 13 сентября 2011

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

Хорошее начало - http://gafferongames.com/networking-for-game-programmers/sending-and-receiving-packets/. Хотя это и для C ++ (я думаю, но если я правильно помню, кто-то перенесет это и на C #, может быть: P) теория всего этого объясняется очень хорошо.

Возможно, стоит прочитать о программировании сокетов WinAPI. Это будет более техническим, чем чтение учебников о том, как выполнять сетевое программирование на C #, но это также прояснит ситуацию, чем использование оболочек, которые запутывают то, что действительно происходит за кулисами.

Edit:

Как правило, вам решать, использовать ли вы фоновый поток для прослушивания пакетов или использовать BeginReceive с методом AsyncCallback. Недостаток последнего заключается в том, что вам в конечном итоге потребуется вызвать EndReceive, после чего он будет по-прежнему блокировать ваше приложение, пока фактическое получение не будет завершено. Создание собственного потока и использование режима блокировки, очевидно, не будут блокировать ваш (основной) поток пользовательского интерфейса / бизнес-логики, но вам нужно будет самостоятельно программировать часть взаимодействия между потоками.

Я также нашел простое руководство для приложения UDP-Client-Server, использующего режим потоков и блокировки здесь .

1 голос
/ 13 сентября 2011

Асинхронная концепция, безусловно, то, что вы хотите посмотреть здесь.Проблема может заключаться в том, что если все работает в одном потоке, определенные действия пользовательского интерфейса (например, рендеринг графики (потеря кадров в секунду) или воспроизведение звука (ваше заикание)) вполне могут ожидать других аспектов программы, таких как сетькоммуникации.

Обычно вы отделяете потоки, чтобы пользовательский интерфейс и звуковая сторона процесса могли обрабатываться самостоятельно, без зависимости от чего-либо еще.Прочитайте некоторые примеры потоков msdn, затем попробуйте поместить ваши более длительные процессы в отдельный поток из вашего пользовательского интерфейса и посмотрите, как это поможет:

http://msdn.microsoft.com/en-us/library/aa645740(v=vs.71).aspx

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...