udp networking in freebasic.

New to FreeBASIC? Post your questions here.
Post Reply
Boromir
Posts: 463
Joined: Apr 30, 2015 19:28
Location: Oklahoma,U.S., Earth,Solar System
Contact:

udp networking in freebasic.

Post by Boromir »

For many years making multiplayer games has been an interest of mine. I've learned how to make a simple network in freebasic using tcp but it runs too slow for games. I've read that udp networking is the way to go for speed but I can't find any information on how to do this in freebasic.
My needs:
--more than 1 client
--be able to send a lot of information quickly for RTS and action games

This looks simple but it has no udp examples. Can I use this for games?
http://www.freebasic.net/forum/viewtopi ... =7&t=23421
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: udp networking in freebasic.

Post by badidea »

Not sure if imple [N]etwork [C]onnection can be used with UDP.

In 2010 I played with UDP a little: http://www.freebasic.net/forum/viewtopi ... 6&start=14
Boromir
Posts: 463
Joined: Apr 30, 2015 19:28
Location: Oklahoma,U.S., Earth,Solar System
Contact:

Re: udp networking in freebasic.

Post by Boromir »

I tested you program. Do you mind if I fool with it and use it in some of my programs?

I added visuals to test the speed and there seems to be some bad delay in messages sent from the server to a client. Client to server messages are instant though.

network.bi

Code: Select all

#define __FD_SETSIZE 32

#If Defined(__FB_WIN32__)
  #Include Once "win/winsock2.bi"
#ElseIf Defined(__FB_LINUX__)
  #Include Once "crt/netdb.bi"
  #Include Once "crt/sys/socket.bi"
  #Include Once "crt/netinet/in.bi"
  #Include Once "crt/arpa/inet.bi"
  #Include Once "crt/unistd.bi"
  #Include Once "crt/sys/select.bi"
#Else
  #Error Platform Not supported
#EndIf

function init_socket_API() as integer
  #Ifdef __FB_WIN32__
    dim as WSADATA wsaData
    return WSAStartup(MAKEWORD(2,2), @wsaData)
  #Else
    return 0
  #EndIf
end function

sub close_socket_API()
  #Ifdef __FB_WIN32__
    WSACleanup()
  #Else
    'Nothing to do
  #EndIf
end sub

function inet_addr_rev(ipAddress as in_addr) as string
  dim as ubyte ptr pChar = cptr(ubyte ptr, @ipAddress)
  return str(pChar[0]) & _
    "." & str(pChar[1]) & _
    "." & str(pChar[2]) & _
    "." & str(pChar[3])
end function

type net_data
  as integer seqNr
  as integer x
  as integer y
end type
server

Code: Select all

Screen 18,32
Dim As Integer x,y,x2,y2
#include "network.bi"
#include "fbgfx.bi"

#DEFINE SERVER_PORT 27015
#DEFINE CLIENT_IP "192.168.1.18"

'--- SERVER ---

dim as SOCKET socketId
dim as sockaddr_in clientAddr
dim as sockaddr_in serverAddr
dim as integer serverAddrSize = sizeof(serverAddr)
dim as integer clientAddrSize = sizeof(clientAddr)
dim as integer iResult, sendCount

dim as net_data netDataIn
dim as net_data netDataOut

dim as fd_set readfds, readfds0
dim as fd_set writefds, writefds0
dim as timeval timeout

iResult = init_socket_API()
if (iResult <> 0) Then print "Winsock init: Error":Sleep:End

socketId = socket_(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
if (socketId < 0) then print "Socket: Error":close_socket_API():End

serverAddr.sin_family = AF_INET
serverAddr.sin_port = htons(SERVER_PORT)
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY)

iResult = bind(socketId, cptr(sockaddr ptr, @serverAddr), serverAddrSize)
if (iResult < 0) then print "Bind: Error":close_socket_API():Sleep:End

clientAddr.sin_family = AF_INET
clientAddr.sin_port = htons(SERVER_PORT)
clientAddr.sin_addr.s_addr = inet_addr(CLIENT_IP)

