Member 14150101 Ответов: 1

Мульти-клиентский односерверный чат C#


Уважаемые Все Разработчики,

Я новичок в этой области.Моя задача-создать приложение для диаграмм с несколькими клиентами и одним сервером с использованием C#. Это приложение, которое позволяет серверу отвечать на сообщение от клиента к клиенту, который отправляет сообщение в одной форме. Я пытался понять этот пример Многопоточный Чат-Сервер[^] .

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

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

это мой код в форму form1.в CS

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

namespace serverchat
{
    public partial class Form1 : Form
    {
        private int count;
        Dictionary<string, TcpClient> clientDict;
        List<TcpClient> clientList;
        private TcpListener tcpServer;
        private TcpClient tcpClient;
        private Thread th;
        private ArrayList formArray = new ArrayList();
        private ArrayList threadArray = new ArrayList();
        public delegate void ChangedEventHandler(object sender, EventArgs e);
        public event ChangedEventHandler Changed;
        public delegate void SetListBoxItem(String str, String type);

        private TcpClient client;
        private NetworkStream clientStream;
        public delegate void SetTextCallback(string s);
        //private Form1 owner;

        public TcpClient connectedClient
        {
            get { return client; }
            set { client = value; }

        }


        public Form1()
        {
            InitializeComponent();

            // memasukkan data dari client yang baru ke dalam tree view
            Changed += new ChangedEventHandler(ClientAdded);
            TreeNode node;
            node = tvClientList.Nodes.Add("list client");
        }

        public void StartServer() // memulai server
        {
            tbPort.Enabled = false;
            th = new Thread(new ThreadStart(StartListen));
            th.Start();
        }

        public void StartListen() 
        {

            IPAddress localAddr = IPAddress.Parse("127.0.0.1");

            tcpServer = new TcpListener(localAddr, Int32.Parse(tbPort.Text));
            tcpServer.Start();

            // Keep on accepting Client Connection
            while (true)
            {

                // New Client connected, call Event to handle it.
                Thread t = new Thread(new ParameterizedThreadStart(NewClient));
                tcpClient = tcpServer.AcceptTcpClient();
                t.Start(tcpClient);
                count++;

            }

        }

        public void StopServer()
        {
            if (tcpServer != null)
            {
                tvClientList.Nodes[0].Nodes.Clear();

                // Abort Listening Thread and Stop listening
                th.Abort();
                tcpServer.Stop();
            }
            tbPort.Enabled = true; 
        }
        
        public void NewClient(Object obj)
        {
            ClientAdded(this, new MyEventArgs((TcpClient)obj));
        }

        public void ClientAdded(object sender, EventArgs e)
        {
            tcpClient = ((MyEventArgs)e).clientSock;
            String remoteIP = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
            String remotePort = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port.ToString();
           
            // Call Delegate Function to update Tree View
            UpdateClientList(remoteIP + " : " + remotePort, "Add");

            connectedClient = tcpClient;
            clientStream = tcpClient.GetStream();

            // Create the state object.
            StateObject state = new StateObject();
            state.workSocket = connectedClient.Client;

            //Call Asynchronous Receive Function
            connectedClient.Client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                    new AsyncCallback(OnReceive), state);

           

        }
        private void UpdateClientList(string str, string type)
        {
            // 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.tvClientList.InvokeRequired)
            {
                SetListBoxItem d = new SetListBoxItem(UpdateClientList);
                this.Invoke(d, new object[] { str, type });
            }
            else
            {
                // If type is Add, the add Client info in Tree View
                if (type.Equals("Add"))
                {
                    this.tvClientList.Nodes[0].Nodes.Add(str);
                }
                // Else delete Client information from Tree View
                else
                {
                    foreach (TreeNode n in this.tvClientList.Nodes[0].Nodes)
                    {
                        if (n.Text.Equals(str))
                            this.tvClientList.Nodes.Remove(n);
                    }
                }

            }
        }

        private void tvClientList_DoubleClick(object sender, System.EventArgs e)
        {
              // Open Hidden Dialog Box
           // if (!((ChatDialog)formArray[index]).Visible)
            //    ((ChatDialog)formArray[index]).Show();
        }

        private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
        {
            StopServer();

        }

