Как отправить список подключенных клиентов с сервера на клиент, различая обычное сообщение? - PullRequest
0 голосов
/ 02 мая 2018

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

В настоящее время нет никаких ловушек или методов для отключения клиента, которые я добавлю позже. Однако сейчас я хочу добавить функцию отображения списка онлайн-пользователей в текстовом поле на моей клиентской форме.

Когда клиент подключается к серверу, сервер добавляет этого клиента в «clientList». Тем не менее, я немного запутался в том, как мне поступить, отправляя этот список клиенту, но, что более важно, как я заставил бы клиента признать, что это не обычное сообщение, тем более список клиентов.

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

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

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

код стороны города -

   using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Net.Sockets;
    using System.Net;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Forms;

    namespace socketClientForm
    {
        public partial class Form1 : Form
        {
            private static byte[] buffer = new byte[1024];
            private static Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            public string message = "";
            public Form1()
            {
                InitializeComponent();
                this.Text = "Client";
            }

            delegate void SetTextCallback();

            private void SetText()
            {
                if (this.InvokeRequired)
                {
                    SetTextCallback d = new SetTextCallback(SetText);
                    this.Invoke(d, new object[] { });
                }
                else
                    this.chatBox.AppendText(message);
            }

            private void LoopConnect()
            {
                int attempts = 0;

                while (!clientSocket.Connected)
                    try
                    {
                        attempts++;
                        clientSocket.Connect(IPAddress.Parse(IPBox.Text), 8080);
                    }
                    catch (SocketException)
                    {
                        chatBox.Clear();
                        chatBox.AppendText("Connection attempts: " + attempts.ToString());
                    }

                clientSocket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(backgroundWorker1.RunWorkerAsync), clientSocket);
                chatBox.Clear();
                chatBox.AppendText("Connected \n");
            }

            private void submitButton_Click(object sender, EventArgs e)
            {
                if (!String.IsNullOrWhiteSpace(msgBox.Text))
                {

                    string req = usernameBox.Text + ": " + msgBox.Text;
                    byte[] buffer = Encoding.ASCII.GetBytes(req);
                    clientSocket.Send(buffer);
                    msgBox.Text = "";
                }
            }

            private void connectButton_Click(object sender, EventArgs e)
            {
                LoopConnect();
            }

            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                while (clientSocket.Connected)
                {
                    try
                    {
                        byte[] receivedBuf = new byte[1024];
                        int rec = clientSocket.Receive(receivedBuf);
                        byte[] data = new byte[rec];
                        Array.Copy(receivedBuf, data, rec);

                        message = Encoding.ASCII.GetString(data) + "\n";
                        SetText();
                    }
                    catch
                    {

                    }
                }
            }
        }
    }

Код серверной стороны -

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace socketServer
{
    class Program
    {
        private static byte[] buffer = new byte[1024];
        private static List<Socket> clientSockets = new List<Socket>();
        private static Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

        static void Main(string[] args)
        {
            Console.Title = "Server";
            SetupServer();
            Console.ReadLine();
        }

        private static void SetupServer()
        {
            Console.WriteLine("Setting up server...");
            serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080));
            serverSocket.Listen(1);

            serverSocket.BeginAccept(new AsyncCallback(AcceptCallBack), null);
        }

        private static void AcceptCallBack(IAsyncResult AR)
        {
            Socket socket = serverSocket.EndAccept(AR);
            clientSockets.Add(socket);
            Console.WriteLine("Client Connected");
            socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
            serverSocket.BeginAccept(new AsyncCallback(AcceptCallBack), null);
        }

        private static void ReceiveCallBack(IAsyncResult AR)
        {
            Socket socket = (Socket)AR.AsyncState;

            int received = socket.EndReceive(AR);
            byte[] dataBuff = new byte[received];
            Array.Copy(buffer, dataBuff, received);

            string text = Encoding.ASCII.GetString(dataBuff);
            Console.WriteLine("Text received: " + text);

            byte[] data = Encoding.ASCII.GetBytes(text);

            foreach (Socket client in clientSockets)
            {
                client.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
                client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), client);
            }

            //socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
            //socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
        }

        private static void SendCallback(IAsyncResult AR)
        {
            Socket socket = (Socket)AR.AsyncState;
            socket.EndSend(AR);
        }
    }
}

1 Ответ

0 голосов
/ 02 мая 2018

Труднее получить протокол обмена сообщениями, если вы работаете с простыми байтами и строковыми сообщениями. Вы лучше всего создаете модель - что-то вроде

public class NetMessage{

public int MessageType{get;set;}
public dynamic Payload{get;set;}

}

Итак, пусть Imaging MessageType 1 - это ваш запрос аутентификации.

это было бы что-то вроде

 {    "MessageType":"1",    "PayLoad":{
                 "Username":"Admin",
                 "Password":"Password123"
              }

 }

Вы можете либо сериализовать это в строку и отправить его (через Newtonsoft.Json) Или, как я предпочитаю, использовать двоичный форматер для непосредственного преобразования объекта в байты и последующей отправки байтов по сети. Отправка сериализованных данных в виде байтов будет немного более эффективной, чем отправка строковой информации по сети.

Используя протокол, описанный выше, вы можете заставить свой сервер выполнять оператор switch для MessageType, а затем обрабатывать логику по-другому.

По вашему вопросу вы хотите отправить список подключенных клиентов?

Используйте что-то вроде MessageType 99 и установите в качестве полезной нагрузки список клиентов. Просто помните, что вы не можете сериализовать объект TcpClient и отправить его удаленному пользователю и ожидать, что объект будет функционировать как подключенный TcpClient. Вы можете максимально отправить удаленный IP-адрес и порт, к которому подключен сервер. Поэтому я бы рекомендовал отправить модель, которая представляет эти данные.

UPDATE:

В данный момент ваш фоновый работник получает данные и обрабатывает их как байты -> текст, а затем выполняет бизнес-логику прямо над текстом.

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

Используйте менеджер пакетов nuget в Visual Studio для установки Newtonsoft.Json (или JSON.Net иногда называют)

С Newtonsoft вы можете делать следующее.

Учитывая класс, который выглядит так

public class MessageClass
{
    public int MessageType{get;set;}
    public dynamic Payload{get;set;}
}

Вы можете сделать следующее

string content = "{\"MessageType\":\"2\",\"Payload\":\"blah\"}";

Это строка в формате JSON, представляющая экземпляр класса.

В C # Code этот объект будет выглядеть так:

var message = new MessageClass();
message.MessageType=2;
message.Payload = "blah";

Что дает вам Newtonsoft - это возможность превращать строки в управляемые типы C #. Например:

Помните нашу строку выше под названием 'content'?

var managedObject = JsonConvert.DeserializeObject<MessageClass>(content);
Console.WriteLine(managedObject.MessageType);  // will; write 2

Я предлагаю, чтобы ваш клиент и сервер связывались через объекты в формате JSON, что затем дает вам возможность выполнять более сложные условные выражения и более точные утверждения.

Newtonsoft предоставляет 2 ключевых метода для вас. Документально подтверждено на сайте newtonsoft. newtonsoft.com/json/help/html/Methods_T_Newtonsoft_Json_JsonConvert.htm

Чтобы превратить объект C # в строку JsonConvert.SerializeObject (object o); JsonConvert.DeserializeObject (String value);

Для метода десериализации укажите тип, к которому вы его десериализируете, где T.

Например:

MessageClass msg = JsonConvert.DeserializeObject<MessageClass>(content);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...