Использование NetworkStream.BeginRead

445
29 мая 2017, 22:52

Здравствуйте, пишу класс сервера, который мог бы обрабатывать несколько подключений. До этого никогда не писал. Использую TcpListener и TcpClient. После запуска TcpListener, каждое новый TcpClient сохраняется и в нём вызывается метод BeginRead, который, по-моему пониманию, будет ждать, пока на другом конце я не запишу строку в буфер, например, с помощью Write. Однако, работает не так, как ожидалось. BeginRead бесконечно считывает пустые строки, а при попытке выполнения Read со стороны клиента происходит ошибка: "Операция не разрешается на не подключённых сокетах" Совсем не понятно почему, ведь успешно выполнил команду Connect и не отключался.

Этот метод запускается в процессе сервера

    public void Start()
    {
        try
        {
            TcpListener tcpListener = new TcpListener(IPAddress.Parse(ipAddress), port);
            tcpListener.Start();
            ServerLogger.Log("Server has been started");
            while(true)
            {
                GameConnections.Add(new GameConnection(tcpListener.AcceptTcpClient(), GameConnections.Count));
            }
        }
        catch(Exception ex)
        {
            ServerLogger.Error(ex.Message);
        }
    }

Создание подключения

class GameConnection
{
    string GameID { get; set; }
    string ConnectionID { get; set; }
    TcpClient Client { get; set; }
    byte[] acceptedData = new byte[1024];
    byte[] sendData = new byte[1024];
    byte[] buffer = new byte[1024];
    NetworkStream stream;
    public GameConnection(TcpClient client, int id)
    {
        Client = client;
        stream = client.GetStream();
        ConnectionID = "connection" + id;
        ServerLogger.Log(string.Format("Client connected. ConnectionID: {1}", GameID, ConnectionID));            
        stream.BeginRead(acceptedData, 0, acceptedData.Length, FirstReadCallback, null);
    }
    public void FirstReadCallback(IAsyncResult ar)
    {
        int bytesRead = stream.EndRead(ar);
        if(bytesRead > 0)
        {
            Console.WriteLine(bytesRead);                
            GameID = Encoding.UTF8.GetString(acceptedData, 0, bytesRead);
            Console.WriteLine("Game id - " + GameID);
            stream.BeginRead(acceptedData, 0, acceptedData.Length, ReadCallback, null);
            ServerLogger.Log(String.Format("{0} game id is {1}", ConnectionID, GameID));
        }else
        {
            ServerLogger.Log(String.Format("Empty first read from client({0})", ConnectionID));
            stream.BeginRead(acceptedData, 0, acceptedData.Length, FirstReadCallback, null);
        }
    }
    public void ReadCallback(IAsyncResult ar)
    {
        int bytesRead = stream.EndRead(ar);
        if(bytesRead > 0)
        {
            string command = Encoding.UTF8.GetString(acceptedData, 0, bytesRead);
            ServerLogger.Log(String.Format("Command from client({0}): {1}", ConnectionID, command));
            string serverAnswer = "some game command";
            Encoding.UTF8.GetBytes(serverAnswer, 0, serverAnswer.Length, sendData, 0);
            stream.BeginWrite(sendData, 0, sendData.Length, WriteCallback, null);
        }else
        {
            ServerLogger.Log(String.Format("Empty read from client({0})", ConnectionID));
            stream.BeginRead(acceptedData, 0, acceptedData.Length, ReadCallback, null);
        }
    }
    public void WriteCallback(IAsyncResult ar)
    {
        stream.EndWrite(ar);
        stream.BeginRead(acceptedData, 0, acceptedData.Length, ReadCallback, null);
    }

После того как сервер запущен пробую подключиться так:

    static void Main(string[] args)
    {
        TcpClient client = new TcpClient();
        try
        {
            Console.WriteLine("Connecting to server");
            client.Connect(IPAddress.Parse("127.0.0.1"), 8888);
            using (BinaryWriter writer = new BinaryWriter(client.GetStream()))
            {
                byte[] data = new byte[1024];
                string gameID = "1000";                    
                Encoding.UTF8.GetBytes(gameID, 0, gameID.Length, data, 0);
                writer.Write(data, 0, gameID.Length);
                Console.WriteLine(Encoding.UTF8.GetString(data));
            }
            while (true)
            {
                string command = Console.ReadLine();
                if (command == "exit") break;
                byte[] data = new byte[1024];
                NetworkStream stream = client.GetStream();
                using (BinaryWriter writer = new BinaryWriter(stream))
                {
                    writer.Write(command);
                }
                using (BinaryReader reader = new BinaryReader(stream))
                {
                    reader.Read(data, 0, 1024);
                    Console.WriteLine("Server answer: {0}", Encoding.UTF8.GetString(data));
                }
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        finally
        {
            client.Close();
        }
    }

По итогу в лог выглядит так:

Server has been started
Client connected. ConnectionID: connection0
connection0 game id is 1000
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
Empty read from client(connection0)
READ ALSO
Как такое получается что в ASP.NET MVC AnonymousID = null

Как такое получается что в ASP.NET MVC AnonymousID = null

Делаю модуль на сайте, который выводит пользователей на сайте за последние 24 часаВключил <anonymousIdentification enabled="true" /> на сайте

228
Password char в windows form. С#

Password char в windows form. С#

Не понимаю как правильно сделать чекбокс на показ пароля если отмеченЕсть вот такой код

265
Написать код на C# для такого задания [требует правки]

Написать код на C# для такого задания [требует правки]

Назначение Программа реализует автоматный распознаватель, использующий в качестве структуры данных таблицу переходов

256
Как получить иконку папки?

Как получить иконку папки?

Как получить иконку папки?

299