how can i "handle" socket server ?

Just starting out? Need help? Post your questions and find answers here.
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 637
Joined: Fri Dec 04, 2015 9:26 pm

how can i "handle" socket server ?

Post by skinkairewalker »

hello everyone !

i have a question : Can i create multiple socket servers within only 1 standalone software, and each socket instance within this single software be named without having to change the port?

like this example (Address to connect):

127.0.0.1:5566/MyServerSocket001
127.0.0.1:5566/MyServerSocket002
127.0.0.1:5566/MyServerSocket003
127.0.0.1:5566/MyServerSocket004

note that everyone is using the same IP and PORT

each running independently ?

like : Jetty Handlers ( JAVA ) https://www.eclipse.org/jetty/documenta ... mples.html
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: how can i "handle" socket server ?

Post by mk-soft »

There can only be one socket per port.
In this socket you have to evaluate from which client the request comes.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
skinkairewalker
Enthusiast
Enthusiast
Posts: 637
Joined: Fri Dec 04, 2015 9:26 pm

Re: how can i "handle" socket server ?

Post by skinkairewalker »

can i disconnect client and force this same client to connect to server what i want ?
Marc56us
Addict
Addict
Posts: 1479
Joined: Sat Feb 08, 2014 3:26 pm

Re: how can i "handle" socket server ?

Post by Marc56us »

The server can receive several simultaneous connections and reply to differents clients (socket mechanism), it recognizes each of them by their IP ( GetClientIP() )
and port ( GetClientPort() ) source and assigns them an ID ( ConnectionID() )

You can of course disconnect this connection ( CloseNetworkConnection() ) but that's it.

Network Lib

:wink:
User avatar
mk-soft
Always Here
Always Here
Posts: 5409
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: how can i "handle" socket server ?

Post by mk-soft »

A server can also disconnect the client connection.
On the client you can also see that the connection has been disconnected from the server.

Small Server example (Not testet)

Code: Select all

;-TOP

; -----------------------------------------------------------------------------

CompilerIf #PB_Compiler_Thread = 0
  CompilerError "Use Compiler-Option ThreadSafe"
CompilerEndIf

; -----------------------------------------------------------------------------

Enumeration FormWindow
  #Main
EndEnumeration

Enumeration FormGadget
  #MainList
EndEnumeration

Enumeration FormStatusBar
  #MainStatusBar
EndEnumeration

Enumeration CustomEvent #PB_Event_FirstCustomValue
  #MyEvent_Trace
EndEnumeration

; -----------------------------------------------------------------------------

Global ExitApplication

; -----------------------------------------------------------------------------

;#TraceList = -1 ; Use Debugger output
#TraceList = #MainList

