B4J Question TCP Socket Server works but I've done something wrong!

vfafou

Well-Known Member
Licensed User
Longtime User
Hello!
I'm trying to implement a TCP Sockets Server for use on my LAN.
I had written the shared code inside the Main Sub and it was working.
I tried to move the shared code inside a new code module. Since moving the code to another module, I can't connect to the socket server. Init sub is called from Main.
The sockets created are derived from a Class module.
What am I doing wrong?
Note that I need every socket running at its own thread!

Thank you in advance!

The shared module code:
B4X:
Sub Process_Globals
    'Global statistics.
    Private intActiveClients As Int
    Private intMessages As Int
    Private intBytes As Int
  
    Public  srvListener As ServerSocket
    Public  IsListening As Boolean
    Dim     intPort As Int
    Private lstClients As List
  
End Sub

Private Sub srvListener_NewConnection(Successful As Boolean, NewSocket As Socket)
    Dim intClient As Int
    Dim RMC As RMClient
    Dim FoundAvailable As Boolean
    Dim intActualClient As Int
    Dim NewClient As RMClient
  
    If Successful Then
        'Socket1 = NewSocket
      
        For intClient = 0 To lstClients.Size - 1
  
            RMC = lstClients.Get(intClient)
          
            If Not(RMC.InUse) Then
                FoundAvailable = True
                'Hack needed here to emulate action of
                'an "Exit For" statement:
                intActualClient = intClient
                intClient = lstClients.Size - 1
            End If
          
        Next
      
        If Not(FoundAvailable) Then
            intActualClient = intClient
            NewClient.Initialize(Me, "Client", intActualClient)
            lstClients.Add(NewClient)
            RMC = NewClient  
        End If
      
        RMC.NewConnection(NewSocket)
        intActiveClients = intActiveClients + 1
        Log("Client " & intActualClient & " connected")
      
    Else
        Log("Connection attempt failed: " & LastException.Message)
    End If
  
    srvListener.Listen

End Sub

Public Sub RMClient_Input(strMsg As String)
    Dim intClient As Int
    Dim Client As RMClient
  
    intMessages = intMessages + 1
   
    For intClient = 0 To lstClients.Size - 1
        Client = lstClients.Get(intClient)
  
        If Client.InUse Then
            Client.Write(strMsg & Chr(0x0d))
        End If
  
    Next

End Sub

Private Sub RMClient_Bytes(ReceivedByteCount As Int)
    intBytes = intBytes + ReceivedByteCount
    Log(intBytes)
End Sub


Public Sub Init
    intPort = 61999
    srvListener.Initialize(intPort, "srvListener")
    srvListener.Listen
    Log("Listening on port " & intPort)
    lstClients.Initialize
    IsListening = True
End Sub


Private Sub StopServer
    Dim intClient As Int
    Dim Client As RMClient
  
    For intClient = 0 To lstClients.Size - 1
        Client = lstClients.Get(intClient)
        If Client.InUse Then
            Client.Close
        End If
    Next
    srvListener.Close
    IsListening = False
End Sub

The Class code:
B4X:
Private Sub Class_Globals
    'PseudoConsts:
    Private DELIMITER As String = Chr(0x0d) 'CR.
    Private ENCODING As String = "WINDOWS-1253"
    Private INPUT_STREAM_FALLBACK As Int = 18000
    Private INPUT_STREAM_MAX As Int = 22000 'This can be ineffective if not
                                            'greater than underlying socket
                                            'buffer length (normally 8192
                                            'bytes).
  
    Private mParent As Object
    Private mEventName As String
    Private mIndex As Int
    Private mInput As String
    Private mInUse As Boolean
    Private mLastError As String
  
    Public  mClientType As Int         ' 1 = Statuses, 2 = WorkStations, 3 = AnswerStatuses
    Private mClientBase As String  ' CD_BASE
  
    Private sckClient As Socket
    Private astmClient As AsyncStreams
    Private sbAssemStm As StringBuilder 'Assembled input stream buffer.
  
    Private Strings As JStringFunctions
  
