Jump to content

TCP UDF, Event driven!


Kip
 Share

Recommended Posts

@Kip do you see any problems with changing around line 538 to the following

Func _ASockConnect($hSocket, $sIP, $uiPort)
    
    Local $sTemp = TCPNameToIP($sIP)
    If Not $sTemp = "" Then
        $sIP = $sTemp
    EndIf
    
    Local $iRet
    Local $stAddress

This will allow users of the UDF to connect to UNC names and internet addresses. I just want to make sure I don't break anything (it works in my script).

EDIT: I have been testing more and it makes the connection less reliable, but I'm not sure why.

Edited by Prab
Link to comment
Share on other sites

@Kip do you see any problems with changing around line 538 to the following

Func _ASockConnect($hSocket, $sIP, $uiPort)
    
    Local $sTemp = TCPNameToIP($sIP)
    If Not $sTemp = "" Then
        $sIP = $sTemp
    EndIf
    
    Local $iRet
    Local $stAddress

This will allow users of the UDF to connect to UNC names and internet addresses. I just want to make sure I don't break anything (it works in my script).

EDIT: I have been testing more and it makes the connection less reliable, but I'm not sure why.

When you say less reliable, do you mean in general or just to UNC names or IP addresses? Also, what do you mean by less reliable? Does it just not work sometimes? I never ran into any problems with it and I've been using it like an IRC server for a while now.
Link to comment
Share on other sites

I found that my script would have a harder time connecting. I think it may be an issue with Func Connected($hSocket, $iError) not firing every time the client actually connects (race condition?).

I did not test it very much. I was just working on get a quick chat agent working. If I have more time to play around with it I will let you know more details.

Link to comment
Share on other sites

  • 2 weeks later...

Hi,

Very good work.

Actually I try tu use this UDF in a client/server project but i've actually a bug when trying to send message (TCP_Send) from the server to the client. Once the client connected, when the server receive a message from the client, the server should reply an echo (the message itself). to the client.

Actually, when the client is connected, the server reply to itself and the client receive nothing and is unable to send new message, the socket number seem to be lost.

Any idea to solve my issue ?

Here the server script :

#include "TCP.au3"
#include "pannel.au3"

Dim Const $SERVER_SHUTDOWN = "SHUTDOWN"
Dim Const $SERVER_ALIVE = "ALIVE"

_PANNEL_createPannel("Server " & @IPAddress1)
_PANNEL_updateMessage("Server is running...")

$hServer = _TCP_Server_Create(21)

_TCP_RegisterEvent($hServer, $TCP_NEWCLIENT, "NewClient")
_TCP_RegisterEvent($hServer, $TCP_DISCONNECT, "Disconnect")
_TCP_RegisterEvent($hServer, $TCP_RECEIVE, "Receive")

While 1
    Sleep(333)
WEnd

Func NewClient($hSocket, $iError)
     _PANNEL_updateMessage(_TCP_Server_ClientIP($hSocket) & " connected.")
EndFunc

Func Disconnect($hSocket, $iError)
     _PANNEL_updateMessage("Client disconnected.")
EndFunc

Func Receive($hSocket, $sReceived, $iError)
     _PANNEL_updateMessage($sReceived)
     Sleep(100)
     Switch $sReceived 
        Case $SERVER_SHUTDOWN
            _PANNEL_destroyPannel()
            _TCP_Server_Stop()
            Exit
        Case $SERVER_ALIVE
            _TCP_Server_Broadcast(@ComputerName & " is ready")
        Case Else
            _TCP_Send($hSocket, String($sReceived))
    EndSwitch
EndFunc

Here the client side script :

#include "TCP.au3"
#include "pannel.au3"

Dim Const $CLIENT_SHUTDOWN = "QUIT"

$ip = _PANNEL_clientConfig()
If @error Then Exit @error
 
_PANNEL_createPannel("Client " & @ComputerName, True)
_PANNEL_updateMessage("Connecting...")

