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

时间:2018-06-22 09:09:59

标签: c# networking tcp client listener

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

我能够从 Client => Server 发送消息,并且消息到达服务器,但是当连接多个客户端时,其他客户端将看不到我的消息。

例如,我有两个客户端连接到侦听器:一个客户端的昵称为“ user1”,另一个客户端的昵称为“ user2”。当user1发送消息时,服务器会接收到该消息。当user2发送消息时,服务器也接收到该消息。但是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);
        }
    }

MessageHelper.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 个答案:

答案 0 :(得分:0)

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

要广播

  1. 在MessageHelper中创建一个事件,并在 Console.WriteLine(GetMessageFormat(message));处引发该事件。
  2. 传递消息 事件中的EventHandler。
  3. 在Client.cs文件中,处理事件以接收所有消息

示例代码

MessageHelper类中,声明事件为

public event EventHandler ReadMessageEvent;

ReadMessage中的Console.WriteLine(GetMessageFormat(message));方法中替换为

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

Client类的try块中,添加以下代码

helper.ReadMessageEvent += ReadMessageEvent_HandleEvent;

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