• Welcome to Theos PowerBasic Museum 2017.

News:

Attachments are only available to registered users.
Please register using your full, real name.

Main Menu

Simple UDP time server and client for beginners

Started by Patrice Terrier, September 30, 2015, 10:49:25 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Patrice Terrier

This is a PowerBASIC Console Compiler translation of the original codeproject C source code,
using UDP to send datagram between a server and client on a local network, using port 8000.

Server code
'// A simple UDP server that sends the current date and time to the client
'// Original code: http://www.codeproject.com/Articles/11740/A-simple-UDP-time-server-and-client-for-beginners
'// Translated from C to PowerBASIC by Patrice Terrier
'// Date: 09-29-2015

#BREAK ON
#COMPILE EXE "TimeServer.exe"
#Include "win32api.inc"
#Include "time.inc"

%NULL        = 0
%BUFFER_SIZE = 4096
%PORT_NUMBER = 8000 '// Port number to use

declare function my_inet_ntoa lib "wsock32.dll" alias "inet_ntoa" (byval inn as dword) as dword

function pbmain() as long

    local wsa as WSADATA                  '// Used to open windows connection
    local client_length as long           '// Length of client struct
    local bytes_received as long          '// Bytes received from client
    local lps as DWORD                    '// Socket descriptor of server
    local serverinfo as sockaddr_in       '// Information about the server
    local clientinfo as sockaddr_in       '// Information about the client
    local buffer as asciiz * %BUFFER_SIZE '// Where to store received data
    local hp as hostent PTR               '// Information about this computer
    local host_name as asciiz * 256       '// Name of the serverinfo
    local current_time as long            '// Current time

    '// Open windows connection
    if (WSAStartup(&h0202, wsa)) then
        print "Could not open Windows connection."
        function = 0: exit function
    end if

    '// Open a datagram socket
    lps = socket(%AF_INET, %SOCK_DGRAM, byval %NULL)
    if (lps = %INVALID_SOCKET) then
        print "Could not create socket."
    else
        '// Clear out server struct
        RtlFillMemory(byval varptr(serverinfo), sizeof(sockaddr_in), 0)
       
        '// Set family and port
        serverinfo.sin_family = %AF_INET
        serverinfo.sin_port = htons(%PORT_NUMBER)
       
        '// Set address automatically
        gethostname(host_name, sizeof(host_name))
        hp = gethostbyname(host_name)
        '// Check for %NULL pointer
        if (hp = %NULL) then
            print "Could not get host name." 
        else
            local h as hostent, IPaddr as byte ptr
            MoveMemory(byval varptr(h), byval hp, sizeof(hostent))
            MoveMemory(byval varptr(IPaddr), byval h.h_addr_list, 4)
            dim n(0 to 3) as byte at IPaddr
            '// Assign the address
            serverinfo.sin_addr.S_un.S_un_b.s_b1 = n(0)
            serverinfo.sin_addr.S_un.S_un_b.s_b2 = n(1)
            serverinfo.sin_addr.S_un.S_un_b.s_b3 = n(2)
            serverinfo.sin_addr.S_un.S_un_b.s_b4 = n(3)
           
            '// Bind address to socket
            if (bind(lps, serverinfo, sizeof(sockaddr_in)) = -1) then
                print "Could not bind name to socket."
            else
                '// Print out serverinfo information
                local ptrAddr as dword ptr, ptrAsciiz as asciiz ptr
                ptrAddr = @hp.h_addr_list
                ptrAsciiz = my_inet_ntoa(@@ptrAddr)
                print "server running on " + @ptrAsciiz
                print "Press Ctrl+Break or Ctrl+Pause/Attn to quit"
               
                local zTime as asciiz * 8
                client_length = sizeof(sockaddr_in)
                '// Loop and get data from clients
                do
                    '// Receive bytes from client
                    bytes_received = recvfrom(lps, buffer, %BUFFER_SIZE, byval 0, clientinfo, client_length)
                    if (bytes_received < 0) then
                        print "Could not receive datagram.": exit do
                    else
                        '// Check for time request
                        if (rtrim$(buffer, chr$(13,10)) = "GET TIME") then
                            '// Get current time
                            current_time = time(0)
                            RtlFillMemory(byval varptr(zTime), sizeof(zTime), 0)
                            MoveMemory(byval varptr(zTime), byval varptr(current_time), 4)

                            ptrAsciiz = ctime(current_time)
                            print "Sending current time: " + rtrim$(@ptrAsciiz, any chr$(0,10,13))

                            '// Send data back
                            if (sendto(lps, zTime, sizeof(zTime), 0, clientinfo, client_length) <> sizeof(zTime)) then
                                print "Error sending datagram.": exit do
                            end if
                        end if
                    end if
                loop
            end if
        end if
        closesocket(lps)
    end if
    WSACleanup()
    function = 0
end function


