[TCP] Verbindungsprobleme

Übersicht BlitzBasic Beginners-Corner

Neue Antwort erstellen

DerKeks

Betreff: [TCP] Verbindungsprobleme

BeitragSa, Dez 27, 2008 2:30
Antworten mit Zitat
Benutzer-Profile anzeigen
hey leute,
habe mal wieder ein TCP-Problem...
habe mich mal wieder an nem Chat versucht und soweit alles ok...
bis auf 2 probleme..

1)
Habe insgesamt 4 "actions" (_new_user, _in_msg, _leave_user und _server_close) der server liest die ersten 3 aus und kann die letzte senden (logisch). das problem liegt darin, dass er die "_new_user" actions ohne prbleme behandelt, die entsprechenden Types anlegt und allen verbundenen clients bescheid gibt. nur wenn einer eine nachricht schreibt ("_in_msg") oder den chat verlässt ("_leave_user") werden diese beiden actions zwar am client abgesendet (mit debuglog geprüft) aber kommen am server nicht an (auch so geprüft) ich kann clints verbinden soviele ich will, es kommt immer _new_user an im stream aber die anderen beiden actions kommen nie am server an....
habe echt kaum ne ahnung woran es liegt dass nur eine von 3 actions geprüft/behandelt wird...

2)
das ende des servers:
ESC -> Message an Alle (Server closing) -> Server closen (CloseTCPServer) -> End
die nachricht von wegen server closing kommt bei den clients an, nur direkt nach dem senden dieser nachrichten bekommen ich am Server nen MAV ... Wenn ich das im debugmodus mache kriegen ich nen c-runtime error irgendwas mit program terminating... unexpected oder so. kann ich bei bedarf nen screen von machen, denn es war soweit ich weiss eine fehlernummer bei.

hier noch ein screen : 2 mal verbunden und geschrieben, nur die connects kamen am server an..
http://file.qip.ru/download/69...7-74f2c4f8
(einmal aufs bild klicken zum anzeigen und dann rechtsklick -> grafik anzeigen. ist QIP photo hosting Wink )

bei bedarf poste ich auch code, nur bescheid sagen Wink

hoffe ihr könnt mir da irgendwie helfen...

Holzchopf

Meisterpacker

BeitragSa, Dez 27, 2008 14:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Es wird schwierig, dir ohne Code helfen zu wollen. Und das stückchen Code, dass man auf dem Screen sieht, hilft mir auch nicht gerade weiter.

Nun... ich rate einfach mal wild drauflos:
zu 1) das klingt ganz so, als ob du für jede IF-Abfrage den Nachrichtentypen neu auslesen würdest... Also würde nur beim ersten If ReadLine auch der Nachrichtentyp abgefragt, die anderen würden bereits auf irgendwelche Daten zugreiffen wollen.
Zudem würde ich dir empfehlen, die Nachrichtentypen nicht per Line, sondern per Byte zu definieren. Spart schon mal ein wenig Netzwerkverkehr...

zum 2) kann ich dir leider grad absolut nicht helfen =/ habe ich nämlich noch nie erlebt.

mfG
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

DerKeks

BeitragSa, Dez 27, 2008 15:53
Antworten mit Zitat
Benutzer-Profile anzeigen
okay dann geb ich euch mal den code Wink
so schauts im moment beim server aus :
Code: [AUSKLAPPEN]
AppTitle "TCP-Chat | Server"

Type user
   Field ip$, name$, stream, admin
End Type

port = 200

Print "|= Server wird gestartet..."
Print

stream = CreateTCPServer(port)
If stream <> 0
   Print "|= Server gestartet!"
   Print
   CountHostIPs("localhost")
   Print "|+ IP : " + DottedIP$(HostIP(1))
   Print "|+ Port : " + port
   Print
Else
   Print "|= Server konnte nicht gestartet werden."
   Print "Prüfen sie die Firewall-/Rooter-Einstellungen"
   Print
   Print "*Taste drücken*"
   WaitKey
   End
EndIf

