Sign in to follow this  
Followers 0
zatorg

Asynchronous sockets UDF

42 posts in this topic

#1 ·  Posted (edited)

Hello folks,

well this is my first public contribution to the forums :)

This is a UDF library providing functions for using asynchronous sockets (and async socket transfer).

An asynchronous socket is a socket with which you can listen(), connect(), send() and recv() asynchronously, that is, while the Windows Sockets implementation (Winsock) attempts to complete your action, your program is doing other stuff. When the action is completed (or has afailed) your program is given a notification. In AutoIt3, you GUIRegisterMsg( $iYourMessageID, $sTheFunctionToCall ) and then do whatever you want to (poll the GUI for events, perform calculations etc.) and have the function called when an event that interests you occurs.

///

EDIT: warning: a lot of yada yada follows beyond this!

If you want to see the effect and read some pretty simple and commented sources just go to this post.

///

This is rather simple. Take a look at this:

This is an example server that uses async sockets. It waits for incoming connections and handles them. At the same time, it does usesless bullshit that you can change to useful work like GUI handling or so.

<removed, download from this post>

This is an example client that uses async sockets. It's crazy because it attempts to connect to one place a few times thus establishing a few simultaneous connections. But that's just what we need since my goal is to prove the simplicity of synchronizing socket transfer and program's normal flow whatsoever.

<removed, download from this post>

<Obsolete>

I'm too damn lazy to write a client now... If this gains interest (or I'm at 3A.M. by the computer one night) I'll write one... At present, use one of those blocking TCP clients or use this one. It's a piece of crap, from the days when I was scripting in AutoIt only, and it's not finished. And, oh, it's in lithuanian :D I think you'll understand though. When prompted, enter your local IP address and port to listen to. It starts to listen on that port. There are only two commands (as I said, it's not finished (and I'm not planning to finish it)) you can use:

"prisij hostname_or_IP:port" connects to a host. Use this to test the async server.

"atsij hostname_or_IP:port" disconnects from a host.

Edit: forgot to mention that any other text that is entered is sent to all the connected peers. This way you can see how async server gets notified about received data.

It's an old and crappy server+client (I know it's childish). It uses blocking sockets and shouldn't be used unless you can't find a simple client to test the server...

CNCServ.au3</Obsolete>

Well basically this is it. Here is the UDF:

ASock.au3

OK it's a very long post I have here. If anyone reads it fully, congrats! :D

Anyway, any comments, criticism, ideas and feedback are eagerly waited. If you find this useful or a piece of crap, please let me know.

Cheers

Kostas

EDIT: See my next post to get more info about the _ASock functions.

EDIT #2: this is the same async server that instead of doing nothing while Winsock is polling for data and such, it sends large chunks of data. This version shows that TCPSend() returns immediately even after being requested to send a lot of data if used with async sockets.

server_.au3

EDIT #3: Posted an example client. It's the same server with some stuff changed.

EDIT #4: Added a really simple server example.

OK I guess that I haven't got the ability to explain easily... :D Yet I hope this will gain interest amongst those that do TCP and socket stuff...

Happy coding! :D

Edited by Jon

Share this post


Link to post
Share on other sites



Well I'm no expert on sockets and all that other server inter computer thingys but I am able to appreciate the usefullness of this. Very nice!!


[center][/center]Working on the next big thing.Currently Playing: Halo 4, League of LegendsXBL GT: iRememberYhslaw

Share this post


Link to post
Share on other sites

#3 ·  Posted (edited)

Thank you fear! :)

Alright I clarified some bits:

Events that shall be used and are tested to perfectly work in AutoIt:

$FD_READ - posted when data has arrived on the socket. I suggest you TCPRecv()'ing only when this occurs.

$FD_WRITE - the conditions to TCPSend() are very good. Nevertheless, use TCPSend() anywhere else.

$FD_ACCEPT - a connection attempt from outside is pending. TCPAccept() it if you want. I suggest you TCPAccept()'ing only when this occurs.

$FD_CLOSE - the remote side has closed the connection / connection lost. Don't forget to TCPCloseSocket() to free the resources used!