Client code
'// Gets the current time from a UDP server
'// Original code: http://www.codeproject.com/Articles/11740/A-simple-UDP-time-server-and-client-for-beginners
'// Translated from C to PowerBASIC by Patrice Terrier
'// Date: 09-29-2015

#BREAK ON
#COMPILE EXE "TimeClient.exe"
#Include "win32api.inc"
#Include "time.inc"

%NULL        = 0
%BUFFER_SIZE = 4096
%PORT_NUMBER = 8000 '// Port number to use

function pbmain() as long

    local wsa as WSADATA                  '// Used to open windows connection
    local server_length as long           '// Length of server struct
    local lps as DWORD                    '// Socket descriptor
    local serverinfo as sockaddr_in       '// Information about the server
    local clientinfo as sockaddr_in       '// Information about the client
    local buffer as asciiz * %BUFFER_SIZE '// Where to store received data
    local hp as hostent PTR               '// Information about the server
    local host_name as asciiz * 256       '// Name of the serverinfo
    local current_time as long            '// Time received
    dim a(1 to 4) as byte                 '// Server address components in xxx.xxx.xxx.xxx form
    local K as long
 
    '// Make sure command line is correct
    if (parsecount(command$, ".") <> 4) then
        print "Usage: TimeClient server_adress(xxx.xxx.xxx.xxx)."
        function = 0: exit function
    else
        for K = 1 to 4
            a(K)= val(parse$(command$, ".", K))
        next
    end if

    '// Open windows connection
    if (WSAStartup(&h0202, wsa)) then
        print "Could not open Windows connection."
        function = 0: exit function
    end if

    '// Open a datagram socket
    lps = socket(%AF_INET, %SOCK_DGRAM, byval %NULL)
    if (lps = %INVALID_SOCKET) then
        print "Could not create socket."
    else
        '// Clear out server struct
        RtlFillMemory(byval varptr(serverinfo), sizeof(sockaddr_in), 0)

        '// Set family and port
        serverinfo.sin_family = %AF_INET
        serverinfo.sin_port = htons(%PORT_NUMBER)
       
        '// Set server address
        serverinfo.sin_addr.S_un.S_un_b.s_b1 = a(1)
        serverinfo.sin_addr.S_un.S_un_b.s_b2 = a(2)
        serverinfo.sin_addr.S_un.S_un_b.s_b3 = a(3)
        serverinfo.sin_addr.S_un.S_un_b.s_b4 = a(4)
       
        '// Clear out client struct
        RtlFillMemory(byval varptr(clientinfo), sizeof(sockaddr_in), 0)
       
        '// Set family and port
        clientinfo.sin_family = %AF_INET
        clientinfo.sin_port = htons(0)
       
        gethostname(host_name, sizeof(host_name))
        hp = gethostbyname(host_name)
        '// Check for %NULL pointer
        if (hp = %NULL) then
            print "Could not get host name."
        else
            local h as hostent, IPaddr as byte ptr
            MoveMemory(byval varptr(h), byval hp, sizeof(hostent))
            MoveMemory(byval varptr(IPaddr), byval h.h_addr_list, 4)
            dim n(1 to 4) as byte at IPaddr
           
            '// Assign the address
            clientinfo.sin_addr.S_un.S_un_b.s_b1 = n(1)
            clientinfo.sin_addr.S_un.S_un_b.s_b2 = n(2)
            clientinfo.sin_addr.S_un.S_un_b.s_b3 = n(3)
            clientinfo.sin_addr.S_un.S_un_b.s_b4 = n(4)
           
            '// Bind local address to socket
            if (bind(lps, clientinfo, sizeof(sockaddr_in)) = -1) then
                print "Cannot bind address to socket."
            else
                '// Tranmsit data to get time
                server_length = sizeof(sockaddr_in)
                buffer = "GET TIME"
                if (sendto(lps, buffer, sizeof(buffer), 0, serverinfo, server_length) < 0) then
                    print "Error transmitting data."
                else
                    '// Receive time
                    local zTime as asciiz * 8
                    if (recvfrom(lps, zTime, sizeof(zTime), 0, serverinfo, server_length) < 0) then
                        print "Error receiving data."
                    else
                        '// Display time
                        MoveMemory(byval varptr(current_time), byval varptr(zTime), 4)
                        local ptrAsciiz as asciiz ptr: ptrAsciiz = ctime(current_time)
                        print "Server time is: " + rtrim$(@ptrAsciiz, any chr$(0,10,13))
                    end if
                end if
            end if
        end if   
        closesocket(lps)
    end if

    WSACleanup()
    function = 0
end function


Usage:
On server run "TimeServer" from a DOS prompt.
On client run "TimeClient xxx.xxx.xxx.xxx" from a DOS prompt where xxx.xxx.xxx.xxx matches the address displayed by TimeServer.

To shut down TimeServer, press Ctrl+Break.

Note: The EXE(s) from the attached zip file, have been created with PBCC 7.0 (beta) and using José Roca's include files.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

José Roca