User 13204940 Ответов: 1

Консультация по проекту + необычная проблема tcpclient


Привет

Я работаю над созданием сервера для игры, которую собираюсь начать разрабатывать с использованием Unreal Engine, однако я хочу, чтобы сервер был приложением WinForms. Мой подход состоял в том, чтобы создать приложение C# WinForms, которое способно принимать TCP-соединения и хранить их, получать пакеты от любого и транслировать при необходимости. Примером может служить PacketPlayerDisconnect, когда игрок отключается от сервера, этот пакет отправляется всем другим клиентам и содержит идентификатор игрока, так что модель игрока удаляется на клиентах.

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

EDIT: в моем решении решается следующее

Способ реализации пакетной системы в моем коде заключается в отправке массива байтов в следующем формате:

0 | 1 | 2...
длина данных | packetID | содержимое пакета...

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

Я вижу странную проблему, когда сервер отправляет один пакет клиенту, и он говорит, что получает 7. Вот код:

Сервер:
public class GameServer
    {
        private Main main;
        private List<GameClient> clients = new List<GameClient>();

        #region Config
        private int port = 1123;
        #endregion

        #region Connection
        private TcpListener listener;
        private bool listening = false;
        private Thread listenThread;
        #endregion

        public GameServer(Main main)
        {
            this.main = main;
        }

        public void start()
        {
            listener = new TcpListener(IPAddress.Parse("127.0.0.1"), port);
            listener.Start();

            listenThread = new Thread(listen);
            listenThread.Start();
        }

        public void stop()
        {
            listening = false;
            listener.Server.Close();
            listener.Stop();

            clients.ForEach((client) => client.disconnect());
        }

        private void listen()
        {
            listening = true;

            while(listening)
            {
                TcpClient client = listener.AcceptTcpClient();
                GameClient game_client = new GameClient(main, client);
                clients.Add(game_client);
                game_client.sendPacket(new PacketRawData("Hello, Client"));
            }
        }

Клиент:
public class GameClient
    {
        private Main main;
        private TcpClient client;
        private NetworkStream client_stream;
        private Thread listenThread;
        private bool listening;

        public GameClient(Main main, String ipAddress, int portNum)
        {
            this.main = main;
            client = new TcpClient();
            
            listenThread = new Thread(receive);
            listenThread.Start();

            client.Connect(ipAddress, portNum);
            client_stream = client.GetStream();
        }

        public void send(string message)
        {
            byte[] message_data = Encoding.UTF8.GetBytes(message);
            byte[] data = new byte[1 + message_data.Length];

            int message_length = message_data.Length;
            data[0] = (byte)message_length;

            for(int i = 0; i < message_length; i++) // place message bytes after length byte
            {
                data[i + 1] = message_data[1];
            }

            NetworkStream client_stream = client.GetStream();
            client_stream.Write(data, 0, data.Length);
            client_stream.Flush();

            main.logPacket(PacketDirection.SEND, message);
        }

        private void receive()
        {
            listening = true;

            while(listening)
            {
                if(client_stream.DataAvailable)
                {
                    byte[] length_byte = new byte[1];
                    client_stream.Read(length_byte, 0, length_byte.Length); // read first byte (length)

                    int data_length = length_byte[0];
                    byte[] data_bytes = new byte[data_length]; // read rest of data
                    client_stream.Read(length_byte, 0, length_byte.Length);

                    String data = Encoding.UTF8.GetString(data_bytes);

                    main.logPacket(PacketDirection.RECEIVE, data);
                }
            }            
        }
    }


Что я уже пробовал:

Использование Wireshark для мониторинга пакетов, но он не обнаруживает мои интерфейсы

Использование нескольких методов для отправки/получения.

________________

Когда вы устанете от низкоуровневых проблем, взгляните на WCF (https://www.codeproject.com/Articles/406096/A-beginners-tutorial-for-understanding-Windows)

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

1 Ответов

Рейтинг:
1

User 13204940

Решение: эта часть кода была проблемой:

for(int i = 0; i < message_length; i++) // place message bytes after length byte
{
        data[i + 1] = message_data[1];
}
Там была опечатка;
message_data[1];
должно быть
message_data[i];

Это привело к тому, что вместо правильного сообщения было отправлено много букв "а".