Jump to content

Asynchronous sockets UDF


zatorg
 Share

Recommended Posts

  • Replies 41
  • Created
  • Last Reply

Top Posters In This Topic

Top Posters In This Topic

Would there be a simpler version for the client?

Like, You wrote a simpler version of the server.

Hey,

ooh, it has been a long time since I last visited these forums...

Let me see. Which part don't you understand? I admit it's a bit confusing with all those new function names etc. Maybe I should comment on what the script does?

Link to comment
Share on other sites

I just want to use the functions as a simple simple TCP connection, Like, For basic testing purposes.

Like, Connecting to a server, sending data, and receiving the response.

# MY LOVE FOR YOU... IS LIKE A TRUCK- #
Link to comment
Share on other sites

OK, here's a PoC but it's not tested cause my Windows is going nuts. Will prob switch to OS X Leopard some time soon :P

#include <ASock.au3>
Const $MYMSG = 1024
Global $bConnectResult = 0
Global $hSocket = -1

;;;
Const $IP2CONNECT2   = "127.0.0.1"
Const $PORT2CONNECT2 = 42775
;;;

If Not TCPStartup( ) Then Exit 1
_StartConnecting( $IP2CONNECT2, $PORT2CONNECT2, "EventHandler" )
If @extended Then
    ConsoleWrite( "+> Connected IMMEDIATELY. You have a darn good connection..." & @CRLF )
Else; Wait for the result of the connection attempt.
    
    Do
        Sleep( 100 )
    Until $bConnectResult <> 0; $bConnectResult = 0 => connecting // = 1 => connected // = -1 => failed
    
EndIf

If $bConnectResult = -1 Then
    ConsoleWrite( "+> FAILED to connect to " & $IP2CONNECT2 & ":" & $PORT2CONNECT2 & "." & @CRLF )
Else
    ConsoleWrite( "+> YAY, connected!!! :)" & @CRLF )
    TCPSend( $hSocket, "Howdy!" )
    ; Will catch any response in "EventHandler". You can, however, TCPRecv() but this will be the usual BLOCKING function.
    ; Thus, you shouldn't use TCPRecv() :)
    
    ; Do whatever you desire....
    While $bConnectResult = 1
        TCPSend( $hSocket, "Fl000d..." )
        Sleep( 1000 )
    WEnd
EndIf
TCPCloseSocket( $hSocket )
TCPShutdown( )
Exit 0


Func EventHandler _
    ( _
        $hWnd, _   ; Equals to $hNotifyGUI (see _StartConnecting())
        $iMsgID, _ ; Equals to $MYMSG if it's coming from Winsock
        $WParam, _ ; Equals to $hSocket
        $LParam _  ; Mixture of an error encountered (if any) and the type of event
    )
    
    Local $iError = _HiWord( $LParam ); If $iError = 0 then it means the event indicates a success
    Local $iEvent = _LoWord( $LParam ); The event: connected / failed to conenct / data received / perfect conditions to send / conn closed
    
    Local $sDataBuff
    
    If $iMsgID = $MYMSG Then; Winsock, not Windows GDI
        Switch $iEvent
            Case $FD_CONNECT
                If $iError <> 0 Then
                    $bConnectResult = -1; Failed to connect.
                Else
                    $bConnectResult = 1; Connected!
                EndIf
            Case $FD_WRITE
                If $iError <> 0 Then
                    $bConnectResult = -1; Error related to TCPSend(), probably failed sending data.
                EndIf
            Case $FD_READ
                If $iError <> 0 Then
                    $bConnectResult = -1; Failed while attempting to receive data.
                Else
                    ; Data arrived!
                    $sDataBuff = TCPRecv( $hSocket, 65536 ); 64K buffer
                    ConsoleWrite( "+> " & $IP2CONNECT2 & " says: " & $sDataBuff & @CRLF )
                EndIf
            Case $FD_CLOSE
                ConsoleWrite( "+> Connection _gracefully_ closed." & @CRLF )
                $bConnectResult = -1
        EndSwitch
    EndIf
EndFunc

Func _StartConnecting( $sIP, $iPort, $sFunc )
    Local $hNotifyGUI
    
    $hSocket = _ASocket( )
    If @error Then Return False
    
    Local $hNotifyGUI = GUICreate( "notify" )
    _ASockSelect( $hSocket, $hNotifyGUI, $MYMSG, BitOR( $FD_READ, $FD_WRITE, $FD_CONNECT, $FD_CLOSE ) )
    If @error Then Return False
    
    GUIRegisterMsg( $MYMSG, $sFunc )
    
    _ASockConnect( $hSocket, $sIP, $iPort )
    If @extended Then; Have connected IMMEDIATELY, no point in waiting for _ASockConnect() result
        SetExtended( 1 )
        Return True
    EndIf
    
    ; Connection attempt issued.
    Return True