        private void cbStartStop_CheckedChanged_1(object sender, EventArgs e)
        {
            if (cbStartStop.Checked == true)
            {
                // validate the port number
                try
                {
                    int port;
                    port = Int32.Parse(tbPort.Text);

                    string cx = tbPort.Text.ToString();

                    StartServer();

                    MessageBox.Show("connect!!!" + cx);

                }
                catch (Exception ex)
                {
                    MessageBox.Show("Please enter the correct port number!!!");
                    cbStartStop.Checked = false;
                }
            }

            else
            {
                StopServer();
            }

        }

        private void SetText(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.
            String remotePort = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Port.ToString();
            if (this.rtbchattting.InvokeRequired)
            {
                SetTextCallback d = new SetTextCallback(SetText);
                this.Invoke(d, new object[] { text });
            }
            else
            {
                this.rtbchattting.SelectionColor = Color.Blue;
                this.rtbchattting.SelectedText = remotePort +" : " + text +"\n";
            }
        }


        public void OnReceive(IAsyncResult ar)
        {
            String content = String.Empty;

            // Retrieve the state object and the handler socket
            // from the asynchronous state object.
            StateObject state = (StateObject)ar.AsyncState;
            Socket handler = state.workSocket;
            int bytesRead;

            if (handler.Connected)
            {

                // Read data from the client socket. 
                try
                {
                    bytesRead = handler.EndReceive(ar);
                    if (bytesRead > 0)
                    {
                        // There  might be more data, so store the data received so far.
                        state.sb.Remove(0, state.sb.Length);
                        state.sb.Append(Encoding.ASCII.GetString(
                                         state.buffer, 0, bytesRead));

                        // Display Text in Rich Text Box
                        content = state.sb.ToString();
                        SetText(content);

                        handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
                            new AsyncCallback(OnReceive), state);

                    }
                }

                catch (SocketException socketException)
                {
                    //WSAECONNRESET, the other side closed impolitely
                    if (socketException.ErrorCode == 10054 || ((socketException.ErrorCode != 10004) && (socketException.ErrorCode != 10053)))
                    {
                        // Complete the disconnect request.
                        String remoteIP = ((IPEndPoint)handler.RemoteEndPoint).Address.ToString();
                        String remotePort = ((IPEndPoint)handler.RemoteEndPoint).Port.ToString();
                        //this.owner.DisconnectClient(remoteIP, remotePort);

                        handler.Close();
                        handler = null;

                    }
                }
                // Eat up exception....Hmmmm I'm loving eat!!!
                catch (Exception exception)
                {
                    MessageBox.Show(exception.Message + "\n" + exception.StackTrace);

                }
            }
        }

        public class StateObject
        {
            // Client  socket.
            public Socket workSocket = null;
            // Size of receive buffer.
            public const int BufferSize = 1024;
            // Receive buffer.
            public byte[] buffer = new byte[BufferSize];
            // Received data string.
            public StringBuilder sb = new StringBuilder();
        }

        private void Btn_Kirim_Click(object sender, EventArgs e)
        {
            byte[] chatts;
            chatts = Encoding.ASCII.GetBytes(tbSendChat.Text);
            if (String.IsNullOrEmpty(tbNoClient.Text))
            {
            MessageBox.Show("Enter Material Name Please.");
            //dataGridView1.Rows.Clear();
            }
            
            else{

                
                   

                        connectedClient.Client.Send(chatts);
                        //and use selected client.
                    
                

            }
            
            
            
            

            rtbchattting.SelectionColor = Color.IndianRed;
            rtbchattting.SelectedText = "\nServer:     " + tbSendChat.Text + "\n";
            
        }

       


       
    }
}




в MyEventArgs.в CS

namespace serverchat
{
    class MyEventArgs : EventArgs
    {
        private TcpClient sock;
        public TcpClient clientSock
        {
            get { return sock; }
            set { sock = value; }
        }

        public MyEventArgs(TcpClient tcpClient)
        {
            sock = tcpClient;
        }


    }
}

Richard MacCutchan

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

Member 14150101

Спасибо за ваш совет, я воссоздам свой вопрос.

1 Ответов

Рейтинг:
2

Graeme_Grant

Вам было бы лучше использовать Помощью SignalR[^]. Microsoft docs включает в себя пример приложения для чата[^].

Вот пример статьи приложения чата здесь на CodeProject, которая делает именно то, что вы хотите: SignalChat: приложение для чата WPF &SignalR[^]


Maciej Los

5ed!

Graeme_Grant

Спасибо :)

Member 14150101

спасибо за ваше предложение.