End Sub


Public Sub Initialize(Parent As Object, EventName As String, Index As Int)
    mParent = Parent
    mEventName = EventName
    mIndex = Index
  
    Strings.Initialize
  
End Sub


Public Sub getIndex() As Int
    Return mIndex
End Sub


Public Sub getInput() As String 'Valid during Input event.
    Return mInput
End Sub


Public Sub getInUse() As Boolean
    Return mInUse
End Sub


Public Sub getLastError() As String
    Return mLastError
End Sub


Public Sub Close()
    astmClient.Close
    sckClient.Close
    sckClient = Null
    CallSub2(mParent, mEventName & "_Terminated", Me)
    mInUse = False
End Sub


Public Sub NewConnection(NewSocket As Socket)
    mLastError = ""
    sckClient = NewSocket
    sbAssemStm.Initialize
    astmClient.Initialize(sckClient.InputStream, sckClient.OutputStream, "astmClient")
    mInUse = True
End Sub


Public Sub Write(Output As String)
    Dim mCMesg As String
    Dim mCBase As String
  
    Try
        'Log(Output)
        'Log(mClientType)
        Select Case mClientType
            Case 1
                astmClient.Write(Output.GetBytes(ENCODING))
                'astmClient.Write(DELIMITER.GetBytes(ENCODING))
        
        End Select
      
    Catch
        Log("Error Client Write!")
    End Try
End Sub

Private Sub astmClient_Error()
    mLastError = LastException.Message
    CallSub2(mParent, mEventName & "_Error", Me)
    Log(mLastError)
    Close
End Sub

Private Sub astmClient_NewData(Buffer() As Byte)
    Dim Frag As String
    Dim Msgs As String
    Dim Pos As Int
    Dim DelimPos As Int
  
    Dim RmID As String
    Dim RmMesg As String
  
    CallSub2(mParent, mEventName & "_Bytes", Buffer.Length)
  
    Frag = BytesToString(Buffer, 0, Buffer.Length, ENCODING)
  
    If sbAssemStm.Length > INPUT_STREAM_MAX Then
        sbAssemStm.Remove(INPUT_STREAM_FALLBACK, sbAssemStm.Length)
    End If
  
    sbAssemStm.Append(Frag)
  
    If Frag.Contains(DELIMITER) Then
      
        Msgs = sbAssemStm.ToString
      
        Pos = 0
      
        Do Until DelimPos < 0
            DelimPos = Msgs.IndexOf2(DELIMITER, Pos)
            If DelimPos >= 0 Then
                mInput = Msgs.SubString2(Pos, DelimPos)
              
                RmID = Strings.SplitGetWord(mInput, ",", 1)
                RmMesg = Strings.SplitGetWord(mInput, ",", 2)
              
                Log(mInput)
              
                PushShared.SendWebClientMessage(RmMesg, RmID)
                
                mInput = ""
                Pos = DelimPos + 1
            End If
        Loop
      
        'Delete the processed messages from the assembled input stream,
        'reinsert any leftover characters.
        sbAssemStm.Initialize
        sbAssemStm.Append(Msgs.SubString(Pos))
      
    End If
  
End Sub

Private Sub astmClient_Terminated()
    Close
End Sub
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
What happens when you run the program? Does NewConnection event fire?

Note that I need every socket running at its own thread!
When you use AsyncStreams each socket is managed by its own thread. However your code runs in the main thread.

The only way to completely manage each connection with its own thread is with a real server built with jServer library.
 
Upvote 0

vfafou

Well-Known Member
Licensed User
Longtime User
Hello Erel!
Yes, NewConnection event fire but I have a strange behavior, like confused clients and multiple times message sending.
The behavior before this post was like not connected!
 
Upvote 0
Top