Any package based TCP Server example?

Hello,

is there any 4.2+ TCP Server example?

for example UDP have like here:

while TCP do not have examples like here:

and googling examples i only seems some Client(but not Server) examples or unsafe-download examples.

need to send messages from different (no-godot) app into godot TCP Server.

got something working, but problem is:

using use peerTCP.get_data(bytes) and peerTCP.get_available_bytes()
while more than one messages can be contained in get_data(bytes)
Thought to send message length in bytes first, but i guess i do something totally wrong.
Because didnt seen proper examples.
But i belive there is better build in solution for TCP?

For example current solution can receive:

[28, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 10, 0, 0, 0, 28, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 115, 111, 117, 110, 100, 0, 0, 0, 28, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 115, 99, 101, 110, 101, 0, 0, 0, 28, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 12, 0, 0, 0, 99, 104, 97, 114, 97, 99, 116, 101, 114, 0, 0, 0, 4, 0, 0, 0, 44, 0, 0, 0, 97, 115, 115, 101, 116, 115, 47, 115, 99, 101, 110, 101, 115, 47, 99, 104, 97, 114, 97, 99, 116, 101, 114, 47, 99, 104, 97, 114, 97, 99, 116, 101, 114, 46, 115, 99, 101, 110, 101, 46, 116, 115, 99, 110, 4, 0, 0, 0, 8, 0, 0, 0, 116, 101, 114, 114, 97, 105, 110, 0, 4, 0, 0, 0, 52, 0, 0, 0, 97, 100, 100, 111, 110, 115, 47, 114, 97, 100, 105, 97, 110, 99, 101, 45, 116, 101, 114, 114, 97, 105, 110, 47, 116, 101, 114, 114, 97, 105, 110, 47, 116, 101, 114, 114, 97, 105, 110, 46, 115, 99, 101, 110, 101, 46, 116, 115, 99, 110, 0, 0, 28, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 1, 0, 0, 0, 2, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 28, 0, 0, 0, 4, 0, 0, 0, 4, 0, 0, 0, 20, 0, 0, 0, 76, 111, 99, 97, 116, 105, 111, 110, 67, 111, 109, 112, 111, 110, 101, 110, 116, 0, 0, 0, 28, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 112, 111, 115, 105, 116, 105, 111, 110, 28, 0, 0, 0, 3, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 16, 0, 0, 0, 83, 99, 101, 110, 101, 67, 111, 109, 112, 111, 110, 101, 110, 116, 0, 0, 28, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 115, 99, 101, 110, 101, 0, 0, 0, 4, 0, 0, 0, 8, 0, 0, 0, 116, 101, 114, 114, 97, 105, 110, 0]

that give me [0, 0] after var value = bytes_to_var(available_bytes);
(that is only first array(28 code) but not second - could also use this to split message into 2 messages, but again im not sure if this is a way to go)

while it contains more data (second message) there

UDP works fine tho. But with UDP also needed to create more channels, since Godot was loosing a lot of packages when did stress-test of messages locally(127.0.0.1)

Btw, seen one code that use:

peerstream = PacketPeerStream.new()
peerstream.set_stream_peer( connection )

but it didnt work for me at all since peerstream.get_available_packet_count() was always 0 for me. (even when there was data from client)

1 Like

You can’t use bytes_to_var() if the packet has been created from another application. bytes_to_var() is specific to Godot and it’s the counterpart of var_to_bytes()

You’ll need to create your own buffer with your own packet format and check and process it as you need.

Here’s a small example but you’ll need to modify it to be able to append the data you are getting from the other application until you have a full packet to parse as the data can come chunked in different poll() calls.

extends Node


const PORT = 9955


var server:TCPServer
var client:StreamPeerTCP
var server_stream:StreamPeerTCP


func _ready() -> void:
	set_process(false)


func _process(delta: float) -> void:
	if client:
		process_client()
		return

	if server:
		process_server()
		return


func process_client() -> void:
	client.poll()


func process_server() -> void:
	if server_stream:
		server_stream.poll()
		var available_bytes = server_stream.get_available_bytes()
		if available_bytes > 0:
			var data = server_stream.get_data(available_bytes)
			if data[0] == OK:
				_log('Getting %s bytes' % available_bytes)
				var message = decode_message(data[1])
				_log('Decoded message: %s' % message)
	elif server.is_connection_available():
		server_stream = server.take_connection()
		_log('Server taking connection')


func encode_message(message:String) -> PackedByteArray:
	var packet = StreamPeerBuffer.new()
	var buffer = message.to_ascii_buffer()
	packet.put_u32(0xDEADBEEF)
	packet.put_u32(buffer.size())
	packet.put_data(buffer)

	return packet.data_array