$hClient = _TCP_Client_Create($ip, 21); Create the client. Which will connect to the $ip address on port 88
_TCP_RegisterEvent($hClient, $TCP_RECEIVE, "Received"); Function "Received" will get called when something is received
_TCP_RegisterEvent($hClient, $TCP_CONNECT, "Connected"); And func "Connected" will get called when the client is connected.
_TCP_RegisterEvent($hClient, $TCP_DISCONNECT, "Disconnected"); And "Disconnected" will get called when the server disconnects us, or when the connection is lost.
Sleep(3000)

While 1 
    $szData = _PANNEL_sendRequest()
    Select 
        Case $szData = $CLIENT_SHUTDOWN
            Disconnected($hClient, 0)
        Case $szData <> ""
            _TCP_Send($hClient, $szData)
    EndSelect
WEnd

Func Connected($hSocket, $iError)

    If not $iError Then; If there is no error...
     _PANNEL_updateMessage("Connected!"); ... we're connected.
     _TCP_Send($hSocket, "alive")
    Else; ,else...
     _PANNEL_updateMessage("Could not connect..."); ... we aren't.
     _PANNEL_destroyPannel()
     _TCP_Client_Stop($hSocket)
     Exit
    EndIf
EndFunc

Func Received($hSocket, $sReceived, $iError); And we also registered this! Our homemade do-it-yourself function gets called when something is received.
 _PANNEL_updateMessage($sReceived); (and we'll display it)
EndFunc

Func Disconnected($hSocket, $iError); Our disconnect function. Notice that all functions should have an $iError parameter.
 _PANNEL_updateMessage("Connection closed or lost.")
 _PANNEL_destroyPannel()
 _TCP_Client_Stop($hSocket)
 Exit
EndFunc

The file "pannel.au3" is used from creating GUI, find following the code :

#include <EditConstants.au3>
#include <WindowsConstants.au3>
#include <GuiIPAddress.au3>

Dim $hGuiMsg
Dim $hCtrlEdit
Dim $hButtonSend
Dim $hInputSend

Dim $sleepDelay = 250

Func __PANNEL_showPannel()
    GUISetState(@SW_SHOW, $hGuiMsg)
EndFunc

Func __PANNEL_flashPannel()
    WinFlash($hGuiMsg)
EndFunc

Func _PANNEL_destroyPannel()
    Sleep($sleepDelay)
    __PANNEL_flashPannel()
    GUIDelete($hGuiMsg)
EndFunc

Func _PANNEL_createPannel($titre = "Messages", $bSendBox = False)
    Local $heigth = 230
    Local $width = 210
    If $bSendBox Then $heigth = $heigth + 40
    $hGuiMsg = GUICreate($titre, $width, $heigth, 40, 40, $WS_EX_CLIENTEDGE)
    $hCtrlEdit = GUICtrlCreateEdit("", 10, 10, 180, 180, $WS_VSCROLL + $ES_MULTILINE)
    If $bSendBox Then __PANNEL_addSendBox()
    __PANNEL_showPannel()
    Sleep($sleepDelay)
EndFunc

Func _PANNEL_updateMessage($msg)
    Sleep($sleepDelay)
    If $msg <> "" Then ControlSend ($hGuiMsg, "", $hCtrlEdit, ">" & $msg & @CRLF)
EndFunc

Func __PANNEL_addSendBox()
    $hInputSend = GUICtrlCreateInput ("", 10, 200, 140, 25 )
    $hButtonSend = GUICtrlCreateButton ("Send", 160, 200 )
EndFunc

Func _PANNEL_sendRequest()
    Local $msg
    
    $msg = GUIGetMsg()
    Switch $msg
        Case $hButtonSend
                Return GuiCtrlRead ($hInputSend)
        Case Else
                Return ""
    EndSwitch   
EndFunc

Func _PANNEL_clientConfig($defaultIP = @IPAddress1)
    
    Local $hWnd, $hButtonConnect, $hButtonDimiss, $hIP, $msg
    
    $hWnd = GUICreate ("Connect to server", 250, 80, @DesktopWidth/2-100, @DesktopHeight/2-50, $WS_DLGFRAME)
    
    $hButtonConnect = GUICtrlCreateButton ("Connect", 140, 10)
    $hButtonDimiss = GUICtrlCreateButton ("Dimiss", 195, 10)
    
    $hIP = _GUICtrlIpAddress_Create ($hWnd, 10, 10)
    _GUICtrlIpAddress_Set($hIP, $defaultIP)
    
    GUISetState (@SW_SHOW, $hWnd)
    
    While 1
        $msg = GUIGetMsg()
        Switch $msg
            Case $hButtonConnect
                GUISetState(@SW_HIDE, $hWnd)
                Return _GUICtrlIpAddress_Get($hIP)
            Case $hButtonDimiss
                Exit
            EndSwitch
        WEnd
        
EndFunc
Edited by Edno
Link to comment
Share on other sites

  • 1 month later...

Wow Kip, thanks a lot! Just after I get *almost* done with my script I ran across this, it's SO MUCH nicer to have it event-based! Also (and the reason I was looking for help in the first place) to be able to detect client disconnects is very nice!

So I've rewritten my script (made a 2.0, kept the old one 'cause it works fine except it can't detect disconnects... and isn't event-driven :P ), and went to test it. I would like to be able to have the client and server in the same app, and be able to connect to itself. I know it sounds strange, but it'll be useful for basic TCP stack testing before moving one to another comptuer to check the network.

