• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

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