FD_ZERO(@readfds0)
FD_ZERO(@writefds0)
FD_SET_(socketId, @readfds0)
FD_SET_(SocketId, @writefds0)


Do
 	ScreenLock
	Cls
	Circle(x,y),10,RGB(255,255,255)
	Circle(x2,y2),10,RGB(255,255,255)
	ScreenUnLock
	Sleep 1
	If MultiKey(17) Then y2-=1
	If MultiKey(31) Then y2+=1
	If MultiKey(32) Then x2+=1
	If MultiKey(30) Then x2-=1

 'Keep a backup because SelectSocket will change the data
  readfds = readfds0
  writefds = writefds0
  timeout = type(0, 0)

  iResult = selectSocket(FD_SETSIZE, @readfds, @writefds, NULL, @timeout)
  if (iResult = 0) then
    print "SelectSocket: Timeout"
  elseif (iResult < 0) then
    print "SelectSocket: Error"
  else
    'print "SelectSocket: Sockets ready: "; iResult
  end if

    netDataOut.seqNr = sendCount
    netDataOut.x = x2:netDataOut.y = y2'"Server says: No!"
    if(FD_ISSET(socketId, @writefds)) then
      iResult = sendto(socketId, cptr(ubyte ptr, @netDataOut), _
        SizeOf(net_data), 0, cptr(sockaddr ptr, @clientAddr), clientAddrSize)
      if (iResult < 0) then
        print "Send: Error":closeSocket(socketId):close_socket_API():Sleep:End
      else
        print "Bytes send:"; iResult;
        print " to: "; inet_addr_rev(clientAddr.sin_addr)
      end if
    end if
    sendCount += 1
 
  if(FD_ISSET(socketId, @readfds)) then
    iResult = recvfrom(socketId, cptr(ubyte ptr, @netDataIn), _
      sizeof(net_data), 0, cptr(sockaddr ptr, @clientAddr), @clientAddrSize)
    if (iResult > 0) then
      print "Bytes received:"; iResult;
      Print " from: "; inet_addr_rev(clientAddr.sin_addr)
      Print "SeqNr: "; netDataIn.seqNr;
      print " text: "; netDataIn.x
      x=netDataIn.x:y=netDataIn.y
    elseif (iResult = 0) then
      print "Receive: Connection closed":closesocket(socketId):close_socket_API():Sleep:End
    else
      print "Receive: Error":closesocket(socketId):close_socket_API():Sleep:End
    end if
  end if

Loop Until MultiKey(1)

iResult = closesocket(socketId)
if (iResult < 0) then
  print "CloseSocket: Error"
end if
close_socket_API()
client

Code: Select all

Screen 18,32
Dim As Integer x,y,x2,y2
#Include "network.bi"
#include "fbgfx.bi"

#DEFINE SERVER_PORT 27015
#DEFINE SERVER_IP "192.168.1.11"

'--- CLIENT ---

dim as SOCKET socketId
dim as sockaddr_in serverAddr
dim as integer serverAddrSize = sizeof(serverAddr)
dim as integer iResult, sendCount

dim as fd_set readfds, readfds0
dim as fd_set writefds, writefds0
dim as timeval timeout

dim as net_data netDataIn
dim as net_data netDataOut

iResult = init_socket_API()
if (iResult <> 0) then
  print "Winsock init: Error"
  sleep
  end
end if

socketId = socket_(AF_INET, SOCK_DGRAM, IPPROTO_UDP)
if (socketId < 0) then
  print "Socket: Error"
  close_socket_API()
  sleep
  end
end if

serverAddr.sin_family = AF_INET
serverAddr.sin_port = htons(SERVER_PORT)
serverAddr.sin_addr.s_addr = inet_addr(SERVER_IP)

FD_ZERO(@readfds0)
FD_ZERO(@writefds0)
FD_SET_(socketId, @readfds0)
FD_SET_(SocketId, @writefds0)


