Questions about sockets and checking for recieved data


#1

So I am working on a solo project for fun. I essentially made a socket server in c# and can send data to it with the lua client created in defold.
I was just wondering how I can check for received data in defold from the server.
So say I send a string to the client from the server how would I check for any data or specific data sent from the server.
so something like
if(client:recievedData)then
print(recievedData)
end
also was wondering how I can check if the client got connected in lua.
I have looked over the lua socket api but can’t find it.
Is there such a function for this?

any help would be greatly appreciated <3


#2

It’s non trivial to make non-blocking socket connections. You can take a look at the tcp client in DefNet for inspiration (https://github.com/britzl/defnet/blob/master/defnet/tcp_client.lua).

socket.select() takes two lists of sockets to check for ability to read and write from.

The receive() function on a client socket is used to read data (possibly partial data).


#3

Sorry but I see receive has two arguments how would I go about receiving any data coming in?
say I send a hi from the server.
how would I print the hi in the console on defold engine?

so something line

if client:receive() then
 print(client:msg)
end

Sorry I know this may be a nooby question but I really do need help on this. I just don’t understand it yet.


#4

The documentation (https://www.defold.com/ref/socket/#client:receive:-pattern---prefix-) says the two arguments are pattern and prefix.

Pattern is either a number with the number of bytes you wish to read or a string indicating how to read data, “*l” reads until a newline for instance. Prefix is any already read data to prefix received data with.


#5

is there a way to set pattern as whatever bytes are received?


#6

Again, the documentation (https://www.defold.com/ref/socket/#client:receive:-pattern---prefix-):

“*a” reads from the socket until the connection is closed. No end-of-line translation is performed;


#7

ok thanx Ill give it my best shot :slight_smile:

wow I feel kinda dumb now ;(
I figured the “*a” was something I was suppose to specify myself not just write “*a”
yup I’m dumb


#8

You will likely not want to use “*a”. It will read until there are no more bytes. I’m not sure what would happen if there’s like a megabyte of data to receive but it will likely cause a hitch while receiving. It’s better, in a game, to set timeout to 0 and read in chunks. Especially if you don’t know how much data there is.


#9

just a question sorry still having trouble showing the data from the receive
if I wanted to show the received data could I in theory do

local data = client:receive("*a", 0)
if data then
         print(data)
end

reason I ask is because I am just trying to make sure I have my client setup right so I can troubleshoot if I am sending the data correctly or not from the server.
sorry again.


#10

bump


#11

What kind of problem? Are you not receiving any data?

I think it’s better if you share all of your socket handler code. It’s hard to tell if what you’re doing is good or bad.

Did you look at the tcp_client.lua from DefNet? It handles non-blocking TCP socket clients without any problems. Sending and receiving data.


#12

I did have a look at it but for some reason it will not connect to my server, not sure why. it doesn’t give an error just says connection was denied.
anyways here is my current code for what I have in my login script . it works completely I just don’t know how I can check for the data I send back.

local tcp_client = require "main.scripts.tcp_client"
local IP = "localhost"
local PORT = 5392

function init(self)
	sock = socket.connect(IP, PORT)
	self.user_message = ""
	self.pass_message = ""
	msg.post(".", "acquire_input_focus") 
	self.message = "" 
	status = gui.get_node("Status")
	
	if not sock then
		gui.set_text(status, "server offline")
	end
	if sock then
		gui.set_text(status, "server online")
	end
	
end
function onData(data)
	print(data)
end
function onDisconnect()
	print("disconnected")
end
function on_input(self, action_id, action)
	local userField = gui.get_node("userBg")
	local passField = gui.get_node("passBg")
	local loginBtn = gui.get_node("loginBtn")
	if(gui.pick_node(userField, action.x, action.y))then
		self.field_selected = "user"
		userField = gui.get_node("userField")
		userTxt = gui.get_text(userField)
	end
	if(gui.pick_node(passField, action.x, action.y))then
		self.field_selected = "pass"
		passField = gui.get_node("passField")
		passTxt = gui.get_text(passField)
	end

	if(gui.pick_node(loginBtn, action.x, action.y))then
		sock:send(self.user_message .. "," .. self.pass_message)
		
	end
	if self.field_selected == "user" then
		if action_id == hash("type") then
			self.user_message = self.user_message .. action.text
			gui.set_text(userField, self.user_message) 
		elseif action_id == hash("backspace") and action.repeated then
			local l = string.len(self.user_message)
			self.user_message = string.sub(self.user_message, 0, l-1) 
			gui.set_text(userField, self.user_message)
		end
	end
	if self.field_selected == "pass" then
		if action_id == hash("type") then
			self.pass_message = self.pass_message .. action.text
			gui.set_text(passField, self.pass_message)
		elseif action_id == hash("backspace") and action.repeated then
				local l = string.len(self.pass_message)
				self.pass_message = string.sub(self.pass_message, 0, l-1) 
				gui.set_text(passField, self.pass_message)
			
		end
	end
end

would really appreciate any help I can get


#13

You don’t have any place where you try to receive data on the socket. All I see is the sock:send() call when clicking the login button. Why do you use sockets for that by the way? It would make a lot more sense to do a login using a normal HTTP request.

Anyway, if you want to receive data on the socket you need to poll for it with some interval. To check if you can read from the socket you use socket.select(). A good place to do this would be in an update loop or using a repeating timer:

-- check if it's possible to read from the socket
-- 0 = don't block the thread, wait 0 seconds
local receivet,sendt = socket.select({ sock }, nil, 0)
-- if the socket is in receivt then it means it's possible to read from the socket
if receivet[sock] then
    -- read a line from the socket (ie until a linebreak \n)
    -- err can be "closed" or "timeout"
    local data, err = sock:receive("*l")
    print("received", data, err)
end

#14

ok so I tried the above code in my update function but when I send the data from the server the client crashes.
This is my current update function.

function update(self, dt)
	local receivet,sendt = socket.select({ sock }, nil, 0)
	-- if the socket is in receivt then it means it's possible to read from the socket
	if receivet[sock] then
		-- read a line from the socket (ie until a linebreak \n)
		-- err can be "closed" or "timeout"
		local data, err = sock:receive("*l")
		print("receivded", data, err)
	end
end

I don’t know if this helps but it is in a gui script. could that cause an issue?
also when I close the server early without any data being sent or received the client log does send the error with nil data received, but when I do send data it doesn’t say anything. prob cus client crashes not sure tho.

thanx again for helping me by the way.


#15

When you say “crash”, do you mean the entire application shut down?
Or, was it a Lua error that was displayed?
Was there any error output in the editor console?

How much data did you send? Is it binary or text you send?


#16

the entire application crashes no Lua errors are displayed no error in output
and Im sending back to the client what the client sends to the server which is just a username and password

Just out of curiosity should I change the 0 in the

receivet, sendt = socket.select({sock}, nil, 0)

to be longer or just leave at 0?


#17

ok. what platform is the client?
The editor console should have said that the client wrote a “_crash” file as well?


#18

sorry I think I mis-explained. it actually just stops responding. but the platform the client it on is windows 10.

sorry that was my bad honestly


#19

Did you get past the if-statement? Add a print before the “sock:receive(”*l")"

Also, when you send the data, do you add a newline? I see the comment here: “read a line from the socket (ie until a linebreak \n)”


#20

I’m not necessarily sending lines of data but just data. should I change to “a*” instead?
also I set the print before the if statement it fires off consistently in the console until I send the socket data and it freezes the client
once it freezes the update function doesn’t seem to keep firing but I would figure that’s normal haha.