Color 000, 255, 000
Print "=============================="
Print "=====       Online       ====="
Print "=============================="
Color 255, 255, 255   
Print
Print "|= Suche Verbindungen..."
Print
Print
Print "=============================="
Print
Print

While Not KeyHit(1)
   in = AcceptTCPStream(stream)
   If in
      in_msg$ = ReadLine(in)
      DebugLog "in_msg$ : "+in_msg$
      Select in_msg$
      Case "_new_user"
         ip$ = ReadLine$(in)
         name$ = ReadLine$(in)
         admin = ReadLine(in)
         
         u.user = New user
         u\ip$ = ip$
         u\name$ = name$
         u\stream = in
         u\admin = admin
         Print "[SYS] - New User '"+name$+"' joined the room"
         If admin = 1
            Print "[SYS] - He is Admin"
         Else
            Print "[SYS] - He is User"
         EndIf
         
         For o.user = Each user
            If o\stream <> in
               WriteLine o\stream, "_new_user"
               WriteLine o\stream, name$
            EndIf
         Next
         
         in_msg$ = ReadLine(in)
      Case "_in_msg"
         sender$ = ReadLine(in)
         nachr$ = ReadLine(in)
         
         Print "[MSG] - <"+sender$+"> : "+nachr$
         
         For o.user = Each user
            If o\stream <> in
               WriteLine o\stream, "_in_msg"
               WriteLine o\stream, sender$
               WriteLine o\stream, nachr$
            EndIf
         Next
         
         in_msg$ = ReadLine(in)
      Case "_leave_user"
         leaver$ = ReadLine$(in)
         reason$ = ReadLine$(in)
         
         Print "[SYS] - User '"+leaver$+"' left the room ("+reason$+")"
         
         For o.user = Each user
            If o\stream <> in
               WriteLine o\stream, "_leave_user"
               WriteLine o\stream, leaver$
               WriteLine o\stream, reason$
            Else
               Delete o
            EndIf
         Next
         
         in_msg$ = ReadLine(in)
      End Select         
   EndIf
Wend

Print "[SYS] - Server shutting down..."

For a.user = Each user
   WriteLine a\stream, "_server_close"
Next

CloseTCPServer stream
End


und das ist der client dazu :
Code: [AUSKLAPPEN]
AppTitle "TCP-Chat | Client"

port = 21

Print "Nickname:"
nick$ = Input("")
Print
Print "Server-IP:"
ip$ = Input("")
Print
Print "Verbinde..."

stream = OpenTCPStream(ip$, port)
If stream <> 0
   Print "Verbunden !"
   Print "Anmelden..."
   Print
   CountHostIPs("")
   own_ip$ = DottedIP$(HostIP(1))
   Print "Eigene IP : "+own_ip$
Else
   Print "Server ist offline/existiert nicht!"
   Print "*Taste drücken*"
   WaitKey
   End
EndIf

WriteLine stream, "_new_user"
WriteLine stream, own_ip$
WriteLine stream, nick$
WriteLine stream, 0

Print "Angemeldet!"
Delay 500
Cls
Locate 0, 0

While Not quit = 1
   While ReadAvail(stream)
      in_msg$ = ReadLine(stream)
      If in_msg$ = "_new_user"
         name$ = ReadLine$(stream)
      
         Print "New User '"+name$+"' joined the room"
      ElseIf in_msg$ = "_in_msg"
         sender$ = ReadLine(stream)
         nachr$ = ReadLine(stream)
      
         Print "<"+sender$+"> : "+nachr$
      ElseIf in_msg$ = "_leave_user"
         leaver$ = ReadLine$(stream)
         reason$ = ReadLine$(stream)
      
         Print "User '"+leaver$+"' left the room ("+reason$+")"
      ElseIf in_msg$ = "_server_close"
         Print "Server is closing now..."
         CloseTCPStream stream
         WaitKey
         End
      EndIf
   Wend
   
   If KeyHit(14)
      in$ = Input$(">")
      WriteLine stream, "_in_msg"
      DebugLog "Send : _in_msg"
      WriteLine stream, nick$
      WriteLine stream, in$
      DebugLog "Message : "+in$
      If in$ = "/quit"
         quit = 1
      EndIf
   EndIf
