More threading

General FreeBASIC programming questions.
badidea
Posts: 1897
Joined: May 24, 2007 22:10
Location: The Netherlands

Postby badidea » Nov 21, 2010 1:10

Thanks, I have the basics working.
Using fd_set and 2-way communications, multiple clients.
Works with WinXp and Ubuntu.

Client.bas

Code: Select all

#include "network.bi"
#include "fbgfx.bi"

#DEFINE SERVER_PORT 27015
#DEFINE SERVER_IP "127.0.0.1"

'--- CLIENT ---

dim as SOCKET socketId
dim as sockaddr_in serverAddr
dim as integer serverAddrSize = sizeof(serverAddr)
dim as integer iResult, quit, sendData, sendCount
dim as string key

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)

print "q = quit"
print "s = send"

while (quit = 0)

  quit = 0: sendData = 0
  key = lcase(inkey())
  if (key = "q") then quit = 1
  if (key = "s") then sendData = 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

  if(sendData = 1) then
    netDataOut.seqNr = sendCount
    netDataOut.text = "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
  end if

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

  sleep 1, 1

wend

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

print "End."
sleep


Server.bas

Code: Select all

#include "network.bi"
#include "fbgfx.bi"

#DEFINE SERVER_PORT 27015
#DEFINE CLIENT_IP "127.0.0.1"

'--- 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, quit, sendData, sendCount
dim as string key

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
end if

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

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
end if

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)

print "q = quit"
print "s = send"

while (quit = 0)
 
  quit = 0: sendData = 0
  key = lcase(inkey())
  if (key = "q") then quit = 1
  if (key = "s") then sendData = 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
 
  if(sendData = 1) then
    netDataOut.seqNr = sendCount
    netDataOut.text = "Server says: No!"
    if(FD_ISSET(socketId, @writefds)) then
      print "Send: Trying..."
      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
  end if
 
  if(FD_ISSET(socketId, @readfds)) then
    print "Receive: Trying..."
    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.text
    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
 
  sleep 1, 1
 
wend

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

print "End."
sleep


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 string * 32 text
end type


Now, some management still to do before I can use it in my game.
Things like: Accepting new client, let clients time out, validate the UDP message, etc.
marcov
Posts: 2840
Joined: Jun 16, 2005 9:45
Location: Eindhoven, NL
Contact:

Postby marcov » Nov 21, 2010 14:41

D.J.Peters wrote:
threads often not the right solution.

FD_SET's are a powerfull key.

you must create sockets and put in an FD_SET (an array of sockets)

now your server or your clients can ask with "select()" is any data aviable ?
(without to wait)

of course you can define an optional timeout value too.


I don't think that applies to games. It is more something from pure network servers.

Games have to react swiftly to other events too.
D.J.Peters
Posts: 8019
Joined: May 28, 2005 3:28
Contact:

Re: More threading

Postby D.J.Peters » May 13, 2014 14:42

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

Re: More threading

Postby badidea » May 15, 2014 20:59

Ah, yes, network delay correction.
That's what killed my initial enthousism for making a (fast-paced) network game.

Return to “General”

Who is online

Users browsing this forum: Google [Bot] and 2 guests