$FD_CONNECT - connected to a peer. When you call _ASockConnect(), it returns immediately and almost always (check @extended) is not able to connect/fail that fast, so Winsock posts $FD_CONNECT when the connection is finally made OR an error has occured.

$FD_OOB - UNTESTED You state that you are interested in receiving OOB data. Winsock will announce when such data arrives.

NOTE: check $iError (or whatever you have named it) whether Winsock is telling you about a succeeded event (or one that it hasn't encountered any error on) or a failed event.

These functions have to be used in order to use asynchronous sockets:

Posts a $FD_CONNECT when connected or when afailed.

These functions can be used as usual:

TCPSend() - returns IMMEDIATELY. Attempts to send all the data, no need to check how much is sent.

Returns 0 on closed connection.

Note that $FD_WRITE is posted when it is likely that TCPSend() will succeed very fast / immediately. Nevertheless, call it when you need it.

TCPRecv() - don't call it as usual. Call it when you get a $FD_READ event. This event is posted when data has arrived on the socket.

If you call it on a $FD_READ event and do not receive all the data that has arrived, $FD_READ will be posted again.

TCPAccept() - don't call it as usual. Call it when you get a $FD_ACCEPT event. This event is posted when there is a pending connection to be TCPAccept()'ed.

TCPCloseSocket(), TCPStartup(), TCPShutdown(), TCPNameToIP(), UDFs like SocketToIP() and such.

Edited by Jon
Corrupted code tags

Share this post


Link to post
Share on other sites

After learning how to use this I'll definitely get this into my programs!!

Thanks for sharing :)

Share this post


Link to post
Share on other sites

After learning how to use this I'll definitely get this into my programs!!

Thanks for sharing :)

You came up with this after 13 posts?

VERY NICE!


Be Green Now or Never (BGNN)!

Share this post


Link to post
Share on other sites

Thank you for the warm words mates! :)

You came up with this after 13 posts?

VERY NICE!

Thanks :D Well, I'm not new to AutoIt.. I've been reading the forums occasionaly since maybe Jan '06 or so.. I recall being so happy when I first found out about AutoIt from some batch scripting site :D

Share this post


Link to post
Share on other sites

An example server and client using asynchronous sockets are now tested to work...

The server does not have to be configured whereas for the client, change the following lines:

Const $IP = "127.0.0.1"
Const $PORT = 42775

If you're testing this locally, don't change anything unless you're using a different port.

The server:

server.au3

The client:

client.au3

You want to follow their ConsoleWrite() output so load them from SciTe or wherever. They'll do some TrayTip()'ing as well.

Read the source code to get the basic understanding of how to use _ASock.au3 (some commentary included) if you don't want to read all the yada yada in the first and the third posts...

Again, please comment on this whether you find this useful or not. Thanks in advance!

OK, I definitely need to go to bed. The school starts in seven hours, and I'm reading random Garfield comics-of-the-day :)

Share this post


Link to post
Share on other sites

Hmm 118 views and only a couple of responses... :D Geez, are you that lazy to post something? :)

Share this post


Link to post
Share on other sites

I just spotted your post and read through your rather large, well explained summary and it looks very good. Had no time yet to test or anything but I am taking your word for it, so it is a mighty effort you have done.

Glad to have you as member of the forum and we are grateful for your code that you share with us. :)

Share this post


Link to post
Share on other sites

#10 ·  Posted

Wow thanks man :) I'm glad someone finds it useful...

Share this post


Link to post
Share on other sites

#11 ·  Posted

This could come very useful! Thanks

Share this post


Link to post
Share on other sites

#13 ·  Posted

Thanks people :)

Share this post


Link to post
Share on other sites

#14 ·  Posted

Thanks people :)

Is there more to come on your project? New idea's, new updates? :D

Share this post


Link to post
Share on other sites

#15 ·  Posted

Is there more to come on your project? New idea's, new updates? :)

Hmm, well, I haven't planned any further development (have stuff to do...) but if there's any interest/need, I can surely happily develop this further... The question is, what to develop? :D ASock.au3 enables you to control async sockets not less than those blocking AutoIt socket functions. If you have any ideas, please let me know.

Maybe I should rewrite the library to be more easily usable? Something like this Manadar's idea?

Share this post


Link to post
Share on other sites

