Sign in to follow this  
Followers 0
mattschinkel

UDP Server - talk to client

29 posts in this topic

Hi there,

I'd like to make a UDP server. I need to be able to send data back to the client (whoever that is). I do not wish to specify the IP address/port of the client. This should be possible with UDP.

I posted my non-working code below to show what I would like to do. After the client sends me any data, the server should reply with "Hello Client!") on the same socket.

I would also like to allow multiple clients on my server.

I'm a open source contributor trying to do networking on PIC microcontrollers with JalV2. Some of my work can be found here: http://www.justanotherlanguage.org/

Thanks,

Matt.

;;This is the UDP Server
;;Start this first

HotKeySet("{ESC}", "quit")

; Start The UDP Services
;==============================================
UDPStartup()

; Register the cleanup function.
OnAutoItExitRegister("Cleanup")

; Bind to a SOCKET
;==============================================
;$socket = UDPBind("192.168.2.2", 251)
$socket = UDPBind("192.168.1.11", 251)

While 1
    ;get UDP data from client
    $data = UDPRecv($socket, 50)
    
    If $data <> "" Then
        
        ;display incomming data
        MsgBox(0, "UDP DATA", $data, 1)
        
        ;send a reply message
        MsgBox("", "UDP DATA", "Sending: Hello Client!", 1)
        $status = UDPSend($socket, "Hello Client!     ") 
        If $status = 0 then
            MsgBox(0, "ERROR", "Error while sending UDP message: " & @error)
            Exit
        EndIf
        
        ;clear input data
        $data = ""
        
    EndIf
    sleep(100)
WEnd

Func quit()
    UDPCloseSocket($socket)
    UDPShutdown()
    exit
EndFunc

Share this post


Link to post
Share on other sites



things i noticed

#1 MSGBOX() is a blocking function.

---Can't have it in a Loop and expect the script to continue after the MSGBOX() has been called.

#2 after i looked through it twice: your MaxByteLen is only 50

---maybe the limit needs to be more than that?

#3 no client script

---where is the client script?

Share this post


Link to post
Share on other sites

What do you mean where is the client script? As I said, I'd like to make a UDP server. The server should reply to the client with this code, using the same socket:

$status = UDPSend($socket, "Hello Client!     ")

Share this post


Link to post
Share on other sites

ah. right, i had missed that.

well, have you tried a ConsoleWrite () or some other form of NON blocking function to view the data that is being sent?

Share this post


Link to post
Share on other sites

I think it's better to use TCP, even if it's for use over LAN. Here's a multi-client server you can edit to fit your needs:

$iMaxConnections = 25

Global $iCurrentSocket = 0, $oListenSocket, $oConnectedSocket[$iMaxConnections]

TCPStartup()

$oListenSocket = TCPListen(@IPAddress1, 8044, $iMaxConnections)
If $oListenSocket = -1 Then Exit

While 1
    $oConnectedSocket[$iCurrentSocket] = TCPAccept($oListenSocket)
    ConsoleWrite($oConnectedSocket[$iCurrentSocket]&@CR)
    If $oConnectedSocket[$iCurrentSocket] <> -1 Then
        $iCurrentSocket = $iCurrentSocket + 1
    EndIf
    For $i = 0 To $iMaxConnections-1
        If $oConnectedSocket[$i] <> -1 Or $oConnectedSocket[$i] <> "" Then
            $sResv = TCPRecv($oConnectedSocket[$i], 512)
            If $sResv <> "" Then
                ;
            EndIf
    EndIf
    Next
    Sleep(20)
WEnd

Share this post


Link to post
Share on other sites

Thanks, but I am not interested in TCP at the moment.

I am trying to write one UDP client program on PIC microcontrollers, and one UDP server program for PIC microcontrollers. I have already been able to make a UDP server on the microcontroller, and can correctly connect a Autoit UDP client to it.

However, I cannot make a UDP server on Autoit. It is surprising that I can make UDP server on a 20mhz CPU, but I cannot do the same with Autoit on a PC.

I am very aware that blocking delay's are not good, but it should work in the example given. I changed it to ConsoleWrite() and still does not work.

After the Autoit program receives a UDP packet, it continuously loops printing "Sending: Hello Client!" in the console (it should only print that once), and does not actually send any packets. I am monitoring the network with Wireshark.

Here is an image of the networking device I have connected to my 20mhz microcontroller

http://cgi.ebay.com/NEW-ENC28J60-Network-Development-Board-Ethernet-Module-/320542004086?pt=LH_DefaultDomain_0&hash=item4aa1cad376

And there are some images of a microcontroller I am using on this page:

http://www.justanotherlanguage.org/content/jallib/tutorials/tutorial_blink_a_led

Matt.

Share this post


Link to post
Share on other sites

