C#TCP:接收从TCPClient发送到TCPListener的数据
昨天,我启动了一个项目,您可以在C#Console应用程序中与特定聊天室中的人聊天。服务器端有一个TCPListener,它连续侦听传入连接,并在单独的线程上处理每个传入连接。在客户端,您可以通过输入IP地址和昵称连接到此侦听器,并连接到TCPListener 我能够从客户端=>服务器发送消息,消息到达服务器,但当多个客户端连接时,其他客户端将看不到我的消息 例如,我有两个客户端连接到侦听器:一个昵称为“user1”,另一个昵称为“user2”。当user1发送消息时,服务器接收消息。当user2发送消息时,服务器也会收到它。但是user1看不到user2发送给服务器的内容,反之亦然 我的问题 我的问题是: 如何使连接到TCPListener的TcpClient接收来自其他TcpClient的消息 其他信息 我添加了一些注释,以便于理解我使用的方法。侦听器在端口8345上侦听 客户端C#TCP:接收从TCPClient发送到TCPListener的数据,c#,networking,tcp,client,listener,C#,Networking,Tcp,Client,Listener,昨天,我启动了一个项目,您可以在C#Console应用程序中与特定聊天室中的人聊天。服务器端有一个TCPListener,它连续侦听传入连接,并在单独的线程上处理每个传入连接。在客户端,您可以通过输入IP地址和昵称连接到此侦听器,并连接到TCPListener 我能够从客户端=>服务器发送消息,消息到达服务器,但当多个客户端连接时,其他客户端将看不到我的消息 例如,我有两个客户端连接到侦听器:一个昵称为“user1”,另一个昵称为“user2”。当user1发送消息时,服务器接收消息。当user
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
classReadMessage
方法中,您没有存储消息或者没有将消息广播给所有客户端
播送
在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,带有示例代码。我希望这足以成为一个答案