Do
	ScreenLock
	Cls
	Circle(x,y),10,RGB(255,255,255)
	Circle(x2,y2),10,RGB(255,255,255)
	ScreenUnLock
	Sleep 1
	If MultiKey(17) Then y-=1
	If MultiKey(31) Then y+=1
	If MultiKey(32) Then x+=1
	If MultiKey(30) Then x-=1
  
 'Keep a backup because SelectSocket will change the data
  readfds = readfds0
  writefds = writefds0
  timeout = type(0, 0)
 
  iResult = selectSocket(FD_SETSIZE, @readfds, @writefds, NULL, @timeout)
  if (iResult = 0) then
    print "SelectSocket: Timeout"
  elseif (iResult < 0) then
    print "SelectSocket: Error"
  else
    'print "SelectSocket: Sockets ready: "; iResult
  end if

    netDataOut.seqNr = sendCount
    netDataOut.x=x:netDataOut.y=y'"Client says: Yes!"
    if(FD_ISSET(socketId, @writefds)) then
      print "Send: Trying..."
      iResult = sendto(socketId, cptr(ubyte ptr, @netDataOut), _
        sizeof(net_data), 0, cptr(sockaddr ptr, @serverAddr), serverAddrSize)
      if (iResult < 0) then
        print "Send: Error":CloseSocket(socketId):close_socket_API():sleep:end
      else
        Print "Bytes send:"; iResult;
        print " to: "; inet_addr_rev(serverAddr.sin_addr)
      end if
    end if
    sendCount += 1

  if(FD_ISSET(socketId, @readfds)) then
    print "Receive: Trying..."
    iResult = recvfrom(socketId, cptr(ubyte ptr, @netDataIn), _
      sizeof(net_data), 0, cptr(sockaddr ptr, @serverAddr), @serverAddrSize)
    if (iResult > 0) then
      Print "Bytes received:"; iResult;
      Print " from: "; inet_addr_rev(serverAddr.sin_addr)
      Print "SeqNr: "; netDataIn.seqNr;
      print " text: "; netDataIn.x
      x2=netDataIn.x:y2=netDataIn.y
    elseif (iResult = 0) then
      print "Receive: Connection closed":CloseSocket(socketId):close_socket_API():sleep:end
    else
      Print "Receive: Error":closesocket(socketId):close_socket_API():sleep:end
    end if
  end if

Loop Until MultiKey(1)

iResult = closeSocket(socketId)
if (iResult < 0) then
  print "CloseSocket: Error"
end if
close_socket_API()

badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: udp networking in freebasic.

Post by badidea »

[duplicate]
Last edited by badidea on Apr 30, 2017 15:18, edited 1 time in total.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: udp networking in freebasic.

Post by badidea »

Do you mind if I fool with it and use it in some of my programs?
Not at all, please do fool around with it :-)
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: udp networking in freebasic.

Post by D.J.Peters »

To day there is no need for using UDP packages anymore.
In the time of modems like 19K 56K or 115K baud it was OK.

Both on LAN and WAN the ping rate are the same for TCP and UDP packages.

The frame where the content of TCP packages are included are little bit larger than UDP
but TCP comes in in the same order at it was send and no packages will be lost.

For UDP packages you have collect them all and bring it in the right order
and if an UDP package are missing you have to send an extra message to the server.

"hello server one package with timestamp XYZ from client ABC are lost please send it again"

For short sorting the incomming UDP packages by a timestamp and ask for missing packages
will not be faster then using directly TCP packages.

I wrote the TCP plugin for Basic4GL and we have tested it with 32 clients per game session UDP was never really faster.

For all those reasons I don't put UDP in my cute Simple Network Connection include file.

There is one point where UDP is the first choice if you stream video and or audio content.
(The result of a missing UDP package while streaming is a cute cube with wrong colors on the screen but with 24 FPS you won't noticed this tiny error)

bla bla bla :-)

Joshy
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: udp networking in freebasic.

Post by caseih »