#7 ·  Posted (edited)

Im not an expert in Protocols, but right now im trying to get known with it and had also trouble understanding the way to get UDP working two sided.

Well, its quite simple:

- you only can use UDPSend on a socket you created with UDPOpen

- you can only use UDPRecv on a socket you created with UDPBind

So if you want that the "Server"(UDPBind/UDPRecv) communicate with the "Client"(UDPOpen/UDPSend)

you have to also use UDPOpen/UDPSend on the server and UDPBind/UDPRecv on the client.

TCP works different, once you created a socket with TCPOpen, you can send and recieve on this socket.

Got me some F5's to understand that difference.

But with this setup you even can use only one UDPport since its the fixed local port on each pc that is used for recieving and for sending AutoIt will use a random port.

Example below:

#Include <Misc.au3>
_Singleton("QsekTCPEventServerSingleton")

;;This is the UDP Server
;;Start this first

; Start The UDP Services
;==============================================
UDPStartup()

; Register the cleanup function.
OnAutoItExitRegister("Cleanup")

; Bind to a SOCKET
;==============================================

$recvSocket = UDPBind(@IPAddress1, 65532)
If @error <> 0 Then Exit
$sendSocket = UDPOpen("xxx.xxx.xxx.xxx", 65532); <---- Client IP here
If @error <> 0 Then Exit
While 1
    sleep(10)
    $inc = UDPRecv($recvSocket, 50)
    If $inc <> "" Then
        Sleep(50)
        ConsoleWrite("SERVER> Recieved $data: "&$inc)
        $spl = StringSplit($inc,"|",2)
        If Not @error And IsArray($spl) And UBound($spl) = 3 Then
            If $spl[2] = @CRLF Then
                If $spl[0] = "HiImClient:i_got_number" Then
                    ConsoleWrite("SERVER> processed number: "&$spl[1] & @CRLF& @CRLF)
                    $status = UDPSend($sendSocket,"IAMSERVER:i_got_this_number_from_you|"&$spl[1]&"|"&@CRLF)
                    If $status Then
    ;~                  ConsoleWrite("SERVER> sending: '"&"IAMSERVER:i_got_this_number_from_you||"&$data&"|@CRLF'"&@CRLF)
                    Else
                        MsgBox(0, "ERROR", "Error while sending UDP message: " & @error)
                        Exit
                    EndIf
                EndIf
                $data = ""
            Else
                $data &= $inc
            EndIf
        EndIf
    EndIf
WEnd

Func Cleanup()
    UDPCloseSocket($recvSocket)
    UDPShutdown()
EndFunc

;;This is the UDP Client
;;Start the server first

; Start The UDP Services
;==============================================
UDPStartup()

; Register the cleanup function.
OnAutoItExitRegister("Cleanup")

; Open a "SOCKET"
;==============================================
$sendSocket = UDPOpen("xxx.xxx.xxx.xxx", 65532); <--- Server IP here
If @error <> 0 Then Exit
$recvSocket = UDPBind(@IPAddress1, 65532)
If @error <> 0 Then Exit
$ti = TimerInit()
$n=0
$data = ""
While 1
    Sleep(10)
    $inc = UDPRecv($recvSocket, 100)
    If $inc <> "" Then
        ConsoleWrite("CLIENT    > Recieved $data: "&$inc)
        $spl = StringSplit($inc,"|",2)
        
        If Not @error And IsArray($spl) And UBound($spl) = 3 Then
            If $spl[2] = @CRLF Then
                If $spl[0] = "IAMSERVER:i_got_this_number_from_you" Then
                    ConsoleWrite("CLIENT    > processed number: "&$spl[1] & @CRLF& @CRLF)
;~                  $status = UDPSend($sendSocket,"IAMSERVER:i_got_this_number_from_you|"&$spl[1]&"|"&@CRLF)
                ElseIf $spl[0] = "other Command" Then
    ;~              ConsoleWrite("CLIENT    > Answer from Server: "&$inc & @CRLF)
                EndIf
                $data = ""
            Else
                $data &= $inc
            EndIf
        EndIf
    EndIf
    If TimerDiff($ti) > 2000 Then
        $ti = TimerInit()
        $n = Random(1,99999,1)
        $status = UDPSend($sendSocket, "HiImClient:i_got_number|"&$n&"|"&@CRLF)
        If $status Then
            ConsoleWrite("CLIENT    > sending: '"&"HiImClient:i_got_number|"&$n&"'@CRLF"&@CRLF)
        Else
            MsgBox(0, "ERROR", "Error while sending UDP message: " & @error)
            Exit
        EndIf
    EndIf
WEnd

Func Cleanup()
    UDPCloseSocket($sendSocket)
    UDPShutdown()
EndFunc

