Sign in to follow this  
Followers 0

TCP UDF, Event driven!

318 posts in this topic

#1 ·  Posted (edited)

Hey,

Because people always ask how to create a TCP client/server, and then (if they get it) don't know how to make it multi client,

I simplified it.

It's event driven, so you don't have to manualy check everything.

Please read this whole post to understand my UDF.

Version 3 of this UDF:

Functions renamed, and everything is event-driven.

Functions:

_TCP_Server_Create($iPort, $sIP="0.0.0.0")
 _TCP_Server_Broadcast($sData)
 _TCP_Server_ClientList()
 _TCP_Server_ClientIP($hSocket)
 _TCP_Server_DisconnectClient($hSocket)
 _TCP_Server_Stop()
 
 
 _TCP_Client_Create($sIP , $iPort)
 _TCP_Client_Stop($hSocket)
 
 
 _TCP_Send($hSocket, $sText)
 _TCP_RegisterEvent($hSocket, $iEvent, $sFunction)

Use _TCP_RegisterEvent() to register an event. These are the possible events to register:

$TCP_SEND - When the other side of the connection is ready to receive (more) data.

$TCP_RECEIVE - If something is received.

$TCP_CONNECT - When you connect to the server. (Client only)

$TCP_DISCONNECT - When a connection is closed.

$TCP_NEWCLIENT - When a new client connects to the server. (Server only)

Example client:

#include "TCP.au3"
 
 ToolTip("CLIENT: Connecting...",10,10)
 
 $hClient = _TCP_Client_Create(@IPAddress1, 88); Create the client. Which will connect to the local 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.
 
 While 1
 ; just to keep the program running
 WEnd
 
 Func Connected($hSocket, $iError); We registered this (you see?), When we're connected (or not) this function will be called.
 
 If not $iError Then; If there is no error...
     ToolTip("CLIENT: Connected!",10,10); ... we're connected.
 Else; ,else...
     ToolTip("CLIENT: Could not connect. Are you sure the server is running?",10,10); ... we aren't.
 EndIf
 
 EndFunc
 
 
 Func Received($hSocket, $sReceived, $iError); And we also registered this! Our homemade do-it-yourself function gets called when something is received.
 ToolTip("CLIENT: We received this: "& $sReceived, 10,10); (and we'll display it)
 EndFunc
 
 Func Disconnected($hSocket, $iError); Our disconnect function. Notice that all functions should have an $iError parameter.
 ToolTip("CLIENT: Connection closed or lost.", 10,10)
 EndFunc

And the server: (which is smaller than the client)

#include "TCP.au3"
 
 ToolTip("SERVER: Creating server...",10,30)
 
 $hServer = _TCP_Server_Create(88); A server. Tadaa!
 
 _TCP_RegisterEvent($hServer, $TCP_NEWCLIENT, "NewClient"); Whooooo! Now, this function (NewClient) get's called when a new client connects to the server.
 _TCP_RegisterEvent($hServer, $TCP_DISCONNECT, "Disconnect"); And this,... this will get called when a client disconnects.
 
 While 1
 
 WEnd
 
 Func NewClient($hSocket, $iError); Yo, check this out! It's a $iError parameter! (In case you didn't noticed: It's in every function)
 
 ToolTip("SERVER: New client connected."&@CRLF&"Sending this: Bleh!",10,30)
 
 _TCP_Send($hSocket, "Bleh!"); Sending: "Bleh!" to the new client. (Yes, that's right: $hSocket is the socket of the new client.)
 
 EndFunc
 
 Func Disconnect($hSocket, $iError); Damn, we lost a client. Time of death: @Hour & @Min & @Sec :P
 
 ToolTip("SERVER: Client disconnected.",10,30); Placing a tooltip right under the tooltips of the client.
 
 EndFunc

Now, as you can see, every function has an $iError parameter.

Function($hSocket, $iError)

Every funtion that is called can contain two parameters (1st: Socket, 2nd: Error) except for the Received function.

Which should contain 3 parameters. 1:Socket, 2:Data, 3:Error

You can't create a server and a client in the same script.

Well, I think that's all.

Happy coding :)

Kip

Previous number of downloads: 975

TCP.au3

Edited by Kip

Share this post


Link to post
Share on other sites



#2 ·  Posted

Hey,

Because people always ask how to create a TCP client/server, and then (if they get it) don't know how to make it multi client,

I simplified it.

Client: (not very large, as you can see)

#include "_TCP.au3"

_TCP_Start(); Start all the tcp crap


Do
    $iClientCreate = _TCP_Client_Create(@IPAddress1, 88); Connect to the server. I assume that the server is on the same computer. If not, change the ip address.
    Sleep(100)
Until $iClientCreate <> -1; I put it in a loop so it doesn't matter if you start the server first or the client. Just put a nice Sleep() in it too.


While 1
    
    $sRecieved = _TCP_Client_Recieve($iClientCreate); Checks if we recieved something...
    
    If $sRecieved Then; If we actually recieved something, then...
        
        MsgBox(0,"Client","This is what we recieved:"&@CRLF&$sRecieved); ...we will show a messagebox.
        _TCP_Send($iClientCreate, "And this text is send from the client.")
        ExitLoop; Exit the loop, because we don't want to leave our connection here... all alone :)
    EndIf
    
WEnd


_TCP_Client_Stop($iClientCreate); Close our connection to the server. We've killed our connection. He's dead. He can't be alone anymore :P
_TCP_Stop()


; Well, this isn't so hard... right?

And the server: (also very small, and it support multiple clients)

#include "_TCP.au3"

_TCP_Start(); Start all the tcp crap, just like we did in the client. 


$iServerCreate = _TCP_Server_Create(88); Create the server on port 88. If you're a smart guy you can see that the client also connects to port 88.


While 1
    
    $iUpdate = _TCP_Server_Update($iServerCreate); Updates the server. Checks for new connections (clients), and puts them in an array.
    
    If $iUpdate Then; If a new client has connected. (That doesn't mean he also send something)
        
        MsgBox(0,"Server","Hey! We have a new client connected."); $iUpdate is the socket to the new client. If you don't get that, then just forget it.
        _TCP_Send($iUpdate, "This text is send from the server.")
    EndIf
    
    
    $sRecieved = _TCP_Server_Recieve(); Now we're gonna check if somebody send us something.
    
 ; btw: $sRecieved is an array. $sRecieved[0] contains the socket, and $sRecieved[1] contains the recieved text.
    
    If $sRecieved[0] Then; If a client has send something, then...
        
        MsgBox(0,"Server","I recieved something from a client!"&@CRLF&"Altough we're happy that it works I'm gonna close the client connection.")
        _TCP_Server_DisconnectClient($sRecieved[0]); Disconnect the client.
        ExitLoop; This example has nothing else to show, so i'm shutting down the server.
    EndIf
    
WEnd

_TCP_Server_Stop($iServerCreate)
_TCP_Stop()

; Especially for a multi client server this is a very small script.

I added nice comments, to let you understand better what is going on in the examples.

Just remove the comments to make it more clear.

If you have any questions, just ask. :)

Hi Kip,

Thanks for the enlighting script. I manage to setup a server and a client, they connect. But when i try to sent text to from the client to the server, the server detects there has been a transmission from the client, but $sReceived[1] does not contain anything.

I put in a If IsArray($sReceived) right after If $sRecived[0] to check if the array is even initialised, but i get an error on that, so the array is not even excisting.

What am i doing wrong?

Share this post


Link to post
Share on other sites

#3 ·  Posted

The return value is ALWAYS an array.

(as you can see:)

Func _TCP_Server_Recieve($iBinary=0)
    
    Local $iReturn[2], $sRecv
    
    For $i = 1 to $_TCP_CLIENTS[0]
        If $_TCP_CLIENTS[$i] Then
            $sRecv = TCPRecv($_TCP_CLIENTS[$i], 1024, $iBinary)
            If $sRecv Then
                
                $iReturn[0] = $_TCP_CLIENTS[$i]
                $iReturn[1] = $sRecv
                Return $iReturn
                
            EndIf
        EndIf
    Next
    
    Return $iReturn
    
EndFunc

Does my example work?

I put in a If IsArray($sReceived) right after If $sRecived[0]

So you first check if an element of an array contains something, and then you're gonna check if it's an array at all? :)

Could you post your code?

:P

Share this post


Link to post
Share on other sites

#4 ·  Posted

The return value is ALWAYS an array.

(as you can see:)