I'm guessing your UDF stores all sockets, whether server or client, together. So I start with $hServer = _TCP_Server_Create($sPort, $sIP), then $hClient = _TCP_Client_Create($cIP, $cPort). I _TCP_Send($hClient, $sSend), but then the client gets the $TCP_RECEIVE instead of the server.

It works to open two instances of my script, so I'm fine with that, but would really like to fix it.

Edit: I figured out my problems below. Questions: Do I have to grab the client session from the array with _TCP_Server_ClientList() to specify which client to send to? I'll try to figure it out on my own, but if anyone has ideas they'd be much appreciated.

----Solved problem below----

Solution: move line "Call($__TCP_SOCKETS[0][5], $hSocket, $iError)" a few lines up so it's first in the Case $FD_CLOSE statement in the __TCP_Server_OnSocketEvent function (currently it's pretty much "move line 218 to 214" on the release of TCP UDF as of this writing)

I'd like to display on the server which client disconnected. Post 83 had a workaround to do this, but that seems to have been for an older version and I can't find a way to do this anymore.

----Solved problem below----

Solution: Because the server can have multiple clients, the server socket doesn't specify which client to send to.

After opening a separate process for the client and the server, even on different computers, the client is able to send to the server, but for some reason the server isn't sending to the client. Any ideas?

Pretty sure this should be the code issuing it:

{code omitted for space after I figured out my problem}

When the client sends, the edit box $tabClntDataSend displays how many bytes were sent. When the server sends, the edit box $tabSrvDataSend displays "0 bytes sent" and the client doesn't receive the data.

If this isn't sufficient to see what could be wrong please let me know, I have no problem uploading the whole script if needed.

I'll be looking into this, thanks in advance anyone who has ideas!

Edited by falconv
Link to comment
Share on other sites

  • 3 weeks later...

Kip

Fantastic Job.

I have a question, but I really need to say that is a great UDF, and props for keeping it up to date. This should assist in speeding up an essential process I'm working on.

I noticed in the thread that someone reported 85% CPU use on both client and server.

This may have been in a previous version, but I experience a similar problem with the latest version; both client/server sitting at 50% CPU using the examples given.

I was wondering if this is a common issue, where people have added in a sleep?

I can do this, but wanted to address the issue just in case there is an issue I'm not seeing... or if not to add in the delay into the examples!

Anyway I'm going to get my hands dirty on this tomorrow...

Cheers