EndFunc
Link to comment
Share on other sites

wowow works great :P i finished my msn client using this^^ finally i can handle conversations and the msn socket at the same time.. i love you..have a great life

Do tell :3

I tried a few days ago, Couldnt get the damn thing to login xD;;

# MY LOVE FOR YOU... IS LIKE A TRUCK- #
Link to comment
Share on other sites

Okay, what I'm looking for is a combination of these two. I'm working on it on my own, but I figured I'd see if anyone had any pointers or tips for me.

Basically, I want to listen on a port and run the server, then, when the data comes through, I forward it to another port/IP. Then I wait for certain sequences of data to catch and trigger events in response. My idea is to make a bot, but not a cheating one, I play a GTA roleplaying game and want to create NPCs for questing in the game. You can learn more about the game mod at http://www.sa-mp.com but right now, they don't have NPCs for the RPG mod and if I could create NPCs that would quest, the game would be a blast.

As far as actions go in the game, I'm not as concerned, it's more about interfacing my AI bot in to chat with the user, as well as trigger some "/" commands if the user says certain key phrases.

Edited by Yorn
Link to comment
Share on other sites

Hey,

I'm back. I hope I can help you.

It seems what you need to do is to listen on a socket, accept connections, receive data from those connections, connect to remote host(s) and forward them the data received. This is more or less like tunneling.

If you have any specific questions, don't hesitate asking. Good luck!!!

And thanks everyone for the warm comments :P

Edited by zatorg
Link to comment
Share on other sites

Thanks, but now I'm looking at reading memory addresses instead of trying to do UDP tunneling, the traffic is encrypted anyway. All I really want to know how to do is read where the program is storing the text, so this is not a big deal.

Link to comment
Share on other sites

  • 2 months later...

I get the following error

D:\Data\Entw\AutoIt\TCPIP\server_.au3 (220) : ==> "long_ptr", "int_ptr" and "short_ptr" DllCall() types have been deprecated. Use "long*", "int*" and "short*" instead.:

Local $aRet = DLLCall("Ws2_32.dll","int","getpeername","int",$SHOCKET, "ptr",DLLStructGetPtr($sockaddr),"int_ptr",DLLStructGetSize($sockaddr))

...

; AutoIt Help -> TCPRecv

Func SocketToIP($SHOCKET)

Local $sockaddr = DLLStructCreate("short;ushort;uint;char[8]")

Local $aRet = DLLCall("Ws2_32.dll","int","getpeername","int",$SHOCKET, _

"ptr",DLLStructGetPtr($sockaddr),"int_ptr",DLLStructGetSize($sockaddr))

If Not @error And $aRet[0] = 0 Then

$aRet = DLLCall("Ws2_32.dll","str","inet_ntoa","int",DLLStructGetData($sockaddr,3))

If Not @error Then $aRet = $aRet[0]

Else

$aRet = "(Could not get the address)"

EndIf

$sockaddr = 0

Return $aRet

EndFunc

....

i have found the following description

http://www.autoitscript.com/forum/index.ph...opic=56168&

can somebody help me to eliminate this?

server_.au3

Link to comment
Share on other sites

I get the following error

D:\Data\Entw\AutoIt\TCPIP\server_.au3 (220) : ==> "long_ptr", "int_ptr" and "short_ptr" DllCall() types have been deprecated. Use "long*", "int*" and "short*" instead.:

Local $aRet = DLLCall("Ws2_32.dll","int","getpeername","int",$SHOCKET, "ptr",DLLStructGetPtr($sockaddr),"int_ptr",DLLStructGetSize($sockaddr))

just change 'int_ptr' to ptr

server.au3 with asock.au3 works for me

in v3.2.8.1 and v3.2.11.1

from TCPRecv example in help file

; AutoIt Help -> TCPRecv
Func SocketToIP($SHOCKET)
    Local $sockaddr, $aRet
    $sockaddr = DllStructCreate("short;ushort;uint;char[8]")
    $aRet = DllCall("Ws2_32.dll", "int", "getpeername", "int", $SHOCKET, _
            "ptr", DllStructGetPtr($sockaddr), "ptr", DllStructGetSize($sockaddr))
    If Not @error And $aRet[0] = 0 Then
        $aRet = DllCall("Ws2_32.dll", "str", "inet_ntoa", "int", DllStructGetData($sockaddr, 3))
        If Not @error Then $aRet = $aRet[0]
    Else
        $aRet = 0
    EndIf
    $sockaddr = 0
    Return $aRet
