Polling for the IP address of a server?

Just starting out? Need help? Post your questions and find answers here.
User avatar
Michael Vogel
Addict
Addict
Posts: 2799
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Polling for the IP address of a server?

Post by Michael Vogel »

Hi, I'd like to write a program for my students to allow them giving an answer to certain quiz questions.

There will be a server which waits for answers ('A' ... 'D') and will display a histogram after a while.

The clients are on the notebooks of the students and will send the character representing the chosen answer.

This is not my problem, but every day (in different classrooms) the server will have a different IP address (DHCP) and I don't want, that the clients have to be configured each time. So how it can be done, that the server sends out an broadcast which will be seen by the clients to check the IP address of the server?

Here is my prototype of the server...

Code: Select all

Procedure Init()

	#MaxSessions=100
	Global Dim Sessions(#MaxSessions)

	#ServerID=666
	#ServerPort=6699

	Global ABCD
	Global Event
	Global ClientID
	Global ClientIP
EndProcedure

Procedure NewSession(IP)
	Protected i=0

	Repeat
		If Sessions(i)=0
			Sessions(i)=IP
			ProcedureReturn #True;		unbekannte Session (neu)
	
		ElseIf Sessions(i)=IP
			ProcedureReturn #False;	bekannte Session
		EndIf
		i+1
	Until i=#MaxSessions

	ProcedureReturn #False;			zuviele Sessions aktiv

EndProcedure
Procedure Main()

Init()

If InitNetwork()
	If CreateNetworkServer(#ServerID, #ServerPort,#PB_Network_TCP)

		Debug "wait"

		Repeat
			Event=NetworkServerEvent()

			ClientID=EventClient()
			If ClientID
				ClientIP=GetClientIP(ClientID)
			EndIf

			Select Event

			Case #PB_NetworkEvent_Connect
				Debug "Client connected, ip/hostname: "+IPString(ClientIP)

			Case #PB_NetworkEvent_Disconnect
				Debug "Client disconnected "+IPString(ClientIP)
				;Quit=1

			Case #PB_NetworkEvent_Data

				If NewSession(ClientIP)
					Debug "got what?"
					Debug ClientIP
					If ReceiveNetworkData(ClientID,@ABCD,4)
						Debug ABCD
					EndIf
				EndIf

			EndSelect
			Delay(1)
		Until Quit=1

	Else
		Debug "Error creating server"
	EndIf
Else
	Debug "Error initing network"
EndIf


CloseNetworkServer(#ServerID)
Debug "aus"

EndProcedure

Main()
And here is a (very) simple test for a client...

Code: Select all

#ServerID=666
#ServerPort=6699

Global ABCD
Global SessionID

If InitNetwork()
	SessionID=OpenNetworkConnection("1.1.1.1",#ServerPort)

	ABCD='B';
	SessionID2=OpenNetworkConnection("1.1.1.1",#ServerPort)
	If sessionid2 : SendNetworkData(SessionID2,@ABCD,4) : EndIf

	Debug SessionID
	If SessionID
		Debug "schicke"
		ABCD='A';
		SendNetworkData(SessionID,@ABCD,4)
		Delay(500)
		CloseNetworkConnection(SessionID)

	EndIf
	
EndIf
User avatar
netmaestro
PureBasic Bullfrog
PureBasic Bullfrog
Posts: 8451
Joined: Wed Jul 06, 2005 5:42 am
Location: Fort Nelson, BC, Canada

Post by netmaestro »

You can have their connection routine look on the network for a computer name rather than IP address, should solve the problem.

Code: Select all

SessionID=OpenNetworkConnection("Teacher",#ServerPort)
User avatar
Michael Vogel
Addict
Addict
Posts: 2799
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

Thanks netmaestro, you are sooo fast! :wink:

I'll check soon, if I can use this tip in my school...

Even each teacher PC will have a different name in the classrooms, I can do a list of them and each client will poll them all...

Michael
User avatar
Michael Vogel
Addict
Addict
Posts: 2799
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Post by Michael Vogel »

Hehe,
thanks oncemore to netmaestro, so I could change my program to do the polling in different classrooms (see codes below), but the initial problem is still back:

I'd like to start all Clients with disabled buttons which get enabled only, when polling is started from the server. So I seem to need a broadcast which is seen from all clients...

My actual version works like that:
- Server is started on one PC
- Clients are started on different PCs, checking if a Server (in the ABCD.ini or Data.s) is present
- When Polling is started at the Server, the A-B-C-D entries (but only one of each client) is accepted and the result will be seen at the end.


Server

Code: Select all

Procedure Init()

	EnableExplicit

	#Pollzeit=300; Zehntelsekunden

	#MehrfachAntworten=#False

	#MaxSessions=100
	Global Dim Sessions(#MaxSessions)

	Global Dim Counter(4)
	Global Dim Bingo(4)
	Global Total

	#ServerID=666
	#ServerPort=6699

	#Starttext="&Starte Wertung..."

	#RandX=10
	#RandY=25
	#BarX=50
	#BarY=280
	#BarZ=10
	#BildX=#RandX*2+#BarX*4+#Barz*3
	#BildY=#RandY*2+#BarY

	#WinRand=10
	#WinUnten=81
	#WinX=#BildX+#WinRand<<1
	#WinY=#BildY+#WinRand+#WinUnten

	Global ABCD
	Global Event
	Global ok
	Global ClientID
	Global ClientIP
	Global Sekunden
	Global dummy.s

	Global i,j,x,y,quit

	Global WinID
	Global ImageID=CreateImage(0,#BildX,#BildY)

	LoadFont(0,"Trebuchet MS",16)
	LoadFont(1,"Trebuchet MS",10)

	Enumeration 1
		#Start
		#Ende
		#Bild
	EndEnumeration

	Enumeration
		#IgnoriereNachrichten
		#AkzeptiereNachrichten
	EndEnumeration

	Global Modus=#IgnoriereNachrichten

EndProcedure
Procedure.w Limit(low.w,med.w,high.w)
	If med<low
		ProcedureReturn low
	ElseIf med>high
		ProcedureReturn high
	Else
		ProcedureReturn med
	EndIf
EndProcedure
Procedure Meldung(titel.s,meldung.s,icon=#IDI_ASTERISK,wait=30)

	;#IDI_QUESTION		; (?)
	;#IDI_HAND				; (X)
	;#IDI_EXCLAMATION	; /!\
	;#IDI_ASTERISK		; (i)

	Define mouse.point

	#Hoehe=64 ; mit Ok-Knopf: 96

	GetCursorPos_(@mouse)
	x=limit(0,(mouse\x)-130,GetSystemMetrics_(#SM_CXSCREEN)-260)
	y=limit(0,(mouse\y)-100,GetSystemMetrics_(#SM_CYSCREEN)-#hoehe)

	If OpenWindow(1,x,y,272,#hoehe,titel,#PB_Window_SystemMenu|#PB_Window_Invisible)

		CreateGadgetList(WindowID(1))
		ImageGadget(1, 12, 14, 0, 0, LoadIcon_(0,icon))

		TextGadget(2,60,20,250,30,meldung)
		DisableGadget(1,1)
		HideWindow(1, 0)

		quit=0
		SetTimer_(WindowID(1),1,80,0) ; Default: 100ms
		Repeat

			Select WaitWindowEvent()
			Case #PB_Event_CloseWindow,#PB_Event_Gadget
				quit=#MAXSHORT
			Case #WM_TIMER
				quit+1
				;SetGadgetText(2,Str(quit))
			Case #WM_CHAR
				Select  EventwParam()
				Case 13,32,27
					quit=#MAXSHORT
				EndSelect
				;Default
				;SetGadgetText(2,Str(event))
			EndSelect
		Until quit>wait

		CloseWindow(1)
	EndIf
EndProcedure

Procedure ClearCounter()
	Protected i
	For i=1 To 4
		Counter(i)=0
	Next i
	Total=0
EndProcedure
Procedure ClearSessions()
	Protected i
	For i=0 To #MaxSessions
		Sessions(i)=0
	Next i
EndProcedure
Procedure.l NewSession(IP)
	Protected i=0

	If #MehrfachAntworten
		ProcedureReturn #True;			für Testzwecke - alles ist erlaubt!
	EndIf

	Repeat
		If Sessions(i)=0
			Sessions(i)=IP
			ProcedureReturn #True;		unbekannte Session (neu)

		ElseIf Sessions(i)=IP
			ProcedureReturn #False;	bekannte Session
		EndIf
		i+1
	Until i=#MaxSessions

	ProcedureReturn #False;			zuviele Sessions aktiv

EndProcedure

Procedure.l Prozent(i)
	ProcedureReturn #RandY+#BarY*(100-i)/100
EndProcedure
Procedure Haudrauf()
	Protected i,j,n

	n=100
	For i=1 To 4
		If (Bingo(i)<n) And (Bingo(i)>0)
			n=Bingo(i)
			j=i
		EndIf
	Next i
	Bingo(j)+1

EndProcedure
Procedure DrawBars()

	StartDrawing(ImageOutput(0))

	Box(0,0,#BildX,#BildY,$800000)

	For i=0 To 10
		y=Prozent(i*10)
		LineXY(#RandX>>1,y,#BildX-#RandX+1,y,#Blue)
	Next i

	If Total
		j=0
		For i=1 To 4
			Bingo(i)=Counter(i)*100/Total
			j+Bingo(i)
		Next i
		If j<100
			Haudrauf()
			j+1
		EndIf

		For i=1 To 4
			y=Prozent(Bingo(i))
			Box(#RandX+(i-1)*(#BarX+#BarZ),y,#BarX-1,#RandY+#BarY-y+1,#Red)
		Next i

		DrawingFont(FontID(0))
		DrawingMode(#PB_2DDrawing_Transparent)


		For i=1 To 4
			dummy=Str(Bingo(i))+"%"
			x=TextWidth(dummy)>>1+1
			DrawText(#RandX+(i-1)*(#BarX+#BarZ)+#BarX>>1-x,#RandY,dummy,#White)
		Next i

		DrawingFont(FontID(1))
		For i=1 To 4
			dummy=Chr(64+i);Str(i);"25%"
			x=TextWidth(dummy)>>1+1
			DrawText(#RandX+(i-1)*(#BarX+#BarZ)+#BarX>>1-x,#BarY+#RandY+2,dummy,#White)
		Next i

	Else
		DrawingFont(FontID(0))
		DrawingMode(#PB_2DDrawing_Transparent)

		If Modus=#AkzeptiereNachrichten
			dummy="Bitte Wertung abgeben!"
		Else
			dummy="Keine Wertung!"
		EndIf
		x=TextWidth(dummy)>>1+1
		y=TextHeight(dummy)>>1+1
		DrawText(#BildX>>1-x,#BildY>>1-y,dummy,#White)

	EndIf

	StopDrawing()
	SetGadgetState(#Bild,ImageID)

EndProcedure

Procedure InitServer()
	If InitNetwork()=0
		Meldung("Fehler","Kein Netzwerk verfügbar!",#IDI_HAND)
		End
	EndIf

	If CreateNetworkServer(#ServerID, #ServerPort,#PB_Network_TCP)=0
		Meldung("Fehler","Der Server kann nicht gestartet werden!",#IDI_HAND)
		End
	EndIf

EndProcedure
Procedure Main()

	Init()
	InitServer()

	WinID=OpenWindow(0,0,0,#WinX,#WinY,"ABCD-Server",#PB_Window_ScreenCentered|#PB_Window_Invisible|#PB_Window_SystemMenu)
	;LoadFont(0,"Trebuchet MS",64)

	CreateGadgetList(WinID)
	ButtonGadget(#Start,#RandX,#BildY+#WinRand+12,#BildX,28,#Starttext)
	ButtonGadget(#Ende,#RandX,#BildY+#WinRand+46,#BildX,28,"Ende")
	ImageGadget(#Bild,#WinRand-1,#WinRand,#BildX,#BildY,ImageID,#PB_Image_Border)

	AddKeyboardShortcut(0,#PB_Shortcut_Escape,666)
	AddKeyboardShortcut(0,#PB_Shortcut_S,#Start)
	SetTimer_(WinID,1,100,0)

	DrawBars()
	HideWindow(0,0)

	Repeat
		Select WaitWindowEvent()

		Case #PB_Event_Gadget,#PB_Event_Menu
			Select EventGadget()

			Case #Start
				ClearSessions()
				ClearCounter()
				Modus=#AkzeptiereNachrichten
				DrawBars()
				Sekunden=#Pollzeit
				DisableGadget(#Start,1)
				DisableGadget(#Ende,1)

			Case #Ende
				quit=#True

			Case 666
				If Modus=#IgnoriereNachrichten : quit=1 : EndIf

			EndSelect

		Case #WM_TIMER
			If Modus=#AkzeptiereNachrichten
				If Sekunden
					Sekunden-1
					SetGadgetText(#Start,StrF(Sekunden/10,1)+" Sek.")
				Else
					SetGadgetText(#Start,#Starttext)
					Modus=#IgnoriereNachrichten
					DrawBars()

					DisableGadget(#Start,0)
					DisableGadget(#Ende,0)
				EndIf
			EndIf

		Case #PB_Event_CloseWindow
			If Modus=#IgnoriereNachrichten : quit=1 : EndIf

		EndSelect

		Event=NetworkServerEvent()

		ClientID=EventClient()
		If ClientID
			ClientIP=GetClientIP(ClientID)
		EndIf

		Select Event
			;Case #PB_NetworkEvent_Connect
			;Debug "Client connected, ip/hostname: "+IPString(ClientIP)
			;Case #PB_NetworkEvent_Disconnect
			;Debug "Client disconnected "+IPString(ClientIP)

		Case #PB_NetworkEvent_Data
			ok=NewSession(ClientIP)
			ok=(ReceiveNetworkData(ClientID,@ABCD,4)) And ok
			If ok And (Modus=#AkzeptiereNachrichten)
				If (ABCD>'@') And (ABCD<'E')
					Counter(ABCD-64)+1
					Total+1
				EndIf
				;Debug Chr(ABCD)
				;Else
				;Debug Chr(ABCD)+" ignored"
			EndIf

		EndSelect

	Until Quit=1


	CloseNetworkServer(#ServerID)

EndProcedure

Main()

Client

Code: Select all

Procedure Init()

	EnableExplicit

	#MaxServer=10

	#ServerID=666
	#ServerPort=6699

	#Ausszeit=10000

	Global ABCD
	Global SessionID
	Global Dim Server.s(#MaxServer)
	Global i,x,y
	Global Server
	Global Dummy.s
	Global Blockierung

	Global WinID
	Global quit

	Global Font

EndProcedure
Procedure.w Limit(low.w,med.w,high.w)
	If med<low
		ProcedureReturn low
	ElseIf med>high
		ProcedureReturn high
	Else
		ProcedureReturn med
	EndIf
EndProcedure
Procedure Meldung(titel.s,meldung.s,icon=#IDI_ASTERISK,wait=30)

	;#IDI_QUESTION		; (?)
	;#IDI_HAND				; (X)
	;#IDI_EXCLAMATION	; /!\
	;#IDI_ASTERISK		; (i)

	Define mouse.point

	#Hoehe=64 ; mit Ok-Knopf: 96

	GetCursorPos_(@mouse)
	x=limit(0,(mouse\x)-130,GetSystemMetrics_(#SM_CXSCREEN)-260)
	y=limit(0,(mouse\y)-100,GetSystemMetrics_(#SM_CYSCREEN)-#hoehe)

	If OpenWindow(1,x,y,272,#hoehe,titel,#PB_Window_SystemMenu|#PB_Window_Invisible)

		CreateGadgetList(WindowID(1))
		ImageGadget(1, 12, 14, 0, 0, LoadIcon_(0,icon))

		TextGadget(2,60,20,250,30,meldung)
		DisableGadget(1,1)
		HideWindow(1, 0)

		quit=0
		SetTimer_(WindowID(1),1,80,0) ; Default: 100ms
		Repeat

			Select WaitWindowEvent()
			Case #PB_Event_CloseWindow,#PB_Event_Gadget
				quit=#MAXSHORT
			Case #WM_TIMER
				quit+1
				;SetGadgetText(2,Str(quit))
			Case #WM_CHAR
				Select  EventwParam()
				Case 13,32,27
					quit=#MAXSHORT
				EndSelect
				;Default
				;SetGadgetText(2,Str(event))
			EndSelect
		Until quit>wait

		CloseWindow(1)
	EndIf
EndProcedure

Procedure.l CheckServer(IP.s,Port) ;nur echte IP-Adressen verwenden
	Define *host.HOSTENT
	Define was.WSADATA
	Define IPAddress
	Define s
	Define ret=#False
	Define addr.SOCKADDR_IN
	Define version=(2<<8)+1

	If WSAStartup_(version,@was.WSADATA)=0

		*host=gethostbyname_(IP)
		If *host<>#Null
			IpAddress=PeekL(*host\h_addr_list)
			IP=StrU(PeekB(IpAddress),0)+"."+StrU(PeekB(IpAddress+1),0)+"."+StrU(PeekB(IpAddress+2),0)+"."+StrU(PeekB(IpAddress+3),0)

			s=SOCKET_(#AF_INET,#SOCK_STREAM,0);
			If s<>#INVALID_SOCKET
				addr.SOCKADDR_IN
				addr\sin_family= #AF_INET;
				addr\sin_port= htons_(Port)
				addr\sin_addr= inet_addr_(IP)
				If connect_(s,@addr.SOCKADDR_IN,SizeOf(SOCKADDR_IN)) <> #SOCKET_ERROR
					ret=#True
				EndIf
				closesocket_(s)
			EndIf
		EndIf
		WSACleanup_()
	EndIf
	ProcedureReturn ret
EndProcedure
Procedure InitClient()
	If InitNetwork()=0
		Meldung("Fehler","Kein Netzwerk verfügbar!",#IDI_HAND)
		End
	EndIf

	; Einlesen von bis zu #MaxServer Namen von Servern (Index 0 bis höchstens #MaxServer-1)
	i=0
	#Datei="ABCD.ini"

	If FileSize(#Datei)>0
		ReadFile(0,#Datei)
		While (i<#MaxServer) And (Eof(0)=0)
			Dummy=Trim(ReadString(0))
			If Len(Dummy)
				Server(i)=Dummy
				i+1
			EndIf
		Wend
		CloseFile(0)
	EndIf

	; Einlesen von vordefinierten Servern (Index n bis höchstens #MaxServer)
	Repeat
		Read Dummy
		If Dummy="*" : Break : EndIf
		Server(i)=Dummy
		i+1
	Until i>#MaxServer

	Server=i

	DataSection
		Data.s "vo-notebook"
		Data.s "*"
	EndDataSection

	i=0
	Repeat
		If CheckServer(Server(i),#ServerPort)
			SessionID=OpenNetworkConnection(Server(i),#ServerPort)
			If SessionID : Break : EndIf
		EndIf
		i+1
	Until i=Server

	If SessionID=0
		Meldung("Fehler","Server-Anwendung nicht gefunden!",#IDI_HAND)
		End
	EndIf

EndProcedure
Procedure DisableButtons(auswahl)
	For x=1 To 4
		If x=auswahl
			SetGadgetText(x,Chr(x+64))
		Else
			SetGadgetText(x,"·")
		EndIf
		DisableGadget(x,1)
	Next x

	Blockierung=GetTickCount_()+#Ausszeit
EndProcedure
Procedure EnableButtons()
	If Blockierung
		If GetTickCount_()>Blockierung
			Blockierung=0
			For x=1 To 4
				SetGadgetText(x,Chr(x+64))
				DisableGadget(x,0)
			Next x
		EndIf
	EndIf
EndProcedure
Procedure Main()

	Init()
	InitClient()

	#ButtonX=96
	#ButtonY=96

	WinID=OpenWindow(0,0,0,#ButtonX<<2,#ButtonY,"ABCD-Client",#PB_Window_ScreenCentered|#PB_Window_Invisible|#PB_Window_SystemMenu)
	LoadFont(0,"Trebuchet MS",64)
	SetGadgetFont(#PB_Default,FontID(0))

	CreateGadgetList(WinID)
	For i=0 To 3
		ButtonGadget(i+1,i*#ButtonX,0,#ButtonX,#ButtonY,Chr(65+i))
	Next i

	AddKeyboardShortcut(0,#PB_Shortcut_A,1)
	AddKeyboardShortcut(0,#PB_Shortcut_B,2)
	AddKeyboardShortcut(0,#PB_Shortcut_C,3)
	AddKeyboardShortcut(0,#PB_Shortcut_D,4)
	AddKeyboardShortcut(0,#PB_Shortcut_Escape,666)

	SetTimer_(WinID,1,100,0)

	HideWindow(0,0)

	quit=0
	Repeat
		Select WaitWindowEvent()

		Case #PB_Event_Gadget,#PB_Event_Menu
			i=EventGadget()
			Select i

			Case 1 To 4
				DisableButtons(i)
				ABCD=i+64
				SendNetworkData(SessionID,@ABCD,4)
				Delay(100)

			Case 666
				quit=1
			EndSelect

		Case #PB_Event_CloseWindow
			quit=1

		Case #WM_TIMER
			EnableButtons()

		EndSelect
	Until quit

	CloseNetworkConnection(SessionID)

EndProcedure

Main()
Post Reply