TCP Chat 2 Schwierigkeiten.

  • VB.NET

Es gibt 12 Antworten in diesem Thema. Der letzte Beitrag () ist von Dustin.

    TCP Chat 2 Schwierigkeiten.

    Hallo liebe Community!
    Ich arbeite derzeit an einem TCP Multichat.

    Ich habe bisher alles selber gefunden und auch verstanden, aber mir bleiben trotzdem keine Umsatzideen, wie ich zum einen einen einzelnden User vom Chat kicken kann, indem ich einfach den Text "/kick USERNAME" zum Server sende. Zum zweiten versuche ich einen Text nur an einen bestimmten User zu senden, indem man einfach den Text "/USERNAME DERTEXT" zum Server sendet.

    Ich habe mir bei der Kickfunktion schon einige Gedanken gemacht, leider klappte das nicht.
    Ich habe es so versucht:

    VB.NET-Quellcode

    1. If Console.ReadLine = "/kick " & c.nick then
    2. c.stream.close
    3. End If


    Jedoch wird hier dann nur 1 Verbindung angenommen, wenn sich ein 2.ter User zum Chat verbindet wird dieser erst zugelassen wenn der Kickbefehl ausgeführt wurde. :(

    Und bei meiner 2.ten Idee, wo man einen Text zu nur einem Client senden will, habe ich noch keine Ideen und hoffe auch hier auf eure Hilfe.

    Der Chatserver Source ist folgender Maßen:

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.IO
    3. Imports System.Net
    4. Module Module1
    5. Private server As TcpListener
    6. Private client As New TcpClient
    7. Private ipendpoint As IPEndPoint = New IPEndPoint(IPAddress.Any, 8000) ' eingestellt ist port 8000. dieser muss ggf. freigegeben sein!
    8. Private list As New List(Of Connection)
    9. Private Structure Connection
    10. Dim stream As NetworkStream
    11. Dim streamw As StreamWriter
    12. Dim streamr As StreamReader
    13. Dim nick As String ' natürlich optional, aber für die identifikation des clients empfehlenswert.
    14. End Structure
    15. Private Sub SendToAllClients(ByVal s As String)
    16. For Each c As Connection In list ' an alle clients weitersenden.
    17. Try
    18. c.streamw.WriteLine(s)
    19. c.streamw.Flush()
    20. Catch
    21. End Try
    22. Next
    23. End Sub
    24. Sub Main()
    25. Console.ForegroundColor = ConsoleColor.Green
    26. Console.WriteLine("Der Chatserver ist Online und bereit für einkommende Verbindungen!")
    27. Console.ForegroundColor = ConsoleColor.White
    28. server = New TcpListener(ipendpoint)
    29. server.Start()
    30. While True ' wir warten auf eine neue verbindung...
    31. client = server.AcceptTcpClient
    32. Dim c As New Connection ' und erstellen für die neue verbindung eine neue connection...
    33. c.stream = client.GetStream
    34. c.streamr = New StreamReader(c.stream)
    35. c.streamw = New StreamWriter(c.stream)
    36. c.nick = c.streamr.ReadLine ' falls das mit dem nick nicht gewünscht, auch diese zeile entfernen.
    37. list.Add(c) ' und fügen sie der liste der clients hinzu.
    38. Userlist()
    39. Console.WriteLine("[" & TimeString & "] " & c.nick & " ist dem Chat beigetreten!")
    40. ' falls alle anderen das auch lesen sollen können, an alle clients weiterleiten. siehe SendToAllClient
    41. Dim t As New Threading.Thread(AddressOf ListenToConnection)
    42. t.Start(c)
    43. End While
    44. End Sub
    45. Private Sub ListenToConnection(ByVal con As Connection)
    46. Do
    47. Try
    48. Dim tmp As String = con.streamr.ReadLine ' warten, bis etwas empfangen wird...
    49. Console.WriteLine("[" & Date.Now & "] " & con.nick & ": " & tmp)
    50. SendToAllClients("[" & TimeString & "] " & con.nick & ": " & tmp) ' an alle clients weitersenden.
    51. Catch ' die aktuelle überwachte verbindung hat sich wohl verabschiedet.
    52. list.Remove(con)
    53. Console.WriteLine("[" & TimeString & "] " & con.nick & " hat den Chat verlassem!")
    54. Exit Do
    55. End Try
    56. Loop
    57. End Sub
    58. Public Sub Userlist()
    59. Dim users As String = ""
    60. For Each Connections In list
    61. users = users & Connections.nick.ToString & ","
    62. SendToAllClients("/u " & users)
    63. Next
    64. End Sub
    65. End Module


    Und der Clientsource lautet so:

    VB.NET-Quellcode

    1. Imports System.Net.Sockets
    2. Imports System.IO
    3. Public Class Form6
    4. Private stream As NetworkStream
    5. Private streamw As StreamWriter
    6. Private streamr As StreamReader
    7. Private client As New TcpClient
    8. Private t As New Threading.Thread(AddressOf Listen)
    9. Private Delegate Sub DAddItem(ByVal s As String)
    10. Private nick As String = Form1.TextBox1.Text
    11. Public Sub AddItem(ByVal s As String)
    12. Dim userlist As String()
    13. If s.StartsWith("/u ") Then
    14. userlist = s.Remove(0, 3).Split(",")
    15. ListBox1.Items.Clear()
    16. ListBox1.Items.AddRange(userlist)
    17. Else
    18. ListBox4.Items.Add(s)
    19. End If
    20. End Sub
    21. Private Sub Form4_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    22. Try
    23. client.Connect("127.0.0.1", 8000) ' hier die ip des servers eintragen.
    24. ' da dieser beim testen wohl lokal läuft, hier die loopback-ip 127.0.0.1.
    25. If client.Connected Then
    26. stream = client.GetStream
    27. streamw = New StreamWriter(stream)
    28. streamr = New StreamReader(stream)
    29. streamw.WriteLine(nick) ' das ist optional.
    30. streamw.Flush()
    31. t.Start()
    32. ListBox1.Items.Add(nick)
    33. Else
    34. MessageBox.Show("Verbindung zum Server nicht möglich!")
    35. Me.Close()
    36. End If
    37. Catch ex As Exception
    38. MessageBox.Show("Verbindung zum Server nicht möglich!")
    39. Me.Close()
    40. End Try
    41. End Sub
    42. Private Sub Listen()
    43. While client.Connected
    44. Try
    45. Me.Invoke(New DAddItem(AddressOf AddItem), streamr.ReadLine)
    46. Catch
    47. MessageBox.Show("Verbindung zum Server nicht möglich!")
    48. Me.Close()
    49. End Try
    50. End While
    51. End Sub
    52. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    53. streamw.WriteLine(TextBox1.Text)
    54. streamw.Flush()
    55. TextBox1.Clear()
    56. End Sub
    57. Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    58. End Sub
    59. End Class


    Die Grundstrukturen sind von diesen Tutorial: [VB.NET] Multiserver (TCP)?

    Mit freundlichem Gruß-

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Dustin“ ()

    Und was davon ist von dir ? xD

    VB.NET-Quellcode

    1. Dim tmp As String = con.streamr.ReadLine ' warten, bis etwas empfangen wird...
    2. 'Hier an dieser Stelle kommen alle Nachrichten an und werden verarbeitet.
    3. 'Sagen wir, dU (UserNick:Dustin) schreibst /kick Prollo (usernick der connected ist)
    4. 'Dann ist tmp eben = "/kick Prollo"
    5. 'D.H. hier kannst du die Commandos auswerten.
    6. 'Für den Anfang reicht sicher ein IF tmp.startswith("/kick ") Then CheckIfUserIsConnectedandKickHim(tmp.substring(6))
    7. 'Du schreibst also eine Prozedur zB Namens CheckIfUserIsConnectedandKickHim(byval USername)
    8. 'Dort durchläufst du alle Connections (Ähnlich wie bei SendToAllClients) und prüfst, ob der Username verbunden ist.
    9. 'Wenn ja dann Con.close und SendToAllClients("User soundso wurde von Nick gekickt)
    10. Console.WriteLine("[" & Date.Now & "] " & con.nick & ": " & tmp)
    11. SendToAllClients("[" & TimeString & "] " & con.nick & ": " & tmp) ' an alle clients weitersenden.


    Probiere einfach aus, am Server die Befehle auszuwerten. Dh. überleg dir ein System wie der Server die Befehle empfängt.
    Du kannst auch an den Clients die Befehle schon vereinfachen.
    Das heisst, sendet der User im Client den Befehl "/KICK Irgendwas" prüft das CLient programm den Befehl. Ist der BEfehl korrekt und validiert, sendet der Client gar nicht mehr den Text sondern nur noch einen definierten Befehl wie zB "1Username". Oder irgendwas dergleichen, dieser Befehl sollte natürlich möglichst eindeutig sein, und am besten kurz. zB 1 Startbit eines Bytes wird bei Befehlen so und so gesetzt, bei text eben anders.
    Der Vorteil ist klar, der Server muss weniger prüfen und hat daher weniger Last.
    Der Nachteil, bei neuen Befehlen müssen die Clients geupdatet werden.
    Du musst dir sozusagen dein eigenes Anwendungsprotokoll schreiben.
    Ein verständlich einfaches Beispiel wäre zB das IRC Protokoll.

    ein bissl selber tüfteln und dann schaffst das schon ^^

    Gruss Mono
    Das ist meine Signatur und sie wird wunderbar sein!
    also das Kicken macht man logischerweiße auf der Serverseite...
    Hier mal eigt. C&P Code, was aber noch Fehler haben könnte, da es ausm Kopf geschrieben ist:

    VB.NET-Quellcode

    1. Private Sub ListenToConnection(ByVal con As Connection)
    2. Do
    3. Try
    4. Dim tmp As String = con.streamr.ReadLine ' warten, bis etwas empfangen wird...
    5. If tmp.StartsWith("/kick ") Then'reagieren auf den Kick Befehl
    6. Dim userToKick As String = tmp.Substring(6)'Auslesen des Benutzernamens
    7. For Each Connections In list'durchlaufen aller Benutzer
    8. If Connections.nick = userToKick Then'Wenn der Username dem entspricht der gekickt werden soll
    9. Connections.streamr.Close()'Schließen des StreamReaders
    10. Connections.streamw.Close()'Schließen des StreamWriters
    11. Connections.stream.Close()'Verbindung trennen
    12. list.Remove(Connections)'Benutzer aus der Liste löschen
    13. End If
    14. Next
    15. Else
    16. Console.WriteLine("[" & Date.Now & "] " & con.nick & ": " & tmp)
    17. SendToAllClients("[" & TimeString & "] " & con.nick & ": " & tmp) ' an alle clients weitersenden.
    18. End if
    19. Catch ' die aktuelle überwachte verbindung hat sich wohl verabschiedet.
    20. list.Remove(con)
    21. Console.WriteLine("[" & TimeString & "] " & con.nick & " hat den Chat verlassem!")
    22. Exit Do
    23. End Try
    24. Loop
    25. End Sub


    *Aus anderem Thread hierher verschoben*
    Ich wollte auch mal ne total überflüssige Signatur:
    ---Leer---

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Okay, habs verstanden danke!
    Wie könnte so eine Abfrage denn aussehen, also wo man Abfragt ob der User connected ist?
    Bei mir siehts die Prozedur jetzt so asu:

    VB.NET-Quellcode

    1. Private Sub Useronline(ByVal con As Connection)
    2. End Sub
    Habs schon zum Teil hinbekommen :D
    Aber leider wird nicht der gewünschte Client gekappt, sondern der eigene.
    Was ist mein Fehler?

    VB.NET-Quellcode

    1. Private Sub ListenToConnection(ByVal con As Connection)
    2. Do
    3. Try
    4. Dim tmp As String = con.streamr.ReadLine ' warten, bis etwas empfangen wird...
    5. If tmp.StartsWith("/kick ") Then
    6. Useronline(con)
    7. End If
    8. Console.WriteLine("[" & Date.Now & "] " & con.nick & ": " & tmp)
    9. SendToAllClients("[" & TimeString & "] " & con.nick & ": " & tmp) ' an alle clients weitersenden.
    10. Catch ' die aktuelle überwachte verbindung hat sich wohl verabschiedet.
    11. list.Remove(con)
    12. Console.WriteLine("[" & TimeString & "] " & con.nick & " hat den Chat verlassem!")
    13. Exit Do
    14. End Try
    15. Loop
    16. End Sub


    Prozedur:

    VB.NET-Quellcode

    1. Private Sub Useronline(ByVal con As Connection)
    2. If con.nick = client.Connected Then
    3. con.nick = client.SendTimeout
    4. End If
    5. End Sub
    Der Fehler ist, das du prüfst, ob der NICK existiert, der den Befehl gesendet hat.
    Davon darf man ungeprüft ausgehen ^^
    Du musst natürlich den Nick prüfen, der in der Variable tmp hinter "/kick " kommt.
    Der 2, Fehler ist,
    du liest nicht, was ich schreibe.
    Schau dir doch mal SendToAllClients an.
    Was wird dort gemacht!!!!
    Offensichtlich verstehst du es noch nicht!
    Du musst ja ALLE Verbundenen Clients auf ihren NICK prüfen.
    Für jede CONNECTION, die am Server ist. Oder du nutzt die METHODE 'FIND' der Klasse LIST(OF ).
    Und suchst nach der CONNECTION, mit dem entsprechendem USERNAME!


    Gruss
    Das ist meine Signatur und sie wird wunderbar sein!
    Das ist das selbe Prinzip..nur das du SendToAllClients nicht aufrufst.
    Überleg dir einen Befehl + Username zB /query Username TEXT.

    Sollte tmp mit "/query " starten, dann sende an den Nick der folgt, falls dieser eine Connection hat.
    Wenn nicht, sende zurück, username nicht gefunden. Wenn ja, sende an die gefundene Connection den Rest der Nachricht.
    SendToAllClients darf dann aber nicht mehr aufgerufen werden.
    Das ist meine Signatur und sie wird wunderbar sein!
    Habe es jetzt mal so versucht:

    VB.NET-Quellcode

    1. If tmp.StartsWith("/msgtouser ") Then
    2. Dim MsgToOneUser As String = tmp.Substring(11)
    3. For Each Connection In list
    4. If Connection.nick = MsgToOneUser Then
    5. con.streamw.WriteLine(tmp, tmp.Substring(11))
    6. End If
    7. Next
    8. End If


    Steht in der SendToAllCLient Sub, da ich nicht weüsste wo ich essonst reinschreiben könnte.

    Aber bei den COdewird der Text trotzdem an alle gesendet.