But i yet have to figure out how to get the Client IP on the server.

If the client sends data to server, the server must somehow get packets with the clients IP.

why isnt there a function UDPGetClientIP($socket) or something?

Edited by qsek

Teamspeak 3 User Viewer - Quick and functional TS3 Query script, which shows online users.Cached Screenshot Deleter - Deletes older Fraps Screenshots if they exceed a specified limit.Unresolved Topics:Intercept and modify dragdrop text behaviour in scite

Share this post


Link to post
Share on other sites

@qsek

UDPBind

Return Value

Success: Returns an array : $array[1] contains the real socket, $array[2] contains the specified IP address and $array[3] contains the port.

So if im not wrong $array[2] shud hold client incoming IP adress, never used UDP before so i hope that i did not misunderstood help file


TCP server and client - Learning about TCP servers and clients connection
Au3 oIrrlicht - Irrlicht project
Au3impact - Another 3D DLL game engine for autoit. (3impact 3Drad related)



460px-Thief-4-temp-banner.jpg
There are those that believe that the perfect heist lies in the preparation.
Some say that it’s all in the timing, seizing the right opportunity. Others even say it’s the ability to leave no trace behind, be a ghost.

 

Share this post


Link to post
Share on other sites

#9 ·  Posted (edited)

Thanks for the help bogQ, but:

Success: Returns an array : $array[1] contains the real socket, $array[2] contains the specified IP address and $array[3] contains the port.

So the "specified IP" for UDPBind is the one of the server. Its the one i put into --> UDPBind("xxx.xxx.xxx.xxx", 65532)

I located the Source IP field in the Packet that is recieved from the server. But its in the IPv4 Frame. So i guess its one "level" higher than UDP. But it still should be stored somewhere.

Posted Image

How to query this information?

Update:

Alright, once again the information was in the helpfile, but well hidden, so dont blame me :)

UDPRecv ( socketarray, maxlen [, flag] )

flag [optional] Forces the function to return binary data if set to 1 (default is 0, and will auto detect between binary/string).

Forces the function to return receive from IP/port if set to 2. Results are returned in an Array : [0] data, [1] from IP, [2] from Port.

If you want both just use 3.

Edited by qsek

Teamspeak 3 User Viewer - Quick and functional TS3 Query script, which shows online users.Cached Screenshot Deleter - Deletes older Fraps Screenshots if they exceed a specified limit.Unresolved Topics:Intercept and modify dragdrop text behaviour in scite

Share this post


Link to post
Share on other sites

It works! I was able to make a proper UDP server.

I suggest rewording the help file. Maybe even put an example, such as the following:

;;This is the UDP Server
;;Start this first

#Include <Array.au3>
HotKeySet("{ESC}", "quit")

; Start The UDP Services
;==============================================
UDPStartup()

; Register the cleanup function.
OnAutoItExitRegister("Cleanup")

; Bind to a SOCKET
;==============================================
$Socket = UDPBind("192.168.1.11", 251)

While 1
    ;get UDP data from client
    $Data = UDPRecv($Socket, 50,3)
    
    If IsArray($Data) Then
        ConsoleWrite($Data[0])
        ConsoleWrite(@CRLF)
        
        ;create temp socket from incomming IP/PORT
        $SocketIn = UDPOpen($Data[1], $Data[2])
        
        ;send a reply message
        ConsoleWrite("Sending reply: Hello Client!")
        $status = UDPSend($SocketIn, "Hello Client!     ") 
        If $status = 0 then
            MsgBox(0, "ERROR", "Error while sending UDP message: " & @error)
            Exit
        EndIf
        
        ;remove temp socket
        UDPCloseSocket($SocketIn)
        $Data[0] = 0
        
        ConsoleWrite(@CRLF)
        ConsoleWrite(@CRLF)
    EndIf
    sleep(100)
WEnd

Func quit()
    UDPCloseSocket($Socket)
    UDPShutdown()
    exit
EndFunc

Share this post


Link to post
Share on other sites

The current example under UDPRecv says this:

;;This is the UDP Server

;;Start this first

Although, this is not a server since it is not serving the client.

Matt.

Share this post


Link to post
Share on other sites

One more complaint about the above working code I posted.

I can now reply to the client on the client's port. The destination port does match the client port. However, the server's source port in this reply message is random and does not match. This source port should be the same as our server port. In my sample, the reply message source port should be 251.

example with current procedures:

1. server opens on port 251

2. client sends message to server on destination port 251, source port 1234(random but ok)

3. server sends reply. destination port 1234, source port 5678(random NOT ok)

How it should be:

1. server opens on port 251

2. client sends message to server on destination port 251, source port 1234(random but ok)

3. server sends reply. destination port 1234, source port 251(not random, same as server port, good!)

