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

C#TCP:接收从TCPClient发送到TCPListener的数据,c#,networking,tcp,client,listener,C#,Networking,Tcp,Client,Listener,昨天,我启动了一个项目,您可以在C#Console应用程序中与特定聊天室中的人聊天。服务器端有一个TCPListener,它连续侦听传入连接,并在单独的线程上处理每个传入连接。在客户端,您可以通过输入IP地址和昵称连接到此侦听器,并连接到TCPListener 我能够从客户端=>服务器发送消息,消息到达服务器,但当多个客户端连接时,其他客户端将看不到我的消息 例如,我有两个客户端连接到侦听器:一个昵称为“user1”,另一个昵称为“user2”。当user1发送消息时,服务器接收消息。当user

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

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

例如,我有两个客户端连接到侦听器:一个昵称为“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.");
                }
            }
        }
    }
}
public类MessageHelper
{
公共字符串昵称{get;set;}
公共TcpClient客户端{get;set;}
公共网络流{get;set;}
public MessageHelper(TcpClient客户端、NetworkStream)
{
客户=客户;
溪流=溪流;
}
公共静态IpInformation GetIpInformation(TcpClient客户端,bool isRemote=true)
{
字符串完整主机名;
如果(isRemote)
fullHostname=client.client.RemoteEndPoint.ToString();
其他的
fullHostname=client.client.LocalEndPoint.ToString();
IpInformation info=新IpInformation()
{
IpAddress=IpAddress.Parse(fullHostname.Split(“:”)[0]),
Port=int.Parse(fullHostname.Split(“:”)[1])
};
退货信息;
}
公共字符串GetMessageFormat(字符串消息)
{
DateTime DateTime=DateTime.Now;
返回$“[{dateTime.ToShortTimeString()}]:{message}”;
}
public void ReadMessage()
{
字节[]数据=新字节[256];
int byteCount=Stream.Read(数据,0,数据.长度);
字符串ipAddress=GetIpInformation(客户端).ipAddress.ToString();
字符串消息=Encoding.ASCII.GetString(数据,0,字节数);
//检查消息是否为命令
if(message.StartsWith(“!”)
{
尝试
{

//命令格式为>>!Command=value在
MessageHelper.cs
class
ReadMessage
方法中,您没有存储消息或者没有将消息广播给所有客户端

播送

  • 在MessageHelper中创建事件,并在
    
    Console.WriteLine(GetMessageFormat(message));
  • 把消息传进来 事件中的EventHandler
  • 在Client.cs文件中,处理事件以接收所有消息
  • 示例代码

    MessageHelper
    类中将事件声明为

    public event EventHandler ReadMessageEvent;
    
    控制台的
    ReadMessage
    方法中。WriteLine(GetMessageFormat(message));
    替换为

    if (ReadMessageEvent!= null)
            ReadMessageEvent.Invoke(GetMessageFormat(message), null);
    
    Client
    类中,尝试块添加以下代码

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

    最简单的方法是在服务器上接收消息并将其发送给所有连接的用户clients@Kaj这听起来很有希望!唯一的问题是我不知道如何实现这一点,因为我对使用套接字编程相当陌生。套接字编程需要很多理解。但我会告诉你这个想法。列出TcpCl类型客户端,然后当客户端连接时,将其添加到列表中。当服务器接收到消息时,循环列表并将消息发送给列表中除发件人以外的所有客户端。@Kaj我一直在考虑这个问题。非常感谢,我会再试一次。使用TCP,一个连接上只能有一个发件人和收件人。So为了让每个人都能获得消息,服务器必须向所有客户端发送每个发送/接收消息,以便每个人都能获得所有流量。因此,服务器需要有一个列表,以便能够向所有客户端发送消息。要获得该列表,您需要创建自己的接受方法,该方法接受每个新连接,并在断开连接时添加到列表中让我们从列表中删除套接字。感谢您的回答!我将了解此方法是否适用于我。这应该是一个注释,而不是一个答案,因为它不是一个完整的解决方案!@Kaj Updaqted answer,带有示例代码。我希望这足以成为一个答案