Procedure __Trace(Info.s, Modul.s, Proc.s, Line)
  Protected *msg.String = AllocateStructure(String)
  If Modul = ""
    Modul = "MainScope"
  EndIf
  *msg\s = FormatDate("[%HH:%II:%SS] ", Date())
  *msg\s + "Module " + Modul + " | Proc " + Proc + " | Line " + Line + " | " + Info
  PostEvent(#MyEvent_Trace, 0, 0, 0, *msg)
EndProcedure

; ---

Procedure DoEventTrace()
  Protected *msg.String, cnt
  *msg = EventData()
  If *msg
    If #TraceList >= 0 And IsGadget(#TraceList)
      cnt = CountGadgetItems(#TraceList)
      AddGadgetItem(#TraceList, -1, *msg\s)
      SetGadgetState(#TraceList, cnt)
      SetGadgetState(#TraceList, -1)
      If cnt >= 1000
        RemoveGadgetItem(#TraceList, 0)
      EndIf
    Else
      Debug *msg\s
    EndIf
    FreeStructure(*msg)
  EndIf
EndProcedure

; ---

Macro Trace(Info, Modul = #PB_Compiler_Module, Proc = #PB_Compiler_Procedure, Line = #PB_Compiler_Line)
  __Trace(Info, Modul, Proc, Line)
EndMacro

BindEvent(#MyEvent_Trace, @DoEventTrace())

; -----------------------------------------------------------------------------

Procedure DoEventSizeWindow()
  ResizeGadget(#MainList, 0, 0, WindowWidth(#Main), WindowHeight(#Main) - StatusBarHeight(#MainStatusBar))
EndProcedure

; -----------------------------------------------------------------------------

InitNetwork()

Declare thServer(*data)

Structure udtClient
  ConnectionID.i
  ConnectionTime.i
  RequestTime.i
  RequestString.s
EndStructure

Structure udtServerThread
  ; Header
  ThreadID.i
  Exit.i
  ; Configuration
  Port.i
  ; Data
  ServerID.i
  Map Client.udtClient()
EndStructure

Global MyServer.udtServerThread

MyServer\Port = 6637

; -----------------------------------------------------------------------------

;- Main
Procedure Main()
  Protected Event, ExitTime
  
  #MainWidth = 800
  #MainHeight = 600
  #MainStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
  
  If OpenWindow(#Main, #PB_Ignore, #PB_Ignore, #MainWidth, #MainHeight, "Main Window", #MainStyle)
    ;-- Create StatusBar
    CreateStatusBar(#MainStatusBar, WindowID(#Main))
    AddStatusBarField(100) : StatusBarText(#MainStatusBar, 0, "Run")
    AddStatusBarField(#PB_Ignore)
    ;-- Create Gadget
    ListViewGadget(#MainList, 0, 0, #MainWidth, #MainHeight - StatusBarHeight(#MainStatusBar))
    
    ;-- BindEvent
    BindEvent(#PB_Event_SizeWindow, @DoEventSizeWindow(), #Main)
    
    Trace("Program started")
    
    ;-- Start Server
    MyServer\ThreadID = CreateThread(@thServer(), MyServer)
    
    ;-- EventLoop
    Repeat
      Event = WaitWindowEvent()
      Select Event
        Case #PB_Event_CloseWindow
          ExitApplication = #True
          
        Case #PB_Event_Menu
          Select EventMenu()
              CompilerIf #PB_Compiler_OS = #PB_OS_MacOS   
              Case #PB_Menu_About
                
              Case #PB_Menu_Preferences
                
              Case #PB_Menu_Quit
                ExitApplication = #True
              CompilerEndIf
          EndSelect
          
      EndSelect
      
    Until ExitApplication
    
    MyServer\Exit = 1
    
    ;-- ExitProgram
    Trace("Exit Program (Wait 2 Seconds)")
    
    ExitTime = ElapsedMilliseconds()
    Repeat
      WaitWindowEvent(100)
      If ElapsedMilliseconds() - ExitTime >= 2000
        Break
      EndIf
    ForEver
    
  EndIf
  
EndProcedure : Main()

End

; -----------------------------------------------------------------------------

Procedure thServer(*data.udtServerThread)
  Protected ConnectionID, now
  Protected *buffer, len
  
  With *data
    Delay(100)
    \ServerID = CreateNetworkServer(#PB_Any, \Port)
    If Not \ServerID
      Trace("Server Error: Create Server with Port " + Str(\Port))
      ProcedureReturn 0
    Else
      Trace("Server: Create Server with Port " + Str(\Port))
    EndIf
    *buffer = AllocateMemory($10000)
    ; Loop
    Repeat
      Select NetworkServerEvent()
        Case #PB_NetworkEvent_Connect
          ConnectionID = EventClient()
          Trace("Server: Client connect with IP " + Str(GetClientIP(ConnectionID)))
          If FindMapElement(\Client(), Hex(ConnectionID))
            DeleteMapElement(\Client())
          EndIf
          AddMapElement(\Client(), Hex(ConnectionID))
          \Client()\ConnectionTime = Date()
          \Client()\RequestTime = Date()
          
        Case #PB_NetworkEvent_Disconnect
          ConnectionID = EventClient()
          Trace("Server: Client disconnect with IP " + Str(GetClientIP(ConnectionID)))
          If FindMapElement(\Client(), Hex(ConnectionID))
            DeleteMapElement(\Client())
          EndIf
          
        Case #PB_NetworkEvent_Data
          ConnectionID = EventClient()
          Trace("Server: Client data with IP " + Str(GetClientIP(ConnectionID)))
          If FindMapElement(\Client(), Hex(ConnectionID))
            \Client()\RequestTime = Date()
            len = ReceiveNetworkData(ConnectionID, *buffer, $10000)
            \Client()\RequestString = PeekS(*buffer, len, #PB_Ascii)
            ; Send Echo
            SendNetworkString(ConnectionID, \Client()\RequestString + #LF$, #PB_Ascii)
          EndIf
          
        Default
          now = Date()
          ; Disconnect clients without request over 30 seconds
          ForEach \Client()
            If (now - \Client()\RequestTime) > 30
              SendNetworkString(ConnectionID, "Timeout" + #LF$, #PB_Ascii)
              CloseNetworkConnection(\Client()\ConnectionID)
              DeleteMapElement(\Client())
            EndIf
          Next
          Delay(100)
      EndSelect
      
    Until \Exit
    
    Trace("Server: Shutdown")
          
    ForEach \Client()
      SendNetworkString(ConnectionID, "Server shutdown" + #LF$, #PB_Ascii)
      CloseNetworkConnection(\Client()\ConnectionID)
    Next
    CloseNetworkServer(\ServerID)
      
    ; Exit Thread
    
  EndWith
  
  
EndProcedure
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
Bitblazer
Enthusiast
Enthusiast
Posts: 736
Joined: Mon Apr 10, 2017 6:17 pm
Location: Germany
Contact:

Re: how can i "handle" socket server ?

Post by Bitblazer »

skinkairewalker wrote:can i disconnect client and force this same client to connect to server what i want ?
If you write the client AND server software, yes you could do that in multiple ways. It isnt necessary though and if you want to achieve your initial goal (one server, one port which handles multiple connections), you can do that with the Purebasic network commands.

A basic example is inside the manual - Network section called NetworkServer.pb

Just read all the command descriptions and it should be easy to follow. A common little test server to understand the concepts, would be a server which simply sends any incoming data back to the connected client. Then you can test it by simply connecting to your server and typing text. Let the server write back all of the client information it gets like the ClientID and then get every data from that connection and write it back to the client. Basically echoing the input. Then use a commandline to connect to your server from multiple windows for a test and that way you can develop and test your server in basic easy steps and learn how network communication with a server works.

You might need to install a telnet client for these tests if you develop it in windows. So you can use

Code: Select all

telnet localhost portnumber
in a commandline window for simple testing and understanding the concepts.
User avatar
skywalk
Addict
Addict
Posts: 4003
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: how can i "handle" socket server ?

Post by skywalk »

Why would you need telnet when you have PB?
Just write your tests in PB.
You can easily stress out your server in very few lines.
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
Post Reply