Получение нескольких разных сообщений TcpListener C#

Привет, ребята, я пытался научиться отправлять простые текстовые сообщения между клиентским сервером с помощью TcpListener и сокетов. Я прочитал много потоков, которые, кажется, показывают, как читать _Buffer, скажем, в цикле, чтобы убедиться, что все сообщение прочитано. Однако я не могу понять, как получить второе сообщение после получения первого. Я могу нормально подключиться к серверу и получить первое сообщение. Однако, если я снова нажму кнопку отправки на своем клиенте, сообщение не будет доставлено на сервер. Вот мой код:

// SERVER APPLICATION: -----------------------------------------------

пространство имен TCP_Server { общедоступный частичный класс Form1 : Form { public Form1() { InitializeComponent(); }

    private void btnStartServer_Click(object sender, EventArgs e)
    {
        // Define the TCP Listner:
        TcpListener _listner = new TcpListener(IPAddress.Parse("127.0.0.1"), 7777);

        // Start The Listner:
        _listner.Start();

        //Show the server is now listening:
        listStatus.Items.Add("Server started - Listening on port 7777");

        //Create a socket to accept - This is a Blocking Call:
        Socket _sock = _listner.AcceptSocket();

        //When Client Connects show server has accepted the socket:
        listStatus.Items.Add("User from IP " + _sock.RemoteEndPoint);

        while (_sock.Connected)
        {

            // Create Byte to Receive Data:
            byte[] _Buffer = new byte[1024];

            // Create integer to hold how large the Data Received is:
            int _DataReceived = _sock.Receive(_Buffer);

            // Lets Server Know Message is Received:
            listStatus.Items.Add("Message Received...");

            // Convert Buffer to a String:
            string _Message = Encoding.ASCII.GetString(_Buffer);

            // Post Message to the Server Window:
            listStatus.Items.Add(_Message);

            _sock.Close();
        }
    }
}

}

// CLIENT APPLICATION: ----------------------------------------------------

namespace TCP__Client { public partial class Form1 : Form { public Form1() { InitializeComponent(); }

// Defind the TCP Client: TcpClient _Client = new TcpClient(); private void btnConnect_Click(object sender, EventArgs e) { // Connect the TCP Client: _Client.Connect("127.0.0.1", 7777); // Show the Client has Connected: listStatus.Items.Add("Connected to Server 127.0.0.1"); } private void btnSend_Click(object sender, EventArgs e) { while (_Client.Connected) { // Create a Stream: Stream _Stream = _Client.GetStream(); // Create Instance of an Encoder: ASCIIEncoding _Asc = new ASCIIEncoding(); byte[] _Buffer = new byte[1024]; // Create Buffer to Send Message: _Buffer = _Asc.GetBytes(txtMessage.Text); // Show Client is Sending Message: listStatus.Items.Add("Tranmitting Message..."); // Write Message to the Stream: _Stream.Write(_Buffer, 0, _Buffer.Length); // Close Stream _Stream.Close(); _Stream.Dispose(); } } }

}

Я был бы очень признателен, если бы кто-нибудь объяснил, как это сделать, чтобы я мог получить более одного сообщения. У меня есть небольшой опыт использования задач и многопоточности, нужно ли мне это делать? Я просто пытаюсь понять это, чтобы начать изучать его. Если у кого-то есть какие-либо рекомендации или примеры, которые, по вашему мнению, могут помочь, пожалуйста, поделитесь.


person Timg    schedule 12.01.2014    source источник
comment
Не закрытие сокета в конце цикла было бы хорошим началом. Как вы ожидаете получить больше байтов, если закроете сокет? Также обратите внимание: «байты», а не «сообщение». Только TCP не может передавать «сообщения» длиннее одного байта.   -  person Martin James    schedule 12.01.2014


Ответы (1)


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

Ваше серверное приложение может блокировать поток пользовательского интерфейса в частях AcceptSocket() и Receive(). При нажатии кнопки StartServer окно вашего сервера (UI) может перестать отвечать из-за отсутствия доступного входящего соединения, и вы не можете видеть сообщения в своем элементе управления listStatus. Таким образом, лучше поместить эти фрагменты кода Socket для запуска в отдельном потоке, чтобы не блокировать поток пользовательского интерфейса. Чтобы работать с компонентом пользовательского интерфейса из отдельного потока, для этого требуется потокобезопасная манипуляция с пользовательским интерфейсом.

Вот изменения, которые я сделал:

Сервер

namespace Tcp_Server
{
    public partial class Form1 : Form
    {
        delegate void AddTextCallback(string text);