Wend

WriteLine stream, "_leave_user"
WriteLine stream, nick$
WriteLine stream, "pressed ESC"

CloseTCPStream stream
End


hoffe das hilft jetzt ein bissl Wink

Holzchopf

Meisterpacker

BeitragSa, Dez 27, 2008 16:01
Antworten mit Zitat
Benutzer-Profile anzeigen
AcceptTcpStream -> Da steht, du sollst den Befehl nur einmal benutzen und dann das Streamhandle speichern. Danach, um zu prüfen, ob neue Daten da sind, kommt ReadAvail zum Zuge.
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

DerKeks

BeitragSa, Dez 27, 2008 16:03
Antworten mit Zitat
Benutzer-Profile anzeigen
also das AcceptTCPStream vor die schleife?
was wäre dann wenn ein zweiter client dazu kommt? er würde doch nur das erste handle speichern was ankommt. mangels schleife würden die anderen doch dann garnicht mehr erkannt werden?
oder ich versteht nicht wie dus meinst x)

Holzchopf

Meisterpacker

BeitragSo, Dez 28, 2008 17:57
Antworten mit Zitat
Benutzer-Profile anzeigen
So, weil mir grad deftig langweilig war, hab ich kurz n funktionierendes (ja, habs getestet) Beispiel geschrieben. Bitteschön:

Code: [AUSKLAPPEN]
; Definitionen
Const SERVERPORT   = 8080
Const MAXCONN      = 2

Const MSGT_CONNECT      = $00
Const MSGT_ACC         = $01
Const MSGT_SRVFULL      = $02
Const MSGT_NEW         = $03
Const MSGT_DISC         = $04
Const MSGT_SRVCLOSE      = $05
Const MSGT_CONNINFO      = $10
Const MSGT_TEXT         = $20

; Programm
Dim Printed$(17): Global PrintLine

Graphics 400,300,0,2
SetBuffer BackBuffer()
Global TIMER = CreateTimer(60)
AppTitle "TCP Chat"

Type TConnection
   Field ID
   Field Connected
   Field Stream
   Field Name$
End Type
Local Connection.TConnection, SConnection.TConnection
Local ConnectionCnt, ConnectionID

Local Name$

Local IsServer
Local LocalStream = CreateTCPServer( SERVERPORT )
Local LocalConnection.TConnection
; Programm ist host
If LocalStream
   IsServer = True
   Connection = New TConnection
   Connection\ID = 0
   Connection\Connected = False
   LocalConnection = Connection
   LocalConnection\Name = "Server"
   Print "Server gestartet."
; Programm ist client
Else
   IsServer = False
   LocalStream = OpenTCPStream( "127.0.0.1", SERVERPORT )
   Connection = New TConnection
   Connection\ID = 0
   Connection\Connected = True
   Connection\Stream = LocalStream
   WriteByte LocalStream, MSGT_CONNECT
   Print "Verbinde..."
EndIf