EndFunc   ;==>SocketToIP

I see fascists...

Link to comment
Share on other sites

  • 1 year later...

Hi zatorg

Thanks a Ton for posting Asynchronous sockets UDF.I have been looking for this since from last 3 months .

It's working fine for me, both the clients and the server.

I have a doubt, I am having a client server application , where all the clients are connecting to the server .When they establish a connection they can start talk each other.Now it is totally based on TCP/IP. One loop is always monitoring the data's from the connected sockets.If anything comes it will process accordingly.

If i change my server application by using Asynchronous sockets method will i be able to communicate between server and the clients. Because i am having 'n' number of clients.

If possible can u tell me how can i implement the same.I have tried a lot but i am not able to figure out.

Thanks & Regards

Ajomon

Hey Ajomon,

I think that what you are basically looking at is an adaptation of the original example script <server.au3> which accepts multiple connections and then waits for Winsock to notify about events regarding those connections (e.g. in your case, you'd be interested in being notified about (and reading) received data as well as knowing which client in particular sent you that data -- and it's all in that script).

http://www.autoitscript.com/forum/index....le=attach&section=attach&attach_id=14413 (I hope this is reachable by all users; in any case, it's attached in this post: http://www.autoitscript.com/forum/index....?showtopic=45189&view=findpost&p=336722)

I think that the original script will no longer work due to AutoIt language changes (unfortunately, I no longer have AutoIt around), but e.g. rover has addressed one of the issues here.

On a very abstract level, what you need to do is to have an array of sockets (connection identifiers). When you establish all the connections with the clients (see source code of the script), you do whatever you want. Once data from a specific client is received, OnSocketEvent() is called. This line determines which client has sent the data (it is the socket number in your array of sockets):

Local $nSocket = $iMsgID - $WM_USER - 1

In order for this to work, you have to previously inform WinSock that for each socket, you want to receive a specific ID ($iMsgID):

(this is executed when a new connection has been accepted; on each such event, FreeSock() is called which returns the number of an unused element in the array of sockets)

_ASockSelect( $hSockets[ $iFreeSock ], $hNotifyGUI, $WM_USER + $iFreeSock + 1, BitOR( $FD_READ, $FD_WRITE, $FD_CLOSE ) )

_ASockSelect() "registers" the socket in the sense that it tells Winsock to notify the program when certain events that interest us (in this case, receival of data, closure of the connection and perfect conditions to send data to that client (this last one is not that interesting)) take place. Notice the "$WM_USER + $iFreeSock + 1" part: $iFreeSock is the number of an unused element in the socket array ($iFreeSock stores the number returned by FreeSock()); "$WM_USER + 1" is needed because the notification process uses Windows Graphics Device callback mechanism; what this means is that the mechanism might send events unrelated to the socket concerned (it might be about the dummy GUI window needed to receive notifications from Winsock). Starting with a constant "WM_USER" + 1 (WM_USER is the last (biggest) constant still reserved for Winsock-unrelated events), you are free to choose a number that will be received by OnSocketEvent(). In this script, the number is basically the socket's in question position in the array.

Perhaps you can tell why your current implementation (which, as I understand, uses AutoIt's built-in socket functions) does not satisfy you? I gather you want to do more useful stuff (e.g. handle the GUI) rather than just poll for socket events which Winsock can do for you? If so, then maybe you just need to adapt the script <server.au3> - if I'm totally wrong, maybe you can paste relevant excerpts of your code here/somewhere that we can look at.

Edit: oh, sorry, I haven't actually answered your question :) - yes (see server.au3 - the part in OnSocketEvent() where there is a TrayTip displayed telling what and from where was received - you could simply change that line(s) to TCPSend($hSocket, "response data"))

Edit 2: I also forgot to mention that in order to "register" a socket, you also need to GUIRegisterMsg($id_to_use, "FunctionName"):

For $i = 0 To $N_MAXSOCKETS - 1
    $hSockets[ $i ] = -1
    GUIRegisterMsg( $WM_USER + 1 + $i, "OnSocketEvent" )
Next

In this script, it is done before any actual socket operations (listening etc.) are performed.

Edited by zatorg
Link to comment
Share on other sites

  • 2 months later...

Hello, excelent piece of code ... i already use it on many proyects ...

But, i have a problem when this is performed by a Service AutoIT application ... the message never are received...

I Can see in the server part that the client connect, but in the client, the event never is fired ... i think is because in the system account, there is not a visible desktop ...

Any idea to make a event RECEIVED running inthe system desktop as a service?

Thanks a lot.

Tr4d3r

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...