Ich versuche, einen Befehlszeilen-Chatraum zu bauen, in dem der Server die Verbindungen verarbeitet und Eingaben von einem Client zu allen anderen Clients wiederholt. Momentan ist der Server in der Lage, Eingaben von mehreren Clients zu übernehmen, kann jedoch Informationen nur einzeln an diese Clients zurücksenden. Ich denke mein Problem ist, dass jede Verbindung in einem einzelnen Thread behandelt wird. Wie würde ich zulassen, dass die Threads miteinander kommunizieren oder Daten an jeden Thread senden können?Senden von Daten über NetworkStream mit mehreren Threads
Server Code:
namespace ConsoleApplication
{
class TcpHelper
{
private static object _lock = new object();
private static List<Task> _connections = new List<Task>();
private static TcpListener listener { get; set; }
private static bool accept { get; set; } = false;
private static Task StartListener()
{
return Task.Run(async() =>
{
IPAddress address = IPAddress.Parse("127.0.0.1");
int port = 5678;
listener = new TcpListener(address, port);
listener.Start();
Console.WriteLine($"Server started. Listening to TCP clients at 127.0.0.1:{port}");
while (true)
{
var tcpClient = await listener.AcceptTcpClientAsync();
Console.WriteLine("Client has connected");
var task = StartHandleConnectionAsync(tcpClient);
if (task.IsFaulted)
task.Wait();
}
});
}
// Register and handle the connection
private static async Task StartHandleConnectionAsync(TcpClient tcpClient)
{
// start the new connection task
var connectionTask = HandleConnectionAsync(tcpClient);
// add it to the list of pending task
lock (_lock)
_connections.Add(connectionTask);
// catch all errors of HandleConnectionAsync
try
{
await connectionTask;
}
catch (Exception ex)
{
// log the error
Console.WriteLine(ex.ToString());
}
finally
{
// remove pending task
lock (_lock)
_connections.Remove(connectionTask);
}
}
private static async Task HandleConnectionAsync(TcpClient client)
{
await Task.Yield();
{
using (var networkStream = client.GetStream())
{
if (client != null)
{
Console.WriteLine("Client connected. Waiting for data.");
StreamReader streamreader = new StreamReader(networkStream);
StreamWriter streamwriter = new StreamWriter(networkStream);
string clientmessage = "";
string servermessage = "";
while (clientmessage != null && clientmessage != "quit")
{
clientmessage = await streamreader.ReadLineAsync();
Console.WriteLine(clientmessage);
servermessage = clientmessage;
streamwriter.WriteLine(servermessage);
streamwriter.Flush();
}
Console.WriteLine("Closing connection.");
networkStream.Dispose();
}
}
}
}
public static void Main(string[] args)
{
// Start the server
Console.WriteLine("Hit Ctrl-C to close the chat server");
TcpHelper.StartListener().Wait();
}
}
}
Client-Code:
namespace Client2
{
public class Program
{
private static void clientConnect()
{
TcpClient socketForServer = new TcpClient();
bool status = true;
string userName;
Console.Write("Input Username: ");
userName = Console.ReadLine();
try
{
IPAddress address = IPAddress.Parse("127.0.0.1");
socketForServer.ConnectAsync(address, 5678);
Console.WriteLine("Connected to Server");
}
catch
{
Console.WriteLine("Failed to Connect to server{0}:999", "localhost");
return;
}
NetworkStream networkStream = socketForServer.GetStream();
StreamReader streamreader = new StreamReader(networkStream);
StreamWriter streamwriter = new StreamWriter(networkStream);
try
{
string clientmessage = "";
string servermessage = "";
while (status)
{
Console.Write(userName + ": ");
clientmessage = Console.ReadLine();
if ((clientmessage == "quit") || (clientmessage == "QUIT"))
{
status = false;
streamwriter.WriteLine("quit");
streamwriter.WriteLine(userName + " has left the conversation");
streamwriter.Flush();
}
if ((clientmessage != "quit") && (clientmessage != "quit"))
{
streamwriter.WriteLine(userName + ": " + clientmessage);
streamwriter.Flush();
servermessage = streamreader.ReadLine();
Console.WriteLine("Server:" + servermessage);
}
}
}
catch
{
Console.WriteLine("Exception reading from the server");
}
streamreader.Dispose();
networkStream.Dispose();
streamwriter.Dispose();
}
public static void Main(string[] args)
{
clientConnect();
}
}
}
WOW. Sehr hilfreich. Ja, ich habe meistens nur gegoogelt und zusammengezählt, was ich gefunden hatte, und Fehler ausgebügelt. Du bist wirklich über alles hinaus gegangen für mich und ich schätze es sehr. Ich hatte irgendwie gedacht, dass ich die Kunden speichern musste, aber ich war mir nicht sicher, ob das überflüssig war oder nicht. Vielen Dank für das Aufräumen! – hereswilson
@hereswilson: glücklich zu helfen. Beachten Sie, dass das obige nur ein Beispiel dafür ist, wie Sie etwas tun könnten. Es ist nicht das letzte Wort darüber, wie du es tun sollst. Sie können beispielsweise festlegen, dass die Nachricht auch an den Client gesendet wird, der sie gesendet hat (die Client-Enumeration wird dadurch ein wenig vereinfacht). Beachten Sie auch, dass ich die Synchronisierung für den Relaying-Part geändert habe, indem ich den gesamten Vorgang synchronisiert habe und nicht nur den Teil, an den die Clients gesendet werden. Ich entschied, dass mir das besser gefällt (aus Gründen, die im Kommentar im Code beschrieben sind). –