; Hauptschleife
Local MsgT
Local TcpIn
While Not KeyDown(1)
   Cls
   If IsServer
      TcpIn = AcceptTCPStream( LocalStream )
      ; Neue Verbindung herstellen
      If TcpIn
         ConnectionID = ConnectionID +1
         Connection = New TConnection
         Connection\ID = ConnectionID
         Connection\Connected = True
         Connection\Stream = TcpIn
      EndIf
   EndIf
   ; Alle Verbindungen prüfen
   For Connection = Each TConnection
      If Connection\Stream
      If ReadAvail( Connection\Stream )
         MsgT = ReadByte( Connection\Stream )
         DebugLog MsgT
         ; Nachrichtentyp Prüfen
         Select MsgT
         ; Verbindungsanfrage
         Case MSGT_CONNECT
            ; Verbindung akzeptieren
            If ConnectionCnt < MAXCONN
               ConnectionCnt = ConnectionCnt +1
               WriteByte Connection\Stream, MSGT_ACC
               WriteInt Connection\Stream, ConnectionID
            ; Server voll
            Else
               WriteByte Connection\Stream, MSGT_SRVFULL
               Delete Connection
            EndIf
         ; Verbindung aufgebaut
         Case MSGT_ACC
            ; Eigene ID auslesen
            ival = ReadInt( Connection\Stream )
            ; Lokale "Connection"-Instanz
            LocalConnection = New TConnection
            LocalConnection\ID = ival
            LocalConnection\Name = "Client " +ival
            
            Print "Verbindung aufgebaut. Angemeldet als: " +LocalConnection\Name
            
            ; Vorstellen
            WriteByte Connection\Stream, MSGT_NEW
            WriteInt Connection\Stream, LocalConnection\ID
            WriteString Connection\Stream, LocalConnection\Name
         ; Verbindung kann nicht aufgebaut werden
         Case MSGT_SRVFULL
            Print "Verbindung kann nicht hergestellt werden,"
            Print "der Server ist voll."
         ; Neuer Benutzer wird vorgestellt
         Case MSGT_NEW
            ival = ReadInt( Connection\Stream )
            stval$ = ReadString( Connection\Stream )
            Connection = GetConnectionById( ival )
            Connection\Name = stval$
            Print Connection\Name +" hat sich angemeldet."
            
            ; Der Server muss die Info an alle anderen Spieler weitergeben
            If IsServer = True
               For SConnection = Each TConnection
                  If SConnection\Connected = True And SConnection <> Connection
                     WriteByte SConnection\Stream, MSGT_NEW
                     WriteInt SConnection\Stream, ival
                     WriteString SConnection\Stream, stval$
                  EndIf
               Next
            ; ... und dem neuen alle Infos zu den anderen Spielern geben
               For SConnection = Each TConnection
                  If SConnection <> Connection
                     WriteByte Connection\Stream, MSGT_CONNINFO
                     WriteInt Connection\Stream, SConnection\ID
                     WriteString Connection\Stream, SConnection\Name
                  EndIf
               Next
            EndIf
         ; Benutzer meldet sich ab
         Case MSGT_DISC
            ival = ReadInt( Connection\Stream )
            Connection = GetConnectionById( ival )
            Print Connection\Name +" hat sich abgemeldet."

            ; Der Server muss die Info an alle anderen Spieler weitergeben
            If IsServer = True
               For SConnection = Each TConnection
                  If SConnection\Connected = True And SConnection <> Connection
                     WriteByte SConnection\Stream, MSGT_DISC
                     WriteInt SConnection\Stream, ival
                  EndIf
               Next
               ConnectionCnt = ConnectionCnt -1
            EndIf
            
            Delete Connection
         ; Server wurde beendet
         Case MSGT_SRVCLOSE
            Print "Server wurde beendet."
            
         ; Verbindungsinfos
         Case MSGT_CONNINFO
            ival = ReadInt( Connection\Stream )
            stval$ = ReadString( Connection\Stream )
            Connection = GetConnectionById( ival )
            Connection\Name = stval
            
            Print "Erhalte Infos zu Teilnehmer " +ival +", Name: " +stval$

         ; Textnachricht
         Case MSGT_TEXT
            ival = ReadInt( Connection\Stream )
            stval$ = ReadLine( Connection\Stream )
            Connection = GetConnectionById( ival )
            
            Print Connection\Name +" sagt:"
            Print stval
            
            ; Der Server muss die Info an alle anderen Spieler weitergeben
            If IsServer = True
               For SConnection = Each TConnection
                  If SConnection\Connected = True And SConnection <> Connection
                     WriteByte SConnection\Stream, MSGT_TEXT
                     WriteInt SConnection\Stream, ival
                     WriteLine SConnection\Stream, stval
                  EndIf
               Next
            EndIf
         End Select
      EndIf
      EndIf
   Next
   
   ; Einfacher Chat
   char = GetKey()
   If char = 8
      txt$ = Left( txt$, Len( txt$ ) -1 )
   ElseIf char = 13
      ; Der Server sendet die Nachricht an alle
      If IsServer = True
         For SConnection = Each TConnection
            If SConnection\Connected = True
               WriteByte SConnection\Stream, MSGT_TEXT
               WriteInt SConnection\Stream, 0
               WriteLine SConnection\Stream, txt$
            EndIf
         Next
      ; Hosts nur an den Server
      Else
         WriteByte LocalStream, MSGT_TEXT
         WriteInt LocalStream, LocalConnection\ID
         WriteLine LocalStream, txt$
      EndIf
      Print ">>> " +LocalConnection\Name +" sagt:"
      Print txt$
      txt$ = ""
   ElseIf char > 31
      txt$ = txt$ +Chr(char)
   EndIf
   Text 0,284, "> " +txt$
   
   DrawPrint()
   Flip 0
   WaitTimer( TIMER )