Ugh this shit is so confusing, is there any way of making a very simple server? Your example server is too complex.

Share this post


Link to post
Share on other sites

I second you.. Async stuff ain't simple :) Will try writing one when I have time (and that is today)...

Share this post


Link to post
Share on other sites

#18 ·  Posted (edited)

Alrighty here we go... A simple server... Start it, then connect to it with some client and send some data... Then disconnect from it. Notice that you don't have to poll on the sockets in the main While() loop.

#include <ASock.au3>
Const $MYMSG = 1024

;;;
Const $PORT2LISTEN = 42775
;;;

Global $hNotifyGUI = GUICreate( "notify" )
Global $hListen
Global $hAccepted = -1
If Not TCPStartup( ) Then Exit 1
If Not _StartServer( "0.0.0.0", $PORT2LISTEN, "OnEvent" ) Then Exit 2
ConsoleWrite( "+> Waiting for connection on port #" & $PORT2LISTEN & "..." & @CRLF )
While $hAccepted = -1; You can alse use a flag like $bConnected which would be changed by OnAccept()
                     ; when a connection is accepted...
    ; blah blah...
WEnd
; Connection accepted!
ConsoleWrite( "Connection accepted, socket #" & $hAccepted & @CRLF )

While $hAccepted <> -1; While still connected
    ; Do whatever you like here.
    ; Do GUI handling etc.
WEnd
TCPCloseSocket( $hListen )
TCPShutdown( )
Exit 0

; This is called when an event has happened on a socket.
Func OnEvent( $hWnd, $iMsgID, $WParam, $LParam )
    Local $hSocket = $WParam; Get the socket involved (either $hListen or $hAccepted in this example)
    Local $iError = _HiWord( $LParam ); If error is 0 then the event indicates about a success
    Local $iEvent = _LoWord( $LParam ); The event: incoming conn / data received / perfect conditions to send / conn closed
    
    Local $sDataBuff
    
    If $iMsgID = $MYMSG Then; Winsock, not Windows GDI
        Switch $iEvent
            Case $FD_ACCEPT; Incoming connection!
                If $iError <> 0 Then
                    Exit MsgBox( 16, "simpleServer error", "Failed to listen to " & $PORT2LISTEN & "." )
                EndIf
                $hAccepted = TCPAccept( $hListen )
            Case $FD_READ; Data has arrived!
                If $iError <> 0 Then
                    TCPCloseSocket( $hAccepted )
                    $hAccepted = -1
                Else
                    $sDataBuff = TCPRecv( $hAccepted, 8192 )
                    If @error Then
                        TCPCloseSocket( $hAccepted )
                        $hAccepted = -1
                    Else
                        ConsoleWrite( "{{" & $sDataBuff & "}}" & @CRLF )
                        TrayTip( "Data has arrived!", $sDataBuff, 30 )
                    EndIf
                EndIf
            Case $FD_WRITE
                If $iError <> 0 Then
                    TCPCloseSocket( $hAccepted )
                    $hAccepted = -1
                EndIf
            Case $FD_CLOSE; Bye bye
                _ASockShutdown( $hAccepted ); Graceful shutdown.
                Sleep( 1 )
                TCPCloseSocket( $hAccepted )
                $hAccepted = -1
        EndSwitch
    EndIf
EndFunc

Func _StartServer( $sIP, $iPort, $sFunc )
    $hListen = _ASocket( )
    If @error Then Return False
    _ASockSelect( $hListen, $hNotifyGUI, $MYMSG, BitOR( $FD_ACCEPT, $FD_READ, $FD_WRITE, $FD_CLOSE ) )
    If @error Then Return False
    GUIRegisterMsg( $MYMSG, $sFunc )
    _ASockListen( $hListen, $sIP, $iPort )
    If @error Then Return False
    Return True
EndFunc

Cheers. Don't hesitate to ask what you don't understand...

Edit: some foolish grammar.

Edit2: slightly edited the script to TCPCloseSocket() properly. Not a bug, but still...

Edited by zatorg

Share this post


Link to post
Share on other sites

Works great, you missed a c on EndFunc btw.

Share this post


Link to post
Share on other sites

Great then. And thanks, yeah, I somehow missed it... :)

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