To fix this, I suggest UDPSend() should have an optional parameter for source port. Do you agree? How may I go about getting this implemented?

Matt.

Share this post


Link to post
Share on other sites

whats wrong with the UDPBind port Param? or UDPOpen port Param?

You specify the ports in those functions to create a socket. (not necessarily needed for udp...)

Share this post


Link to post
Share on other sites

whats wrong with the UDPBind port Param? or UDPOpen port Param?

You specify the ports in those functions to create a socket. (not necessarily needed for udp...)

What's wrong is that the UDPBind/UDPOpen only allow you to specify one port which is either the source port or the destination port. You cannot specify both. I guess UDPBind/UDPOpen procedures need another parameter (not UDPSend as I suggested prevously).

This is quite necessary for UDP. As explained above, when the server responds to the client, the server's source port must be correct. It must be correct so the client can identify the socket correctly.

I checked how a normal DNS server (UDP) responds to a client in wireshark, and I am not able to do it the same response with Autoit. In other words, I would not be able to create a proper DNS server with Autoit.

Matt.

Share this post


Link to post
Share on other sites

i've never had problems with UDP's destination/source ports before, i always specifiy UDPBIND (serverip,serverport) UDPOPEN (serverip,serverport) i always use the same port for both... however it is simply the lack of error checking the protocol has that gives me an error. its strange that you have this problem.

Share this post


Link to post
Share on other sites

i've never had problems with UDP's destination/source ports before, i always specifiy UDPBIND (serverip,serverport) UDPOPEN (serverip,serverport) i always use the same port for both... however it is simply the lack of error checking the protocol has that gives me an error. its strange that you have this problem.

You would not have this issue unless you create a proper UDP server. It will work, and it will work good, but it will not work correctly. Can you change my code above to act correctly?

With UDP you must create your own error checking. I like UDP because of my project. UDP is a small and simple protocol that uses less resources.

Matt.

Share this post


Link to post
Share on other sites

Where and how may I modify the Autoit UDP library and procedures? I would like to try to fix this issue myself.

Matt.

Share this post


Link to post
Share on other sites

Where and how may I modify the Autoit UDP library and procedures? I would like to try to fix this issue myself.

Matt.

You can not do that, and there is no need to do that. The library has excellent error checking and exposes these errors to the end-user in AutoIt via the @error macro.

Share this post


Link to post
Share on other sites

Is Autoit is open source? If so, where is the UDP source?

I do not wish to expose errors to users, I'm sure Autoit contributors have some standard way of implementing changes.

I would like to contribute.

Matt.

Share this post


Link to post
Share on other sites

#20 ·  Posted (edited)

what exactly is your issue again? maybe its not even an autoit issue...

you stated that the arrays giving you are random source ports?

try this instead... tell us whats wrong with it.

[EDIT]

well i changed my mind, my solution (maybe already thought of, but why not hardcoding the server's ports? $port = 251

(why)

i could be dead wrong, and i'm not afraid to say i am, but in my networking class at school my teacher mentioned how microsoft opens a port to recv and opens a different port to send, so wouldn't the port that was being opened to send be the one that is recorded in the packet? microsoft randomizes each created port right? just specify to which port that is opened for which function ie the recv port, $port. just have them both the same on both client and server. (i will look like a tard if i'm wrong, heres hoping)

;;This is the UDP Server
;;Start this first

#Include <Array.au3>
HotKeySet("{ESC}", "quit")

; Start The UDP Services
;==============================================
UDPStartup()

; Register the cleanup function.
OnAutoItExitRegister("Quit")

; Bind to a SOCKET
;==============================================
$port = 251
;~ $Socket = UDPBind("192.168.1.11", 251)
$Socket = UDPBind("192.168.1.11", $port)
While 1
    ;get UDP data from client
    $Data = UDPRecv($Socket, 50,3)

    If IsArray($Data) Then
        ConsoleWrite($Data[0])
        ConsoleWrite(@CRLF)

        ;create temp socket from incomming IP/PORT
;~         $SocketIn = UDPOpen($Data[1], $Data[2])
        $SocketIn = UDPOpen($Data[1], $port)

        ;send a reply message
        ConsoleWrite("Sending reply: Hello Client!")
        $status = UDPSend($SocketIn, "Hello Client!     ")
        If $status = 0 then
            MsgBox(0, "ERROR", "Error while sending UDP message: " & @error)
            Exit
        EndIf

        ;remove temp socket
        UDPCloseSocket($SocketIn)
        $Data[0] = 0

        ConsoleWrite(@CRLF)
        ConsoleWrite(@CRLF)
    EndIf
    sleep(100)
WEnd

Func quit()
    UDPCloseSocket($Socket)
    UDPShutdown()
    exit
EndFunc
Edited by CodyBarrett

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