Wend

; Abmelden
If IsServer
   For SConnection = Each TConnection
      If SConnection\Connected = True
         WriteByte SConnection\Stream, MSGT_SRVCLOSE
      EndIf
   Next
Else
   WriteByte LocalStream, MSGT_DISC
   WriteInt LocalStream, LocalConnection\ID
EndIf

End


Function Print( txt$ )
   Printed( PrintLine ) = txt$
   PrintLine = PrintLine +1
   PrintLine = PrintLine Mod 17
End Function
Function DrawPrint()
   For a = 0 To 16
      Text 0,a *16, Printed( ( 17 + a +printline ) Mod 17 )
   Next
End Function

Function GetConnectionById.TConnection( ID )
   Local Conn.TConnection
   For Conn = Each TConnection
      If Conn\ID = ID Return Conn
   Next
   Conn = New TConnection
   Conn\ID = ID
   Return Conn
End Function


(Server und Client in einem Programm und zum Testen reicht es vollkommen, einfach zweimal auf Run zu klicken)

Wie du siehst, reicht es, den Nachrichtentyp als Byte zu definieren. Mit der Sache wegen AcceptTcpStream: Die Funktion lieftert ein Streamhandle zurück, wenn eine neue TCP-Verbindung aufgebaut wurde. Logischerweise (um nachträglich immer noch alle Streams abfragen zu können) muss man dieses Handle in einem Type speichern. Um zu fragen, ob an einem Stream neue Daten ankamen, dient die Funktion ReadAvail().

Guck dich n wenig durch den Code, versuche ihn zu verstehen und mach dir selbst ein paar Gedanken, was ich wohl wieso auf diese Art gelöst habe.

Der Code ist übrigens noch lange nicht ausgereift... da gehören nämlich noch Sicherheitsabfragen rein (was passiert zB wenn sich ein Client anmeldet, auch wenn er vom Server abgewiesen wurde, weil dieser voll ist) ein komplettes Timeout-Managment und vieles mehr.

Achja: Und lass die Finger von der Print Funktion! Das ist nur n Workaround, weil ich zu spät gemerkt habe, dass es mit Print ja ziemlich hässlich wird, wenn man Nachrichten eingeben will. Es gäbe da also bestimmt noch schönere Lösungsmöglichkeiten.

Und wenn noch Fragen offen sind, einfach fragen =)

mfG
Erledige alles Schritt um Schritt - erledige alles. - Holzchopf
CC BYBinaryBorn - Yogurt ♫ (31.10.2018)
Im Kopf da knackt's und knistert's sturm - 's ist kein Gedanke, nur ein Wurm

DerKeks

BeitragSo, Dez 28, 2008 18:52
Antworten mit Zitat
Benutzer-Profile anzeigen
danke dir...
der code scheint zu funzen :>
werd ihn mir dann mal genauer anschauen um zu gucken was ich jetzt falsch gemacht habe

danke Wink

Neue Antwort erstellen


Übersicht BlitzBasic Beginners-Corner

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group