Func _TCP_Server_Recieve($iBinary=0)
    
    Local $iReturn[2], $sRecv
    
    For $i = 1 to $_TCP_CLIENTS[0]
        If $_TCP_CLIENTS[$i] Then
            $sRecv = TCPRecv($_TCP_CLIENTS[$i], 1024, $iBinary)
            If $sRecv Then
                
                $iReturn[0] = $_TCP_CLIENTS[$i]
                $iReturn[1] = $sRecv
                Return $iReturn
                
            EndIf
        EndIf
    Next
    
    Return $iReturn
    
EndFunc

Does my example work?

So you first check if an element of an array contains something, and then you're gonna check if it's an array at all? :)

Could you post your code?

:P

Yes i know i am checking double for the array, trange thing is that element[0] does containt the socket but element[1] does not excist.

In you example you do check if there is received something, by checking element[0] but you never user element[1].

This is my receiving code

$sRecieved = _TCP_Server_Recieve(); Now we're gonna check if somebody send us something.
    
    If $sRecieved[0] Then; If a client has send something, then...
        MsgBox(0, "", $sReceived[0])
        $IPData = $sReceived[1]
        Select
            Case StringInStr($sReceived[1], "%clientping:")
                StringTrimLeft($IPData, 12)
                StringTrimRight($IPData, 1)
                _GUICtrlEdit_AppendText($ServerConsole, @CRLF & _GetTime(1) & " : New client handshaking from IP: " & $IPData)
                $ConClient[0] += 1
                $ConClient[$ConClient[0]] = $IPData
                MsgBox(0, "", $ConClient[0])
                _TCP_Send($sReceived[0], $Control[5])
                _GUICtrlEdit_AppendText($ServerConsole, @CRLF & _GetTime(1) & " : Client succesfully logged in from IP: " & $IPData & "Sending login notification")
                _TCP_Send($sReceived[0], $Control[7])
            Case StringInStr($sReceived[1], "%clientlogoff:")
                StringTrimLeft($IPData, 14)
                StringTrimRight($IPData, 1)
                _GUICtrlEdit_AppendText($ServerConsole, @CRLF & _GetTime(1) & " : Client succesfully logged out from IP: " & $IPData & "Sending logout notification")
                _TCP_Send($sReceived[0], $Control[8])
                _TCP_Server_DisconnectClient($sRecieved[0]); Disconnect the client.
        EndSelect

    EndIf

an you see what is going wrong?

Share this post


Link to post
Share on other sites

#5 ·  Posted

1st: $sRecieved[1] should contain something (if something is send)

2nd: I don't see the logic behind this:

StringTrimLeft($IPData, 12)
StringTrimRight($IPData, 1)
You never save the new string

3th: What if you put MsgBox(0, "", $sReceived[1]) right after MsgBox(0, "", $sReceived[0])?

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

1st: $sRecieved[1] should contain something (if something is send)

2nd: I don't see the logic behind this:

StringTrimLeft($IPData, 12)
StringTrimRight($IPData, 1)
You never save the new string

3th: What if you put MsgBox(0, "", $sReceived[1]) right after MsgBox(0, "", $sReceived[0])?

This is my client code, at least the part where the handshaking is done.

$Control[0] = "%clientping:"&@Ipaddress1&"%"

Do
    $iClientCreate = _TCP_Client_Create(@IPAddress1, 33891); Connect to the server. I assume that the server is on the same computer. If not, change the ip address.
    If @error Then
        MsgBox(4112, "Error", "TCPConnect failed with WSA error: " & @error)
        Exit
    EndIf
    $i += 1
    If $i >= 25 Then ExitLoop
    Sleep(100)
Until $iClientCreate <> -1
                If $iClientCreate = -1 Then
    _GUICtrlEdit_AppendText($ChatConsole, @CRLF & "Kabookie IM Server is not online, cannot connect to clients...")
Else
    _TCP_Send($iClientCreate, $Control[0])
    MsgBox(4112, "Error", "TCPConnect failed with WSA error: " & @error)
    _GUICtrlEdit_AppendText($ChatConsole, @CRLF & "Kabookie IM Server is online...")
    GUICtrlSetData($ServerStatus, "ServerStatus : Server is online and running...   ")
    _GUICtrlEdit_AppendText($ChatConsole, @CRLF & "Sending handshake signal...")
    $Cycletimer1 = _GetTime(0)
EndIf

The StrinTrimLeft was indeed an error and is now fixed, thanks for pointing it out to me :)

Edited by inet

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

I really wanna know this: :)

3th: What if you put MsgBox(0, "", $sReceived[1]) right after MsgBox(0, "", $sReceived[0])?

(In the server) Edited by Kip