func decode_message(buffer:PackedByteArray) -> String:
	var packet = StreamPeerBuffer.new()
	packet.data_array = buffer
	packet.seek(0)
	if packet.get_u32() == 0xDEADBEEF:
		var size = packet.get_u32()
		var data = packet.get_data(size)
		if data[0] == OK:
			return (data[1] as PackedByteArray).get_string_from_ascii()

	return ""


func _log(message:String) -> void:
	var l = Label.new()
	l.text = message
	%LogContainer.add_child(l)


func _on_server_button_pressed() -> void:
	server = TCPServer.new()
	var result = server.listen(PORT)
	_log('Server listening -> %s' % error_string(result))
	set_process(true)


func _on_client_button_pressed() -> void:
	client = StreamPeerTCP.new()
	var result = client.connect_to_host("localhost", PORT)
	_log('Client connecting -> %s' % error_string(result))
	set_process(true)


func _on_send_button_pressed() -> void:
	if not client:
		return

	var buffer = encode_message("hello world")
	client.put_data(buffer)
	_log('Sending packet')

Result:

1 Like

This is not true, as i have separate application, and it already works for me. (its only about this small tcp issue sometimes)

Here is link for you(tho array now is 28 not 19):

Problem is only about TCP package wrapper, i could use own solution to split received data into packages, my only question was about better solution.

UDP works fine for me

TCP works, but sometimes i have 2 packages in 1 message poll (+ package-wrapper dont see package) - this is problem i need solve.

Here’s a small example but you’ll need to modify it to be able to append the data you are getting from the other application until you have a full packet to parse as the data can come chunked in different poll() calls.

Yes, since ready2use solution no work, i guess i will go “prefix bytes” way like in your example.

But again, i can and i will do [bytes_to_var()] and/or [var_to_bytes()]
got no issue using them - it all works fine.

code:

		#UDP
		server.poll()
		if server.is_connection_available():
			peerUDP = server.take_connection()
		if peerUDP != null:
			for peerNum in peerUDP.get_available_packet_count():
				var packet:PackedByteArray = peerUDP.get_packet()
				if packet:
					var value = bytes_to_var(packet)
					_manage_data(value)

This code works perfectly when i send from my Other(non-godot) APP serialized package to unserialize in Godot. (i do receive proper arrays in arrays with values as i need)

		#TCP
		if server.is_connection_available():
			peerTCP = server.take_connection()
		if peerTCP != null:
			var status = peerTCP.get_status()
			if status == 3:
				peerTCP = null
			elif status == 2:
				var code = peerTCP.poll()
				var bytes := peerTCP.get_available_bytes()
				if bytes > 0:
					var data := peerTCP.get_data(bytes)
					print("data ", data)
					if data[0] == 0:
						var value = bytes_to_var(data[1]);
						_manage_data(value)

This code works ALMOST perfectly when i send from my Other(non-godot) APP, the only problem i need solve is to split this into packages or receive it as single packages, because sometimes i receive 2 packages as one so bytes_to_var receive for me only first array but not second.

data[1] here sometimes contains 2 packages (as per spec data[0] contains error code if is there)
value deserialize data[1], but because data[1] sometimes contains 2 arrays in row, it deserialize only first one.

i also tried:

		if server.is_connection_available():
			peerTCP = server.take_connection()
			peerstream = PacketPeerStream.new()
			peerstream.set_stream_peer( peerTCP )
		if peerTCP != null:
			for peerNum in peerstream.get_available_packet_count():
				var packet:PackedByteArray = peerstream.get_packet()
				if packet:
					var value = bytes_to_var(packet);
					_manage_data(value)

BUT here it always see peerstream.get_available_packet_count() as 0

Non-Godot APP is an Java APP that use Netty library to send TCP or UDP and got custom data Godot-spec serializer that works perfectly

As per your example, i can do custom data processing liek you got there, its only about better ready-2-use solution to make it work (i talk about PacketPeerStream wrapper)

What you have in example have one of custom solution i was already thinking and wrote about this in first post. If there is no other way, i will do it ofc the custom solution.

If no other ready2use solution, then i will use things like 0xDEADBEEF and package size prefix to split packages ofc. (btw, i do not need verify/secure packages)

It is still true. Just because you implemented the binary serialization API Godot uses to make those functions work does not mean that my comment is wrong. You did not specify that you were the one implementing the other application or that it was using the same binary serialization API that Godot uses and I can’t read minds.

As I said before, there’s no built-in way to do what you want because the other application could format its packets as it wants. You’ll need to take care of that, filling the buffer until you have enough data and then parsing that data.

You did not specify that you were the one implementing the other application or that it was using the same binary serialization API that Godot uses and I can’t read minds.

i send from my Other(non-godot) APP

Maybe there was some miscomunication, but its just better to ask than assume.

Fixing miscommunication now:
I can and i have power to change this App too.


While for now i can do like was said before.

Still Question from me:

  • Do Godot have some special Specs avaialble how packet should look(prefix/etc)
    to have it working for tcp_peer_stream.get_packet()(PacketPeerStream)