        public Form1()
        {
            InitializeComponent();
        }

        private void btnStartServer_Click(object sender, EventArgs e)
        {
            ThreadPool.QueueUserWorkItem(new WaitCallback(ServerHandler));
        }

        private void ServerHandler(object args)
        {
            TcpListener _listner = new TcpListener(IPAddress.Parse("127.0.0.1"), 7777);

            // Start The Listner:
            _listner.Start();

            //Show the server is now listening (Note: UI Thread-Safe is required):
            AddText("Server started - Listening on port 7777");

            //Create a socket to accept - This is a Blocking Call:
            Socket _sock = _listner.AcceptSocket();

            //When Client Connects show server has accepted the socket:
            AddText("User from IP " + _sock.RemoteEndPoint);

            while (_sock.Connected)
            {

                // Create Byte to Receive Data:
                byte[] _Buffer = new byte[1024];

                // Create integer to hold how large the Data Received is:
                int _DataReceived = _sock.Receive(_Buffer);

                if (_DataReceived == 0)
                {
                    // Socket has been shutdown by the client.
                    break;
                }

                // Lets Server Know Message is Received:
                AddText("Message Received...");

                // Convert Buffer to a String:
                string _Message = Encoding.ASCII.GetString(_Buffer);

                // Post Message to the Server Window:
                AddText(_Message);
            }

            _sock.Close();
            //When Client disconnect from the server:
            AddText("Client Disconnected.");

            _listner.Stop();
            AddText("Server Stop.");
        }


        private void AddText(string text)
        {
            // InvokeRequired required compares the thread ID of the 
            // calling thread to the thread ID of the creating thread. 
            // If these threads are different, it returns true. 
            if (this.listStatus.InvokeRequired)
            {
                AddTextCallback d = new AddTextCallback(AddText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.listStatus.Items.Add(text);
            }
        }
    }
}

Клиент

namespace Tcp_Client
{
    public partial class Form1 : Form
    {
        // Defind the TCP Client:
        TcpClient _Client = null;
        Stream _Stream = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void btnConnect_Click(object sender, EventArgs e)
        {
            _Client = new TcpClient();

            // Connect the TCP Client:
            _Client.Connect("127.0.0.1", 7777);

            // Show the Client has Connected:
            listStatus.Items.Add("Connected to Server 127.0.0.1");

            // Create a Stream:                
            _Stream = _Client.GetStream();
        }

        private void btnSend_Click(object sender, EventArgs e)
        {
            if (_Client.Connected)
            {
                // Create Instance of an Encoder:
                ASCIIEncoding _Asc = new ASCIIEncoding();

                byte[] _Buffer = new byte[1024];

                // Create Buffer to Send Message:
                _Buffer = _Asc.GetBytes(txtMessage.Text);

                // Show Client is Sending Message:
                listStatus.Items.Add("Tranmitting Message...");

                // Write Message to the Stream:
                _Stream.Write(_Buffer, 0, _Buffer.Length);
            }
        }

        private void btnDisconnect_Click(object sender, EventArgs e)
        {
            _Stream.Close();
            _Stream.Dispose();
            _Client.Close();
            listStatus.Items.Add("Disconnected from server.");
        }
    }
}
person Darius Iko    schedule 12.01.2014
comment
Отлично, что сработало Круто... И еще лучше, я даже понял, о чем ты говорил, лол. Цените помощь. - person Timg; 14.01.2014