client server chatclient fehler in buch (synclock) ???



  • hallo

    habe mir das buch "Practical .NET 2.0 Networking Projects" zugelegt
    dort erklärt der autor ein einfaches chat-programm (client/server - siehe unten) - nichts spezielles

    er erklärt aber folgendes:

    "One issue to note in the previous code is that you need to use the SyncLock (lock in C#) statement to prevent multiple threads from using the NetworkStream object.
    This scenario is
    likely to occur when your server is connected to multiple clients and all of them are trying to access the NetworkStream object at the same time."

    ich kann mir aber nicht erklären wieso die aussage für den unten angeführten code zutreffen sollte, denn es wird ja immer ein neuer ChatClient instanziiert (für jede client verbindung) ?

    auch wenn mehrere clients connected sind, hat jeder seinen eigenen chatclient - oder verstehe ich etwas falsch ?

    vielleicht kann mir jemand helfen

    danke

    //PROGRAM.CS
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    using System.Net.Sockets;
    
    namespace server_CS
    {
    class Program
    {
    const int portNo = 500;
    static void Main(string[] args)
    {
    System.Net.IPAddress localAdd = System.Net.IPAddress.Parse("127.0.0.1");
    TcpListener listener = new TcpListener(localAdd, portNo);
    listener.Start();
    while (true)
    {
    ChatClient user = new ChatClient(listener.AcceptTcpClient());
    }
    }
    }
    }
    
    //CHATCLIENT.CS
    using System;
    using System.Collections.Generic;
    using System.Text;
    
    using System.Net.Sockets;
    using System.Collections;
    
    namespace server_CS
    {
    class ChatClient
    {
    public static Hashtable AllClients =
    new Hashtable();
    private TcpClient _client;
    private string _clientIP;
    private string _ClientNick;
    private byte[] data;
    private bool ReceiveNick = true;
    
    public ChatClient(TcpClient client)
    {
    _client = client;
    _clientIP = client.Client.RemoteEndPoint.ToString();
    AllClients.Add(_clientIP, this);
    
    data = new byte[_client.ReceiveBufferSize];
    _client.GetStream().BeginRead(data, 0, System.Convert.ToInt32(_client.ReceiveBufferSize), ReceiveMessage, null);
    }
    
    public void SendMessage(string message)
    {
    try
    {
    System.Net.Sockets.NetworkStream ns;
    lock (_client.GetStream())
    {
    ns = _client.GetStream();
    }
    byte[] bytesToSend = System.Text.Encoding.ASCII.GetBytes(message);
    ns.Write(bytesToSend, 0, bytesToSend.Length);
    ns.Flush();
    }
    catch (Exception ex)
    {
    Console.WriteLine(ex.ToString());
    }
    }
    
    public void ReceiveMessage(IAsyncResult ar)
    {
    int bytesRead;
    try
    {
    lock (_client.GetStream())
    {
    bytesRead = _client.GetStream().EndRead(ar);
    }
    if (bytesRead < 1)
    {
    AllClients.Remove(_clientIP);
    Broadcast(_ClientNick + " has left the chat.");
    return;
    }
    else
    {
    string messageReceived = System.Text.Encoding.ASCII.GetString(data, 0, bytesRead);
    if (ReceiveNick)
    {
    _ClientNick = messageReceived;
    Broadcast(_ClientNick + " has joined the chat.");
    ReceiveNick = false;
    }
    else
    {
    Broadcast(_ClientNick + ">" + messageReceived);
    }
    }
    lock (_client.GetStream())
    {
    _client.GetStream().BeginRead(data, 0, System.Convert.ToInt32(_client.ReceiveBufferSize),ReceiveMessage, null);
    }
    }
    catch (Exception ex)
    {
    AllClients.Remove(_clientIP);
    Broadcast(_ClientNick + " has left the chat.");
    }
    }
    public void Broadcast(string message)
    {
    Console.WriteLine(message);
    foreach (DictionaryEntry c in AllClients)
    {
    ((ChatClient)(c.Value)).SendMessage(message + Environment.NewLine);
    }
    }
    }
    }
    


  • gerdi schrieb:

    auch wenn mehrere clients connected sind, hat jeder seinen eigenen chatclient - oder verstehe ich etwas falsch ?

    Aber sie connecten doch alle auf den _gleichen_ Server, oder? Und auf dem Server muss das thread-safe sein...



  • aber ich habe ja pro client am server eine instanz vom chatClient und somit auch _client ??





  • 1. Da Du nur den client-Code geposted hast kann hier keiner wissen wie Dein sever arbeitet und ob ein locking da notwendig ist oder nicht. Udn wie Alf schon sagte, es gibt mehr als eine Möglichkeit eine Katze zu häuten, bzw einen Chatserver zu implementieren.

    2. Auch Kleinweisch-Beispielcodes können fehlerhaft bzw unvollständig sein. Letzteres ist dabei eher die Regel als die Ausnahme. Schönstes Beispiel ist der "best practice" locking-Beispielcode im C#-Manual der nach wie vor FALSCH ist (was in einem anderen Artikel von Kleinweisch aus dem Jahre 2001 ausführlich beschrieben steht...)

    3. Was meinst Du mit Instanz? eine Instanz der Objectes pro Client oder einen Thread pro Client? Und wieviele Sockets hast Du da pro Client auf dem Server?

    4. Einen Thread pro Client anzulegen mag zwar wie eine gute Idee erscheinen, ist es aber nicht. Bei 2, 3 clients ist das egal, aber bei 200-300 Clients knallt Dir das Betriebssystem damit um die Ohren. Im Schluß muß man also eine Verwaltung in einem (oder nur einer handvoll) Threads machen die jeder für sich mehrere Client-Objekte verwalten. und dann muß man sich schon Gedanken um thread-Safety machen...

    5. Das dumme mit fehlneden Locks ist, daß man in simplen Tests gar nicht bemekrt wenn sie fehlen...



  • hi

    es handelt sich hier eh um den servercode:

    PROGRAM.CS erzeugt bei acceptTcpClient einen neuen chatclien (CHATCLIENT.CS)

    client kann normaler telnet sein

    danke derweil


Anmelden zum Antworten