代码之家  ›  专栏  ›  技术社区  ›  Kees van Voorthuizen

C#TCP:从TCPClient接收发送到TCPListener的数据

  •  0
  • Kees van Voorthuizen  · 技术社区  · 6 年前

    昨天我开始了一个项目,你可以在一个C#控制台应用程序中与特定聊天室的人聊天。服务器端有一个TCPListener,它持续监听传入连接,并在单独的线程上处理每个传入连接。在客户端,您可以通过输入IP地址和昵称来连接到此侦听器,并连接到TCPListener。

    我可以从 客户端=>服务器 消息到达服务器,但是当多个客户端连接时,其他客户端将看不到我的消息。

    例如,我有两个客户端连接到侦听器:一个昵称为“user1”,另一个昵称为“user2”。当user1发送消息时,服务器接收到它。当用户2发送消息时,服务器也会收到它。但是user1看不到user2向服务器发送了什么,反之亦然。

    我的问题

    我的问题是:

    如何使连接到TCPListener的tcpclient接收来自其他tcpclient的消息?

    附加信息

    我添加了一些注释,以便于理解我使用的方法。侦听器侦听端口8345。

    顾客

        public static void Connect(string serverIP, string nickname)
        {
            try
            {
                TcpClient client = new TcpClient();
                NetworkStream stream = null;
                MessageHelper helper = null;
    
                client.Connect(serverIP, PORT);
                stream = client.GetStream();
                helper = new MessageHelper(client, stream);
                helper.SendMessage($"!nickname={nickname}");
    
                Log("Connected!");
    
                Thread receiveThread = new Thread(new ThreadStart(() =>
                {
                    while (true)
                    {
                        // Get messages from other senders
                        helper.ReadMessage();
                        Thread.Sleep(300);
                    }
                }));
    
                receiveThread.Start();
    
                while (Util.IsClientConnected(client))
                {
                    Console.Write(" > ");
                    var message = Console.ReadLine();
    
                    if (!string.IsNullOrWhiteSpace(message))
                    {
                        try
                        {
                            helper.SendMessage(message);
                        }
                        catch (IOException)
                        {
                            Log("The server closed unexpectedly.");
                        }
                    }                        
                }
    
                Log("Disconnected.");
            }
            catch (SocketException ex)
            {
                Log("SocketException: " + ex.ToString());
            }
        }
    

    服务器

        public static bool IsListening;
        private const int PORT = 8345;
    
        public static void HandleClient(object _client)
        {
            TcpClient client = (TcpClient)_client;
            NetworkStream stream = null;
            MessageHelper helper = null;
            var ipAddress = MessageHelper.GetIpInformation(client).IpAddress.ToString();
            stream = client.GetStream();
            helper = new MessageHelper(client, stream);
    
            // Initial read, assuming this will be a '!nickname' command it will set the nickname
            helper.ReadMessage();
            Log($"{helper.Nickname} ({ipAddress}) connected.");
    
            while (Util.IsClientConnected(client))
            {
                try
                {
                    // Check every 300 ms for a new message and print it to the screen.
                    helper.ReadMessage();
                }
                catch (IOException)
                {
                    Log($"{helper.Nickname} disconnected.");
                }
    
                Thread.Sleep(300);
            }
        }
    
        public static void StartListener()
        {
            TcpListener listener = null;
            IPAddress ipAddress = IPAddress.Any;
    
            listener = new TcpListener(ipAddress, PORT);
            try
            {
                listener.Start();
                IsListening = true;
                Log($"Listener started at {ipAddress}:{PORT}.");
            }
            catch (Exception ex)
            {
                Log("Error: " + ex.ToString());
            }
    
            while (IsListening)
            {
                // Check if listener is handling a pending connection, if not, wait 250 ms.
                if (!listener.Pending())
                {
                    Thread.Sleep(250);
                    continue;
                }
    
                // Client connected, handle at a separate thread.
                TcpClient client = listener.AcceptTcpClient();
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
                clientThread.Start(client);
            }
        }
    

    消息帮助程序.cs

    public class MessageHelper
    {
        public string Nickname { get; set; }
        public TcpClient Client { get; set; }
        public NetworkStream Stream { get; set; }
    
        public MessageHelper(TcpClient client, NetworkStream stream)
        {
            Client = client;
            Stream = stream;
        }
    
        public static IpInformation GetIpInformation(TcpClient client, bool isRemote = true)
        {
            string fullHostname;
    
            if (isRemote)
                fullHostname = client.Client.RemoteEndPoint.ToString();
            else
                fullHostname = client.Client.LocalEndPoint.ToString();
    
            IpInformation info = new IpInformation()
            {
                IpAddress = IPAddress.Parse(fullHostname.Split(':')[0]),
                Port = int.Parse(fullHostname.Split(':')[1])
            };
    
            return info;
        }
    
        public string GetMessageFormat(string message)
        {
            DateTime dateTime = DateTime.Now;
            return $" [{dateTime.ToShortTimeString()}] <{Nickname}>: {message}";
        }
    
        public void ReadMessage()
        {
            byte[] data = new byte[256];
            int byteCount = Stream.Read(data, 0, data.Length);
            string ipAddress = GetIpInformation(Client).IpAddress.ToString();
            string message = Encoding.ASCII.GetString(data, 0, byteCount);
    
            // Check if message is a command
            if (message.StartsWith("!"))
            {
                try
                {
                    // Command format is >> !command=value <<
                    string[] commandSplit = message.TrimStart('!').Split('=');
                    string command = commandSplit[0];
                    string value = commandSplit[1];
    
                    if (command == "nickname")
                    {
                        Nickname = value;
                    }
                    else
                    {
                        Log("This command is not found.");
                    }
                }
                catch (Exception)
                {
                }
            }
            else
            {
                // Regular message, print it to the console window.
                Console.ForegroundColor = ConsoleColor.DarkYellow;
                Console.WriteLine(GetMessageFormat(message));
                Console.ResetColor();
            }
        }
    
        public void SendMessage(string message)
        {
            byte[] data = Encoding.ASCII.GetBytes(message);
            Stream.Write(data, 0, data.Length);
    
            if (!message.StartsWith("!"))
            {
                Console.ForegroundColor = ConsoleColor.Green;
                Console.WriteLine(GetMessageFormat(message));
                Console.ResetColor();
            }
            else
            {
                // Issue the '!nickname' command
                if (message.StartsWith("!nickname"))
                {
                    try
                    {
                        Nickname = message.TrimStart('!').Split('=')[1];
                    }
                    catch (IndexOutOfRangeException)
                    {
                        Log("Please enter an argument for this command.");
                    }
                }
            }
        }
    }
    
    1 回复  |  直到 6 年前
        1
  •  0
  •   Bhuvan Ram    6 年前

    MessageHelper.cs ReadMessage 方法您没有存储消息,或者没有将消息广播给所有客户端。

    广播

    1. 在MessageHelper中创建一个事件,并在 Console.WriteLine(GetMessageFormat(message)); .
    2. 把消息传进来 事件中的事件处理程序。
    3. 在Client.cs文件中,处理事件以接收所有消息

    示例代码

    MessageHelper 类声明事件为

    public event EventHandler ReadMessageEvent;
    

    阅读消息 方法 Console.WriteLine(GetMessageFormat(message)); 替换为

    if (ReadMessageEvent!= null)
            ReadMessageEvent.Invoke(GetMessageFormat(message), null);
    

    Client 类try block add below代码

    helper.ReadMessageEvent += ReadMessageEvent_HandleEvent;
    
     private void ReadMessageEvent_HandleEvent(object sender, EventArgs e)
     {
       string message = sender as string;
       Console.WriteLine(message);           
     }