In SocketServerClientHandler.java, the function receivedData has references to handshakingPacket.
If you have the time, could you expound upon that?
In SocketServerClientHandler.java, the function receivedData has references to handshakingPacket.
If you have the time, could you expound upon that?
The handshaking packet is the initial data the client sends until /r/n/r/n.
This is used to deal with websockets, because websockets always send HTTP headers (which end with /r/n/r/n) when connecting to a socket server.
Because of this, normal sockets just send /r/n/r/n to finish the âhandshakingâ packet.
When the handshaking packet is done (so when /r/n/r/n is received), the server checks if it has a WebSocket header in it, and if it does, the server knows that it should wrap and unwrap packets using the websocket protocol.
Anyway, for your client, you just want to send
when you connect, this lets the server know the handshaking packet is done and that you are a normal socket client, and not a websocket client.
Thanks!
<goes off to look up
>
are just characters (\r is bytecode 13,
is bytecode 10).
See SocketConnection.java at line 204.
<CR><LF>!
Thanks to your help, Iâve made good progress today. The asynchronous client is sending to and receiving messages from the java server now. I get the clientConnected message (âhello newly connected client!â) when I send my functionCall packet, but the packet is not yet correct as I get no indication that receivedFunctionCall has been called.
Iâll get back on it tomorrow.
Thanks again!
Is this something that my client would have to explicitly do? From the console output on the server, it appears to have identified the incoming ip and port.
In the receivedData function of the above ref class under
while(data.hasRemaiing())
there are get opcode, get size, get mask, and get payload commented sections. What is the get mask section and must that be a part of the FunctionCall packet?
Opcode and mask is for the websocket functionality, if the client is not using the websocket protocol, this code will be skipped.
The client is supposed to send the TCP and UDP port, which is most clearly programmed in the UE4 plugin:
void ULowEntrySocketConnection::OnConnect()
{
// clear buffers and such, also fail all functioncalls and latentfunctioncalls
// example:
SendingBytes.Empty();
ReceivedBytes.Empty();
ReceivingPacket.Empty();
SendingUdpPackets.Empty();
// set receiving stage to receive type
ReceivingStage = EReceivingStage::RECEIVE_TYPE;
// send the handshaking packet
SendingBytes.Add(13); // \r
SendingBytes.Add(10); //
SendingBytes.Add(13); // \r
SendingBytes.Add(10); //
// send the UDP port of the server (the one it will connect to), send a 0 byte 4 times if you don't want UDP functionality
SendingBytes.Add(PortUdp >> 24);
SendingBytes.Add(PortUdp >> 16);
SendingBytes.Add(PortUdp >> 8);
SendingBytes.Add(PortUdp);
// send the UDP port of the client, send a 0 byte 4 times if you don't want UDP functionality
int32 LocalPort = GetLocalPortUdp();
SendingBytes.Add(LocalPort >> 24);
SendingBytes.Add(LocalPort >> 16);
SendingBytes.Add(LocalPort >> 8);
SendingBytes.Add(LocalPort);
}
The reason you have to send the UDP port of the client and server is so that the server can validate whether youâve typed in the correct UDP port etc, because UDP doesnât do this for you like TCP does.
Also, if you donât send your UDP port to the server, then the server doesnât know to what UDP port it should be sending to.
If you donât support UDP, just use 0 for both the server UDP port as well as the client UDP port.
The source I have for ULowEntrySocketconnection::OnConnect() looks like this:
void ULowEntrySocketConnection::OnConnect()
{
SendingBytes.Empty();
ReceivedBytes.Empty();
ReceivingStage = EReceivingStage::RECEIVE_TYPE;
ReceivingPacket.Empty();
SendingUdpPackets.Empty();
ResetConnectionValidation();
CanCallOnDisconnect = true;
for(TPair<int32, FLowEntrySocketConnectionFunctionCallAction*> FunctionCallEntry : FunctionCalls)
{
FLowEntrySocketConnectionFunctionCallAction* FunctionCall = FunctionCallEntry.Value;
if(FunctionCall != nullptr)
{
FunctionCall->Failed();
}
}
FunctionCalls.Empty();
for(TPair<int32, FLowEntrySocketConnectionLatentFunctionCallAction*> LatentFunctionCallEntry : LatentFunctionCalls)
{
FLowEntrySocketConnectionLatentFunctionCallAction* LatentFunctionCall = LatentFunctionCallEntry.Value;
if(LatentFunctionCall != nullptr)
{
LatentFunctionCall->Failed();
}
}
LatentFunctionCalls.Empty();
#if !PLATFORM_HTML5
SendingBytes.Add(13); // \r
SendingBytes.Add(10); //
SendingBytes.Add(13); // \r
SendingBytes.Add(10); //
#endif
SendingBytes.Add(PortUdp >> 24);
SendingBytes.Add(PortUdp >> 16);
SendingBytes.Add(PortUdp >> 8);
SendingBytes.Add(PortUdp);
int32 LocalPort = GetLocalPortUdp();
SendingBytes.Add(LocalPort >> 24);
SendingBytes.Add(LocalPort >> 16);
SendingBytes.Add(LocalPort >> 8);
SendingBytes.Add(LocalPort);
OnConnectEvent.ExecuteIfBound(this);
}
Did you insert the comments to the code you posted or am I looking in the wrong place?
No I cleaned it up a bit so it is easier to understand, the actual code does exactly that as well but it is a bit messier.
Iâve made progress but have hit another snag.
I get to the âReceived Function Call:â console message but apparently the byte array bytes passed to the receivedFunctionCall function on the java server is empty and I believe I am still missing something in my packet.
I construct my packet as a byte array as follows:
handshake { 13, 10, 13, 10 }
serverUDPport { 0, 0, 0, 0 }
client UDPport { 0, 0, 0, 0 }
function call byte { 2 }
an integer (1234) for the function call id { 0, 0, 4, 210 }
an integer for the length { 0, 0, 0, 57 }
then my message, which is just 3 integers and two strings for testing purposes.
If I understand correctly, bytes should get my message, unless I have left something important out?
âan integer (1234) for the function call id { 0, 0, 4, 210 }â
âan integer for the length { 0, 0, 0, 57 }â
These are incorrect. If the length of the message is below 127, it should be 1 byte, if the message length is 128 or higher, it should be a 4 byte integer with the first bit (the signed bit) set to 1.
The same counts for the function call id, since your function call id is higher than 127, the first bit of it should be a 1.
To visualize it, you could use microsofts calculator, set it to programming (Alt+3), and set it to Word (which means 4 byte signed integer).
Anyway, in the Java library you can find the code in classes/sockets/SocketFunctions.java, here you can find the 1-4 byte int code. You can find the code of it below.
if(value <= 127)
{
buffer.put((byte) (value));
}
else
{
buffer.put((byte) ((value >> 24) | (1 << 7)));
buffer.put((byte) (value >> 16));
buffer.put((byte) (value >> 8));
buffer.put((byte) (value));
}
@
Excellent! Thanks! That got it.
I also had some errors in my logic and misinterpreted âlength of packetâ to mean the length of the message, but those are all fixed and the function call succeeds.
I still have some errors in the way I construct my packet (It may be necessary to port your bytedatawriter to C#) but this biggest hurdle (at least for me) is overcome.
Thanks again for all your help!
Hi, thanks for this excellent library!
I am trying to sort an array of structs comparing a float value attribute in the struct. What is the way to achieve this using the Sort blueprint?
Thanks,
Structs are treated as primitive types (like int, float, etc). In order to accept any struct (or an array of any struct), you will need to use generics. The blueprint system does not support generics like C++ does (as far as I know). Because of this, a struct sorting blueprint is currently impossible.
You could use UObjects instead of structs, which can be sorted with a blueprint.
You could also just sort the array yourself in blueprint:
Hi ,
Whats the correct way to close a SocketServer?
I got a problem where my address is still in use. I am using ServerSocket.terminate() but when i try to open a new socket with same configuration i get the following message âAddress already in use: bindâ.
Any idea why?
terminate() will cause the data that youâve already added to the client.send() buffer to still be send.
terminateImmediately() will cause the server to immediately quit, even if there is still data in the client.send() buffers.
Also, the terminate()/terminateImmediately() calls could be queued up if called in a different thread, meaning that you have to call listen() in order for them to actually happen.
Lastly, the terminate()/terminateImmediately() calls can happen in a different thread, so I would use .sleep(5000) after calling terminateImmediately() to know for certain the server is closed.
So in summary, this should work:
server.terminateImmediately();
server.listen();
.sleep(5000);
Itâs a bit messy, because I never anticipated someone starting a new server on the same port. Why would you actually need that, isnât it better to host a different server on a different port?
Thanks for the fast reply, i give it a try!
I close and open sockets based on the load. I could of-course just use another port but as the framework works now it has a socket âconfigurationsâ that are used to create SocketServers which can be turned on or off which is replicated to a specific type of server.
Iâm trying to use the Sort Object Array function but itâs saying that my function signature is incorrect. Any help would be greatly appreciated.
Hmm, could you try naming them like this:
Donât know if it matters, but thatâs the only thing that is different from my testing code.
Also, if you havenât yet, you should save+compile your code (the gears button with âCompileâ on it), if you havenât done this yet, then that could also cause the error youâre describing.
Edit: Oh Iâve figured it out. It doesnât matter how you name the objects, but the returned boolean should be called âReturnâ. Iâll update the documentation of the blueprint for that.
That worked. Glad it was so simple. Thanks!