I'm currently having a working TCP connection between Unity(Client) and an Android App(Server). Unity handles the task to send my controller joysticks data to the Server.
I have 2 joysticks on my controller and both of them return Vector2 output(x,y) (in total, I will receive 4 float values if I use both at the same time)
My current method is to individually parse them into a byte array and send each of them to the Server (Below is my code to send the left joy x and y values from the Client to the Server)
float fData_Lx = LeftJoy.GetAxis(SteamVR_Input_Sources.Any).x;
float fData_Ly = LeftJoy.GetAxis(SteamVR_Input_Sources.Any).y;
byte[] clientMessageAsByteArray_1 = BitConverter.GetBytes(fData_Lx);
byte[] clientMessageAsByteArray_2 = BitConverter.GetBytes(fData_Ly);
Array.Reverse(clientMessageAsByteArray_1); // Flip - Reverse from little Endian to Big Endian (C# -> Java)
Array.Reverse(clientMessageAsByteArray_2);
// Write byte array to socketConnection stream.
stream.Write(clientMessageAsByteArray_1, 0, clientMessageAsByteArray_1.Length);
stream.Write(clientMessageAsByteArray_2, 0, clientMessageAsByteArray_2.Length);
Server code to receive the data:
in = new DataInputStream(new BufferedInputStream(socket.getInputStream()));
in.read(cData);
float f = ByteBuffer.wrap(cData).order(ByteOrder.BIG_ENDIAN).getFloat(); //Use to read single Data
System.out.println("Data: " + f);
Therefore, the Server will receive 2 floats at the same time and it won't know which float is the x and which float is the y.
I want to ask if there is a solution to sort these floats at the Server side so that it can understand these float values. I'm planning to send 4 floats at the same time as I gonna use both of my joysticks.
Really appreciate your help (Please don't be mad at me, I know my logic to receive the data is really bad)
if there is a solution to sort these floats at the Server side so that it can understand these float values
-> No!
The server only knows it received a byte[] .. if you wouldn't tell it it is actually a float it wouldn't even know that fact.
However this is TCP. So actually you can rely on two facts:
Everything that is sent in a certain order is received in the exact same order.
There is an individual TCP socket for each of your clients.
These two should be enough to exactly identify your input:
simply make sure the server reads not one but rather two consecutive float values (first x then y - that's exactly how your client sends it). As long as you didn't receive both your Input is not valid anyway, so you wait until you definitely received x and y.
on server side you already know from which of the existing client sockets you received the data. So once you received the two floats you already know exactly who was the sender of these values and who you have to apply them to on server side.
Is there a special reason why you invert the order of the arrays on client side and then tell the server to receive them in BigEndian? Why not simply tell the server to receive LittleEndian and on client side only invert the array within if(BitConverter.IsBigEndian) ?
Related
This question already has answers here:
gRPC + Image Upload
(2 answers)
Closed 3 years ago.
Is there a good pattern for sending a large dataset using gRPC and protocol buffers that has a mix of some header data, and some large repeated data?
E.g. for a server that accepts a matrix generated by some other process as input, a service and message might look as follows:
service MatrixService {
rpc DoSomething(stream Matrix) returns (stream Matrix) {}
}
message Matrix {
uint32 num_rows = 1;
uint32 num_cols = 2;
string created_by = 3;
string creation_parameters = 4;
repeated float data = 5;
}
It's really only the data field that is large enough to require streaming, the rest of the parameters are just headers that the server only needs to receive once.
Is there some commonly used pattern for efficiently making gRPC request that contains some initial header information, and a large amount of repeated data?
Should oneOf be used in cases like this (i.e. splitting the Matrix message into a oneOf { MatrixHeader, MatrixData }?
Or is it typically more common to just set the header fields on the first request, and leave them blank by convention in subsequent requests?
Or are there some other solutions that I've not considered?
You might want to consider chunking your data. See gRPC + Image Upload.
Also, note that the maximum receive message size is 4 MB by default. You can increase it by setting the channel argument GRPC_ARG_MAX_RECEIVE_MESSAGE_LENGTH
TLDR: Can I register callback functions in golang to get notified if a struct member is changed?
I would like to create a simple two-way-binding between a go server and an angular client. The communication is done via websockets.
Example:
Go:
type SharedType struct {
A int
B string
}
sharedType := &SharedType{}
...
sharedType.A = 52
JavaScript:
var sharedType = {A: 0, B: ""};
...
sharedType.A = 52;
Idea:
In both cases, after modifying the values, I want to trigger a custom callback function, send a message via the websocket, and update the value on the client/server side accordingly.
The sent message should only state which value changed (the key / index) and what the new value is. It should also support nested types (structs, that contain other structs) without the need of transmitting everything.
On the client side (angular), I can detect changes of JavaScript objects by registering a callback function.
On the server side (golang), I could create my own map[] and slice[] implementations to trigger callbacks everytime a member is modified (see the Cabinet class in this example: https://appliedgo.net/generics/).
Within these callback-functions, I could then send the modified data to the other side, so two-way binding would be possible for maps and slices.
My Question:
I would like to avoid things like
sharedType.A = 52
sharedType.MemberChanged("A")
// or:
sharedType.Set("A", 52) //.. which is equivalent to map[], just with a predifined set of allowed keys
Is there any way in golang to get informed if a struct member is modified? Or is there any other, generic way for easy two-way binding without huge amounts of boiler-plate code?
No, it's not possible.
But the real question is: how do you suppose to wield all such magic in your Go program?
Consider what you'd like to have would be indeed possible.
Now an innocent assignment
v.A = 42
would—among other things—trigger sending stuff
over a websocket connection to the client.
Now what happens if the connection is closed (client disconnected),
and the sending fails?
What happens if sending fails to complete before a deadline is reached?
OK, suppose you get it at least partially right and actual modification of the local field happens only if sending succeeds.
Still, how should sending errors be handled?
Say, what should happen if the third assignment in
v.A = 42
v.B = "foo"
v.C = 1e10-23
fails?
you could try using server sent events (SSE) to send realtime data to the frontend, while sending a single post request with ur changes. That way you can monitor in the back and send data every second.
I'm trying to create a custom game server protocol in Ruby but i'm failing to understand how i can/should do a couple things:
Q->1#
Server sends an array to client using TCPServer/TCPSocket. but i can't use JSON as the transfer needs to be binary.. How can i convert a ruby array into binary which can then be transformed back into an array in client side?
This is my server:
#!/usr/bin/env ruby
require 'socket'
server = TCPServer.new 5020
loop do
Thread.start(server.accept) { |c|
print "new Client connected"
a = ["Hello, there"]
payload_with_header = CustomProtocolModule.constructMethod(a) # what method do i use to convert a (array -> binary representation? don't really understand .unpack, .pack, what template would i use if i did use String#Unpack? will String#Unpack work for what i need?
client.write payload_with_header
client.close
}
end
(Above is my first question)
Q->2#
Next since i know i need to use some sort of termination to check the end of message or a way to determine if the client/server has received the full message could i set the first two bytes of the payload to contain the size of the message? How would i do this server-side & client-side? The receiving party would have to loop TCPSocket.recv ? until it receives the first two bytes (the header), then read up the size the first two bytes contains? Something like this is what i had in mind:
| Payload Header (2 bytes) | array (contains cmd, message etc) |
If someone could help guide me in the right direction and/or provide pseudo code that can help. It would be greatly appreciated. Specifically i'm interested in how to loop for header, then read the payload back into an array and constructing the payload header.
Thanks!
payload_with_header = CustomProtocolModule.constructMethod(a)
You could serialize with
payload = Marshal.dump(a)
Then you can use
[payload.length].pack('l>') # to create a big endian signed long integer size for the packet
On the other side you can read an integer from the socket, then read the binary and deserialize with
array= Marshal.load(read_binary)
This will work for almost every data structure. Proc instances are an exception.
Ruby also supports remote objects and procedure calls so you can have interprocess communication, even between different ruby implementations (JRuby and MRI for instance)
I'm working on a c program in linux. I need to use client server programming. I used read and write and it worked fine. But after using more than 20 read and write in both server and client, it has stopped working. That is I don't receive any output for that. Line. I don't understand what is the problem because am using the very same lines.
bzero(&hl,200);
read(a,hl,50*sizeof(char));
printf("%s",hl);
In client side,
bzero(&hl,200);
strcpy(hl,"hello");
write(a,hl,50*sizeof(char));
printf("%s",hl);
Also, am not able to get the return value and print it. While I used it in debian, I got the return value and able to print. Now, am in Ubuntu (at home). It's not printing return value now. No error too! Is it anything to do with OS?
Please help me figure out the problem.
UPDATED:
In server,
int c:
s=read(a,&c,sizeof(int));
printf("choice: %d",c);
In client,
scanf("%d",&ch);
s=write(sd,&ch,sizeof(int));
Both has size 4. But, in client I got garbage value while I print the choice.
You throw away the return value of read, so you have no idea how many bytes you've read. What if it's less than 50?
Change:
read(a,hl,50*sizeof(char));
To:
int readBytes = 0;
do
{
int r = read(a, hl + readBytes, 50 - readBytes);
if (r <= 0)
return; // or however you want to handle an error
readBytes += r;
} while (readBytes < 50);
That will ensure you actually read 50 bytes.
You are imagining that TCP somehow "glues" those 50 bytes together. But the system has no idea that those 50 bytes are a message -- only your code does. So it's your code's job to glue them back together. TCP does not preserve application message boundaries -- that is the application's job.
I am looking to send a large message > 1 MB through the windows sockets send api. Is there a efficient way to do this, I do not want to loop and then send the data in chunks. I have read somewhere that you can increase the socket buffer size and that could help. Could anyone please elaborate on this. Any help is appreciated
You should, and in fact must loop to send the data in chunks.
As explained in Beej's networking guide:
"send() returns the number of bytes actually sent out—this might be less than the number you told it to send! See, sometimes you tell it to send a whole gob of data and it just can't handle it. It'll fire off as much of the data as it can, and trust you to send the rest later."
This implies that even if you set the packet size to 1MB, the send() function may not send all of it, and you are forced to loop until the total number of bytes sent by your calls to send() total the number of bytes you are trying to send. In fact, the greater the size of the packet, the more likely it is that send() will not send it all.
Aside from all that, you don't want to send 1MB packets because if they get lost, you will have to transmit the entire 1MB packet again, whereas if you lost a 1K packet, retransmitting it is not a big deal.
In summary, you will have to loop your send() calls, and the receiver will even have to loop their recv() calls too. You will likely need to prepend a small header to each packet to tell the receiver how many bytes are being sent so the receiver can loop the appropriate number of times.
I suggest you take a look at Beej's network guide for more detailed info about send() and recv() and how to deal with this problem. It can be found at http://beej.us/guide/bgnet/output/print/bgnet_USLetter.pdf
Why don't you want to send it in chunks?
That's the way to do it in 99% of the cases.
What makes you think that sending in chunks is inefficient? The OS is likely to chunk large "send" calls anyway, and may coalesce small ones.
Likewise on the receiving side the client should be looping anyway as there's no guarantee of getting all the data in one go.
The windows sockets subsystem is not oblidged to send the whole buffer you provide anyway. You can't force it since some network level protocols have an upper limit for the packet size.
As a practical matter, you can actually allocate a large buffer and send in one call using Winsock. If you are not messing with socket buffer sizes, the buffer will generally be copied into kernel mode for sending anyway.
There is a theoretical possibility that it will return without sending everything, however, so you really should loop for correctness. The chunks you send should, however, be large (64k or the ballpark) to avoid repeated kernel transitions.
If you want to do a loop after all, you can use this C++ code:
#define DEFAULT_BUFLEN 1452
int SendStr(const SOCKET &ConnectSocket, const std::string &str, int strlen){
char sndbuf[DEFAULT_BUFLEN];
int sndbuflen = DEFAULT_BUFLEN;
int iResult;
int count = 0;
int len;
while(count < strlen){
len = min(strlen-count, sndbuflen);
//void * memcpy ( void * destination, const void * source, size_t num );
memcpy(sndbuf,str.data()+count,len);
// Send a buffer
iResult = send(ConnectSocket, sndbuf, len, 0);
// iResult: Bytes sent
if (iResult == SOCKET_ERROR){
throw WSAGetLastError();
}
else{
if(iResult > 0){
count+=iResult;
}
else{
break;
}
}
}
return count;
}