UDP is very useful for many things. For one it's a connectionless protocol. This makes it very nice to use for some things unlike TCP. For example simple data acquisition where the odd missed packet is no problem.

I really admire your work, joshy, but you're off the mark here saying UDP is outdated like a modem. UDP and TCP serve different, complementary and orthogonal purposes.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: udp networking in freebasic.

Post by D.J.Peters »

caseih wrote:UDP is very useful for many things. For one it's a connectionless protocol. This makes it very nice to use for some things unlike TCP. For example simple data acquisition where the odd missed packet is no problem.
Ups this are toaly new for me ;-)

We are talking about UDP vs TCP packages for multiplayer games you know ?

Joshy
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: udp networking in freebasic.

Post by caseih »

Pretty sure UDP still has a place in gaming communication. In any case, the OP said he found TCP/IP connections were too slow for him, likely due to the time it takes to build and tear down connections, and likely due to how he was using connections. I am guessing that many games implement their own light-weight connection protocols on top of UDP for various reasons including faster build/tear downs, better handling of dropped connections, NAT traversal, and other issues.

In fact, UDP's connectionless nature combined with how firewalls NAT UDP packets means that UDP can facilitate direct peer-to-peer communication through NATs and firewalls, whereas TCP/IP cannot. Once a UDP packet goes through the firewall and opens an outward facing UDP port, anyone can send packets to it. I'm sure many games rely on this feature of UDP.
Rainwulf
Posts: 35
Joined: Mar 28, 2007 11:33

Re: udp networking in freebasic.

Post by Rainwulf »

Where do you get network.bi from? Been looking for half an hour and still cant find it.
marcov
Posts: 3455
Joined: Jun 16, 2005 9:45
Location: Netherlands
Contact:

Re: udp networking in freebasic.

Post by marcov »

D.J.Peters wrote:To day there is no need for using UDP packages anymore.
In the time of modems like 19K 56K or 115K baud it was OK.

Both on LAN and WAN the ping rate are the same for TCP and UDP packages.
Ping is ICMP, so neither TCP or UDP.
The frame where the content of TCP packages are included are little bit larger than UDP
but TCP comes in in the same order at it was send and no packages will be lost.
Afaik the TCP/IP handshake is quite slow (since it has to go back and forth 3 times).
For UDP packages you have collect them all and bring it in the right order
and if an UDP package are missing you have to send an extra message to the server.
If they are sequential, and if they must be 100% reliable. A lot of game information is already outdated the next packet, and such packets don't have to be resent. Moreover, with TCP if packet N-1 is missing, packet N won't be passed to the client, thus waiting for resend.

With an own simple integrity system and packet based communications instead of streams, this can be avoided with UDP.
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: udp networking in freebasic.

Post by caseih »

Rainwulf wrote:Where do you get network.bi from? Been looking for half an hour and still cant find it.
viewtopic.php?t=25618, not sure where Boromir got it from.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: udp networking in freebasic.

Post by badidea »

Rainwulf wrote:Where do you get network.bi from? Been looking for half an hour and still cant find it.
Who? My / Boromirs network.bi is posted above.
My version is from 2010, small changes might be needed.
Rainwulf
Posts: 35
Joined: Mar 28, 2007 11:33

Re: udp networking in freebasic.

Post by Rainwulf »

Yea im an bright and didn't read the post properly.

What are those "FD" commands? I ended up using an SDL example that worked perfectly, but it involves having to have the SDL dlls.
As well, never seen the timeout command either. A few more comments would help a lot!


The network.bi would work perfectly, i just want to fully understand the code before i implement it.
badidea
Posts: 2586
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: udp networking in freebasic.

Post by badidea »

FD, see:
https://beej.us/guide/bgnet/html/multi/advanced.html

edit: The timeout command is related to this. Instead of a separate thread that waits 'forever' on data, we check and wait for data until timeout and continue main loop (with or without data received). No other threads needed.

It has been a while since I played with this, I could be wrong.
Post Reply