Share this post


Link to post
Share on other sites

#8 ·  Posted

Hmmm this is strange, i did some more research and discovered that i get an array error on the line:

If $sRecieved[0] Then

What could this be?

Share this post


Link to post
Share on other sites

#9 ·  Posted

I can't help you if you don't do this:

3th: What if you put MsgBox(0, "", $sReceived[1]) right after MsgBox(0, "", $sReceived[0])?

What could this be?

It would be helpful if you post the error too.

Share this post


Link to post
Share on other sites

#10 ·  Posted (edited)

The messagebox is of no use i get the error before that on

If $sRecieved[0] Then

I get $sReceived possibly used before being declared.

Edited by inet

Share this post


Link to post
Share on other sites

#11 ·  Posted (edited)

oohhhhh man, i got it. It was a stupid typo :)

I typed

If $sRecieved[0] then

instead of

If $sReceived[0]

i switched ie for ei :P

Been searching for hours, and now it's a plain old stupid typo....

It is working now :P

Thanks for the help anyway

Edited by inet

Share this post


Link to post
Share on other sites

#12 ·  Posted

Hello inet,

there is a setting in autoit to avoid such a pain searching for a typo in the future.

Simply put

AutoItSetOption('MustDeclareVars',1)
at the start of your scripts.

Look up the detailed explanation in the help file, it will take care that every variable is

declaired prior to use.

I prefer to use this in my scripts, it might seem to be more work at start, but all in all,

it really helps more then it costs.

ciao

Xandl

Share this post


Link to post
Share on other sites

#13 ·  Posted (edited)

oohhhhh man, i got it. It was a stupid typo :)

I typed

If $sRecieved[0] then

instead of

If $sReceived[0]

i switched ie for ei :P

Been searching for hours, and now it's a plain old stupid typo....

It is working now :P

Thanks for the help anyway

Remember "I" before "e" except after "c" :D My teacher tells me that all the time ..... Yay i just realized school is over... lol Edited by Konstig

code

Share this post


Link to post
Share on other sites

#14 ·  Posted

Remember "I" before "e" except after "c" :P My taecher tells me that all the time ..... Yay i just realized school is over... lol

It was not realy a typo, Kip used $sRecieved wich i copied and pasted into my script. But all the other times i used the variable i typed it as $sReceived so i was actualy using 2 variables for the same purpose. I just did not see that Kip spelled it the other way :)

But it's fixed now.

Thank you guys for all the tips and answers...

Share this post


Link to post
Share on other sites

#15 ·  Posted

Remember "I" before "e" except after "c"

I just did not see that Kip spelled it the other way

I never knew that either. :)

Share this post


Link to post
Share on other sites

#16 ·  Posted

I never knew that either. :)

Lol


code

Share this post


Link to post
Share on other sites

#17 ·  Posted

Very VERY nice kip. This can really help me.

(Where is our Visual AutoIt? :) )


[left][sub]We're trapped in the belly of this horrible machine.[/sub][sup]And the machine is bleeding to death...[/sup][sup][/sup][/left]

Share this post


Link to post
Share on other sites

#18 ·  Posted

New udf! :P

It's now 10 times easier. (maybe even 11 times :) )

All old functions are still in the udf.

New functions:

_TcpEvent_Server_Create()

_TcpEvent_Server_Send()

_TcpEvent_Server_GetClientIP()

_TcpEvent_Server_DisconnectClient()

_TcpEvent_Server_Stop()

_TcpEvent_Client_Create()

_TcpEvent_Client_Send()

_TcpEvent_Client_Stop()

You don't have to know anything about sockets, etc.

Share this post


Link to post
Share on other sites

#19 ·  Posted

New udf! :P

It's now 10 times easier. (maybe even 11 times :) )

All old functions are still in the udf.

New functions:

_TcpEvent_Server_Create()

_TcpEvent_Server_Send()

_TcpEvent_Server_GetClientIP()

_TcpEvent_Server_DisconnectClient()

_TcpEvent_Server_Stop()

_TcpEvent_Client_Create()

_TcpEvent_Client_Send()

_TcpEvent_Client_Stop()

You don't have to know anything about sockets, etc.

Nice I may need this.. Thanks


code

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

I already have my app running on the old UDF, but since you left all the old functions in it, i will upgrade to the new version :P

Thanks Kip :)

Edited by inet

Share this post


Link to post
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
Sign in to follow this  
Followers 0