Odd freezing of program - Updated with Source

Just starting out? Need help? Post your questions and find answers here.
cbailey
User
User
Posts: 65
Joined: Sat Jun 04, 2005 4:05 am

Odd freezing of program - Updated with Source

Post by cbailey »

I've got a toughie, and it's got me completely stumped. I understand this will be difficult without full source code, but experience shows the best PB programmers hang out here :)

I'm developing a Chat-type program. I just added the ability of the client to try and connect again if a connection wasn't made, or is broken. Here's a small part:

hSocket=OpenNetworkConnection(GetGadgetText(#HostString),6000)
if hSocket = 0
; We didn't connect. Will try later
showmsg("Unable to connect. Retrying...")
Else
; We're connected
Endif

The problem is, the client acts like the program is using so much CPU time, it doesn't have time to maintain itself. For example, the 'Unable to Connect' message doesn't show up. However, if I wait long enough so they fill the window, I see a scroll bar pop up, as if they were there, but are invisible. Also, if I click on the window, and try to move it around, it does not move around smoothly. Otherwise, my program works fine. It was fine until I tried adding this 'reconnect if we are not connected' feature. I tried peppering the program with Delay() commands, including right after the failure, but the text still isn't visible.

BTW, the program isn't using up tons of CPU time. Any ideas?


Also, I forgot to mention that, once the connection is made, all the hidden messages show up!
Last edited by cbailey on Sun Oct 16, 2005 7:40 am, edited 1 time in total.
Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Do you have a windowEvent() anywhere inside that code loop? If not, try sticking one in.
@}--`--,-- A rose by any other name ..
cbailey
User
User
Posts: 65
Joined: Sat Jun 04, 2005 4:05 am

Post by cbailey »

Yes, one is in there. I did have a WaitWindowEvent, but it tied up things, so I replaced it. Using either, I still get these symptoms..
Trond
Always Here
Always Here
Posts: 7446
Joined: Mon Sep 22, 2003 6:45 pm
Location: Norway

Post by Trond »

Make sure you loop the WindowEvent() until it returns no more events instead of simply calling it once.
cbailey
User
User
Posts: 65
Joined: Sat Jun 04, 2005 4:05 am

Post by cbailey »

Currently, the program is a big Repeat Until loop, and the first item after Repeat is winevent.l=WindowEvent(). Should this be different?
cbailey
User
User
Posts: 65
Joined: Sat Jun 04, 2005 4:05 am

Post by cbailey »

Here's an example. I took Mike Delling's chat client code, and simply modified it to retry if it can't connect. When it can't connect (Which happens if you don't run the server, and have the client point to the server), the "can't connect" text doesn't show up, and it's difficult or impossible to move the window around. However, if you let it run this way for a while, and then start up the server, all the "can't connect" messages will show up, and everything will be fine.

Any ideas?


Code: Select all



; Chat Server X-Ample by Mike Delling 
; 
; With complete documentation for correctly networking in PB. :o) 

If InitNetwork()=0 
  MessageRequester("","Could not initialize WSA.",0) 
  End 
EndIf 



hWin=OpenWindow(0,0,0,600,200,#PB_Window_ScreenCentered|#PB_Window_SystemMenu,"PB Chat Client") 

If hWin=0 
  MessageRequester("","Could not open window.",0) 
  End 
EndIf 

If CreateGadgetList(hWin)=0 
  MessageRequester("","Could not Create Gadgetlist.",0) 
EndIf 

; ----------------------------------------- 
: Dimenstions & Structures & Constants 
; ----------------------------------------- 

#NetworkEvent   = #WM_User +1       ; For incomeing events from server 

#MaxCommands    = 10 
#Maxlines       = 1024 


Dim commands$(#MaxCommands) 

*receivebuffer=GlobalAlloc_(#GMEM_FIXED | #GMEM_ZEROINIT, 12000) 
; ----------------------------------------- 
; Some Procedures 
; ----------------------------------------- 


   Procedure.w MyGetCommand(a$) 
        For a = 0 To #MaxCommands : commands$(a) = "" : Next 
        len = Len(a$) : ak = 1 
        ; 
        Repeat 
          letter$ = Mid(a$,ak,2) 
          If letter$ <> "@!" 
            letter$ = Mid(a$,ak,1) 
            commands$(akcommand)+letter$ : ak + 1 
          EndIf 
          ; 
          If letter$ = "@!" 
            akcommand + 1 : ak + 2 
          EndIf 
        Until ak >= len 
        ; 
        ProcedureReturn akcommand 
    EndProcedure 

;----------------------------------- 
; PROC - Send Datas through network 
;----------------------------------- 
    
    Procedure MySend(id,txt$) 
    
    ; calculate bufferlength 
    
    length.l=Len(txt$)+1        ; String + EOL 
    length.l+4                  ; Packet length at beginning 
    length.l+4                  ; CRC32 

    *mem.l=GlobalAlloc_(#GMEM_FIXED | #GMEM_ZEROINIT, length.l) 
    
    PokeL(*mem.l,length.l)      ; Store the Header (Size of Packet) 
    PokeS(*mem.l+4,txt$)        ; Store String (Datas) 

    crc.l=CRC32Fingerprint(*mem.l+4,length.l-8)   ; Create CRC32 Checksum 
    PokeL(*mem.l+length.l-4,crc.l)                ; Store it at the end of the packet 
    
    Repeat                                       ; Loop for Datasend 
      send=send_(id,*mem.l,length,0)              ; Send our Datas 
      sended+send                                 ; Count our sended Bytes 
      If send=#SOCKET_ERROR 
          wsaerror=WSAGetLastError_() 
          If wsaerror=#WSANOTINITIALISED:err$="Wsa not initialized":EndIf 
          If wsaerror=#WSAENETDOWN :err$="The Windows Sockets implementation has detected that the network subsystem has failed.":EndIf 
          If wsaerror=#WSAENOTCONN :err$="Socket not connected.":EndIf 
          If wsaerror=#WSAEINTR :err$="The (blocking) call was canceled using WSACancelBlocking":EndIf 
          If wsaerror=#WSAEINPROGRESS :err$="A blocking Windows Sockets operation is in progress.":EndIf 
          If wsaerror=#WSAENOTSOCK :err$="The descriptor is not a socket.":EndIf 
          If wsaerror=#WSAEOPNOTSUPP :err$="MSG_OOB was specified, but the socket is not of type SOCK_STREAM.":EndIf 
          If wsaerror=#WSAESHUTDOWN :err$="The socket has been shut down; it is not possible to recv on a socket after shutdown has been invoked with how set to 0 or 2.":EndIf 
          If wsaerror=#WSAEMSGSIZE :err$="The datagram was too large to fit into the specified buffer and was truncated.":EndIf 
          If wsaerror=#WSAEINVAL :err$="The socket has not been bound with bind.":EndIf 
          If wsaerror=#WSAECONNABORTED :err$="The virtual circuit was aborted due to timeout or other failure.":EndIf 
          If wsaerror=#WSAECONNRESET :err$="The virtual circuit was reset by the remote side.":EndIf 
          If wsaerror=#WSAEWOULDBLOCK :err$="The socket is marked as nonblocking":EndIf        
          If wsaerror=#WSAEWOULDBLOCK:send=0:sended=0:Delay(250):EndIf 
      EndIf ; Errorcheck 

    Until sended>=length Or send=#SOCKET_ERROR   ; Loop as long as all Datas has been send 
    GlobalFree_(*mem)                                 ; Free our Memory again 
    ProcedureReturn send 
    EndProcedure 


#HostIPText     = 1 
#HostString     = 2 

#NickText       = 3 
#NickString     = 4 

#Connect        = 5 
#ChatWindow     = 6 
#ChatText       = 7 

#Send           = 8 


#ReturnKey      = 1 

TextGadget    (#HostIPText,10,13,50,20,"Host/IP:") 
StringGadget  (#HostString,70,10,150,20,"127.0.0.1") 

TextGadget    (#NickText,230,13,50,20,"Nickname:") 
StringGadget  (#NickString,290,10,150,20,"Eliot") 

ButtonGadget  (#Connect,450,10,100,20,"Connect") 

ListIconGadget(#ChatWindow,10,40,580,120,"",500) 
StringGadget  (#ChatText,10,170,500,20,"") 
ButtonGadget  (#Send,520,170,70,20,"Send"):AddKeyboardShortcut(0,#PB_Shortcut_Return,#ReturnKey) 


Procedure showmsg(msg$) 
Shared lines,maxlines 
AddGadgetItem(#ChatWindow,lines,msg$) 
SendMessage_(GadgetID(#ChatWindow),#LVM_ENSUREVISIBLE,lines,1) 
lines+1 
EndProcedure 


Procedure window(WindowID, Message, wParam, lParam) 
    Shared hSocket,*receivebuffer.l,totalreceived.l,receiveexpected.l,received 
    Result = #PB_ProcessPureBasicEvents 
 ; Handle Networkevents here 
      
      If Message=#NetworkEvent 
  
      serverevent=NetworkClientEvent(hSocket)  ; What happens? 
      
      If serverevent=2                  ; Rawdata received (2 is described by the PB Manual) 
        
        If receiveexpected>0 
          received=recv_(hSocket,*receivebuffer.l+totalreceived.l,receiveexpected-totalreceived,0) 
      
          If received<>#SOCKET_ERROR 
            If received>0:totalreceived+received:EndIf 
            If totalreceived=PeekL(*receivebuffer.l) ; Is our packet complete? 
              command$=PeekS(*receivebuffer+4)       ; Get our Command-String from Memorybuffer 
              anz=MyGetCommand(command$)             ; Tokanize our Command-String 
              totalreceived=0                        ; Datapacket complete, reset value and wait for new one 
              receiveexpected=-1                     ; Wait for new packetheader but do not execute the next part! 
            
              ; Message Processing here 
              
              If commands$(0)="STRG" 
                ;AddGadgetItem(#ChatWindow,-1,commands$(1)+" > "+commands$(2)) 
                showmsg(commands$(1)+" > "+commands$(2)) 
              EndIf 
              
              If commands$(0)="ENTR" 
                ;AddGadgetItem(#ChatWindow,-1,commands$(1)+" entered the chat.") 
                showmsg(commands$(1)+" entered the chat.") 
              EndIf 
            
            EndIf 
          EndIf 
        EndIf 
      
        If totalreceived<3 And receiveexpected=0                            ; Receive our Packetheader till it is complete 
          received=recv_(hSocket,*receivebuffer+totalreceived,4-totalreceived,0)   ; Receive TCP/IP Buffer (max. 4 Bytes) 
          If received<>#SOCKET_ERROR 
            If received=4 
              receiveexpected=PeekL(*receivebuffer) 
            EndIf        ; Completed yet? 
            If received>0:totalreceived+received:EndIf                       ; Count our Received bytes (we need 4!) 
            commands$(0)=""                                               ; Erase our String to avoid multihandling 
          EndIf 
        EndIf 
              
        If receiveexpected=-1:receiveexpected=0:EndIf                     ; Ready to receive next dataheader again!! 

      EndIf                             ; End RAW Data receive 

      EndIf 
    ProcedureReturn Result 
EndProcedure 

SetWindowCallback(@window()) 


Repeat 
    
    winevent.l=WaitWindowEvent()        ; Get Window-Event ID 
    wineventgadget.l=EventGadgetID()    ; Get Gadget-Event ID 
    wineventtype=EventType()            ; Get Windows Event Type 
    winid=EventWindowID()               ; Get window where the event occurs 
    winmenu=EventMenuID()               ; Get MenuID 

    lastgadget.l=wineventgadget.l 

    ; Handle Windowevents here 
    
    If winevent.l=#PB_Event_Menu        ; Menuchecking for keyboard shortcuts 
      If winmenu=#Returnkey 
          If LCase(GetGadgetText(#Chattext))="send" 
            nick$=InputRequester("Send File to user...","Please type in the nickname of user:","") 
            file$=OpenFileRequester("Select file to send to "+nick$,"","*.*","") 
            mysend(hSocket,"FILE@!"+nick$+"@!"+file$+"@!"+StrU(FileSize(file$),#Long)+"@!") 
          EndIf 
          If mysend(hSocket,"STRG@!"+GetGadgetText(#NickString)+"@!"+GetGadgetText(#Chattext)+"@!")=#SOCKET_ERROR 
          showmsg("Could not send String.") 
         ; AddGadgetItem(#ChatWindow,-1,"Could not send String.") 
        Else 
          ;AddGadgetItem(#ChatWindow,-1,GetGadgetText(#NickString)+" > "+GetGadgetText(#Chattext)) 
          showmsg(GetGadgetText(#NickString)+" > "+GetGadgetText(#Chattext)) 
          SetGadgetText(#ChatText,"") 
        EndIf 
      EndIf 
    EndIf 
    
    If winevent.l=#PB_Event_Gadget      ; Any Gadgetevent here? 
      
      If wineventgadget=#Connect        ; User try to connect 
      
      
      ; -------------------------------------
      ; -------------------------------------
      ; -------------------------------------
      connt:
      
        hSocket=OpenNetworkConnection(GetGadgetText(#HostString),6000) 
        If hSocket=0 
         showmsg("we didn't connect")
         Delay(10)
         ; MessageRequester("","Could not connect to server.",0) 
        Else 
          ; Connection successfull, add a Usermessage to the Window 
          WSAAsyncSelect_(hSocket,hWin,#NetworkEvent,#FD_READ | #FD_Write |#FD_OOB) 
          mysend(hSocket,"ENTR@!"+GetGadgetText(#NickString)+"@!") 
          ;AddGadgetItem(#ChatWindow,-1,"Connected to server.") 
          showmsg("Connected to server.") 
          ; We are now successfully connected 
        EndIf 
        
      If hSocket=0 : Goto connt : EndIf
      ; ---------------------------------------
      ; ---------------------------------------
      ; ---------------------------------------
      
      
      EndIf                             ; End Connect 
      
      If wineventgadget=#Send 
        If mysend(hSocket,"STRG@!"+GetGadgetText(#NickString)+"@!"+GetGadgetText(#Chattext)+"@!")=#SOCKET_ERROR 
          AddGadgetItem(#ChatWindow,-1,"Could not send String.") 
        Else 
          ;AddGadgetItem(#ChatWindow,-1,GetGadgetText(#NickString)+" > "+GetGadgetText(#Chattext)) 
          showmsg(GetGadgetText(#NickString)+" > "+GetGadgetText(#Chattext)) 
          SetGadgetText(#ChatText,"") 
        EndIf 
      EndIf 
      
      EndIf      ; End gadgetevents condition 
    
    

Until winevent=#PB_Event_CloseWindow 

End 

Dare2
Moderator
Moderator
Posts: 3321
Joined: Sat Dec 27, 2003 3:55 am
Location: Great Southern Land

Post by Dare2 »

Heya,

I haven't looked at your code, but try - as a temp measure - putting a delay(1) and a WindowEvent() after every Repeat, For, etc, regardless of how unlikely. If things improve, reduce these until you find the one that counts.

The Delay(1) to give other processess a look in and the WindowEvent() to flush your event queue.

Edit: Especially in the area where you added the retry connection code you mentioned.

Edit again: - perhaps WindowEvent() after the connt: label?
@}--`--,-- A rose by any other name ..
cbailey
User
User
Posts: 65
Joined: Sat Jun 04, 2005 4:05 am

Post by cbailey »

I've peppered the entire code, but especially the section in question, with Delay(), anywhere from 1 to 9000, with the same results. Not surprisingly, the longer delays just make it more sluggish. Again, my CPU time is fine. Other programs are working fine, just my app. I tried another WindowEvent, but it didn't work either.

Maybe this is a bug in AddGadgetItem? (If you put a Debug"HELLO" right after the "If hSocket=0", it shows up fine.
Post Reply