Please correct me if I am wrong in any of my posts. I like learning from my mistakes too.

Link to comment
Share on other sites

  • 4 weeks later...

Kip

Fantastic Job.

I have a question, but I really need to say that is a great UDF, and props for keeping it up to date. This should assist in speeding up an essential process I'm working on.

I noticed in the thread that someone reported 85% CPU use on both client and server.

This may have been in a previous version, but I experience a similar problem with the latest version; both client/server sitting at 50% CPU using the examples given.

I was wondering if this is a common issue, where people have added in a sleep?

I can do this, but wanted to address the issue just in case there is an issue I'm not seeing... or if not to add in the delay into the examples!

Anyway I'm going to get my hands dirty on this tomorrow...

Cheers

Hi MrBeatNik,

This is quite easy to fix - in the loop put a sleep command in so that your processor isn't looping continuously:

While 1
    Sleep(5)
WEnd

This doesn't actually put a delay in your code because everything is now event driven!

Kip,

Great work on this! I only stumbled on AutoIT yesterday and have already been able to make good use of your TCP UDF to replace some old WSH scripts which were very long and laborious and didn't really do what I wanted!

Am still trying to get my head around everything in AutoIT but I hope to get used to it very soon!

Thanks again!

Spence

Link to comment
Share on other sites

Hello everyone!

Kip - I'm loving your application, it's great! However, I'm having issues getting the _TCP_RegisterEvent to work when called from inside a function.

Why do I want to do this? I want to create a TCP Server Service - using the Service UDF.

#include <TCP.au3>
#include <_SQL.au3>
#include <array.au3>
#include <Service.au3>
#include <File.au3>

...

func main()
    $cServer = _TCP_Server_Create(88)
    AddToLog("Server Created on Port 88")
    _TCP_RegisterEvent($cServer, $TCP_NEWCLIENT, "NewClient")
    _TCP_RegisterEvent($cServer, $TCP_DISCONNECT, "ClientDisconnect")
    _TCP_RegisterEvent($cServer, $TCP_RECEIVE, "DataReceived")
    $Update = False
    AddToLog("Starting Loop")
    while 1
        Sleep(1000)
    WEnd
EndFunc

...

The service part starts fine, clients can connect - but the three registered events do not get registered and nothing happens.

Any thoughts anyone?

Many thanks,

Spence

Link to comment
Share on other sites

they will be possible to function as the server _TCP_RegisterEvent ($ server, $ TCP_NEWCLIENT, "customer") but for the client it detects the server when it connects?

(exemple: _TCP_RegisterEvent ($ server, $ TCP_NEWSERVER, "server"))

Edited by lockdu
Link to comment
Share on other sites

if we turn on the client before the server its not working! someone has an idea for a feature to detect the connection of the server to the client?

(exemple: _TCP_RegisterEvent ($ server, $ TCP_NEWSERVER, "server"))

can someone get a function for l'udf tcp.au3?

Edited by lockdu
Link to comment
Share on other sites

Hi MrBeatNik,

This is quite easy to fix - in the loop put a sleep command in so that your processor isn't looping continuously:

While 1
    Sleep(5)
WEnd

This doesn't actually put a delay in your code because everything is now event driven!

Yep, that is what I found, but wasn't sure if Kip wanted to mention this or preferred another solution with his script.

Interestingly, if the script is tied up doing something else (like a run), then events can be missed. I presume that a very long sleep would also miss an event. Not sure if it's just my script that's having that issue...

Please correct me if I am wrong in any of my posts. I like learning from my mistakes too.

Link to comment
Share on other sites

Hi Kip, hi everyone ;-)

First, i want to thank you for great udf, in latest version working great.

I am trying to send/receive file, I had read all topics about file sending, but I can not get it working correctly with your UDF. Is there any chance for to get few lines code that will demonstrate sending file with your UDF?

I had tried to implement GtaSpiders example from http://www.autoitscript.com/forum/index.php?showtopic=46341, but without luck.

Thanks for help.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...