Jump to content

  • Log In with Google      Sign In   
  • Create Account


Member Since 03 Jun 2003
Offline Last Active Yesterday, 08:02 PM

#5289897 sending and receiving struct using eNet and boost.serialization

Posted by hplus0603 on 03 May 2016 - 10:58 AM

I think you really need to step up your debugging here and dive in.
First: What is the text/message of the exception?
Second: Set a breakpoint at the beginning of your closure. Figure out what it's doing when it's serializing, and why it decides to throw.
Third: I have no idea what "g" is because you're not showing that. Is it a reference to some local variable in the outer scope? If so, has that outer function already returned?

#5289780 sending and receiving struct using eNet and boost.serialization

Posted by hplus0603 on 02 May 2016 - 03:19 PM

You can serialize like that, with two changes:

1) You need to write the length of the array first

2) calling strlen() for each comparison in that loop will be unnecessarily inefficient

#5289742 sending and receiving struct using eNet and boost.serialization

Posted by hplus0603 on 02 May 2016 - 08:54 AM

Compile your code with -O0 and -ggdb, and then set a breakpoint before the crashing line, and step through it.

std::string is safe, even though it uses pointers internally, because boost::serialization has a specialization for std::string (and most of the other STL containers.)

Did you look at the binary object and array support functions I recommended? Do you understand how they work and why they're needed? If not, you probably need to read up a bit on how C++ and pointers work in general before you'll be successful doing networking and other systems programming.

#5289595 router programming

Posted by hplus0603 on 01 May 2016 - 11:39 AM

You can open each network interface in the SOCK_RAW mode, which will give you raw network interface data.
You can also just do open() on each of the network interfaces (open("/dev/eth0") and whatnot)
Make sure that Linux does not care about those interfaces -- from Linux's point of view, those interfaces should be closed/down/unconfigured!
Because you will now be doing the job of ARP and ICMP and IP and UDP and TCP and the "route" command and the DHCP client and all the rest.
There are also various intermediate solutions. You might want to check out the results of "linux user space networking."

#5289594 sending and receiving struct using eNet and boost.serialization

Posted by hplus0603 on 01 May 2016 - 11:34 AM

why boost.serialization doesn't serialize pointers?

Because the value of the pointer makes no sense outside your process, and boost::serialization can't know how many elements to serialize if it were to serialize the pointed-at data.

To do that, you have to tell it what to do. Look at:
boost::serialization::binary_object(void * t, size_t size);

template <T> boost::serialization::make_array(T* t, std::size_t size);

#5289439 sending and receiving struct using eNet and boost.serialization

Posted by hplus0603 on 30 April 2016 - 11:33 AM

You can't serialize raw pointers. How would Boost know how long each pointed-to array is?
Use std::string if you want to use boost::serialization for strings.

#5289374 Does server's location affect players' ping?

Posted by hplus0603 on 29 April 2016 - 10:04 PM

Satellite "broadband" is still in use in some parts of the US, with 1600 ms downstream ping, and 56kbps modem upstream and a few hundred ms ping (depending on packet size.)
It is becoming less common, but the US is a large country and some areas are quite sparsely populated. Satellite internet is better than no internet in those locations ...

#5289310 Does server's location affect players' ping?

Posted by hplus0603 on 29 April 2016 - 02:06 PM

To answer the original question:

Yes, if you're hosting a highly latency-sensitive game worldwide, you should prepare for at least five server zones. In typical order of introduction for a US-based product:
- North America. (Pros put one one each coast)
- Europe
- East Asia
- Australia
- South America

If you're based somewhere else, you'll typically use the same list, except put your own home zone at the top of the list :-)

For example, Brazil is a highly-online market, that currently doesn't monetize very well, but a "hit" in that country can be very profitable.
Their data center infrastructure is not as mature, though. You might want to look to places like Uruguay or Argentina, if you decide to do something for that continent.

East Asia could be many countries such as South Korea, Japan, Philippines, could even India -- depending on your specific requirements and market contacts.
Don't attempt to go into China unless you have a native partner that you trust, and that preferably is connected in the government half of the country.

#5289308 Does server's location affect players' ping?

Posted by hplus0603 on 29 April 2016 - 02:00 PM

the speed of light is roughly 300.000 km/s

The speed of electricity in copper is actually more like 150,000 km/s.
(Plus the latency of routers, which is often not insignificant.)

A lot of current backbone infrastructure does in fact use lasers, because it uses fiber optics.
The speed of lasers in fiber optics is more like 200,000 km/s.

This concludes our approximate-trivia-Friday event :-)

#5289156 Network Library that supporst RPCs

Posted by hplus0603 on 28 April 2016 - 04:45 PM

you have to build up your whole message in a temporary buffer first, then measure its length immediately before sending

You want to do that anyway, because you don't want to call send() multiple times for as single packet, because system calls have a cost.
Just leave a few bytes empty at the beginning of your buffer, and after you know the size, pre-fill that at the head of the buffer, then call send() on the entire thing.

I still have to work with a buffer

Yes; any TCP receiver has to call recv() into the end of whatever buffer it keeps around, and then try to decode as many whole packets as possible out of that buffer, and then move whatever is left to the beginning of the buffer.
(Cyclic buffers are sometimes convenient for this.)

how do I know which bytes belong to which parameters?

Decode each argument in order. You presumably know the type of each argument.
The simplest method: If the type is an int, it's 4 bytes. If the type is a double, it's 8 bytes. If the type's a string, then make the rule that strings are less than 256 bytes long, and send a length byte, followed by that many bytes.
When you have decoded the correct number of arguments, you know that the next part of your message follows.
If you support variable number of arguments, first encode the number of arguments to decode, using another byte.

Less simple methods will decode integers as some kind of var-int, floats using some kind of quantization (based on what the particular value is,) strings using a dictionary that gets built up over the connection, etc.

#5289110 Calculating Packet Loss

Posted by hplus0603 on 28 April 2016 - 11:12 AM

The main question is whether you'd want to get an estimate of packet loss even when zero packets have currently made it through.
If so, then the easiest way is to have a counter that you increment every time a packet is received, and read-and-clear this counter every 3 seconds.
Then divide out by the number of packets you expected to receive in 3 seconds; that's your effective throughput rate.
The two main problems with this scheme are:
- You have to have a consistent packet rate. This is often not a problem, expecially for action games.
- You may end up with two windows where one receives 31 packets and one receives 29 packets, an you expect 30 per window. Using a "bank" for overage from the last frame can help with this.

If you're OK to update your estimate only when you receive a packet, you can do this:

unsigned char lastSeq;

int packetLossPercent(unsigned char newSeq) {
  if (newSeq == lastSeq || (unsigned char)(newSeq - lastSeq) >= 128) {
    // out-of-order packet
    return 0;
  unsigned char ret = 100 - 100 / (newSeq - lastSeq);
  lastSeq = newSeq;
  return ret;
Call this for each packet you receive, and set the estimate to the value returned.
You may also want to add something that says "if it's been more than 2 seconds since I got a packet, assume 100% loss."

#5289109 Network Library that supporst RPCs

Posted by hplus0603 on 28 April 2016 - 11:06 AM

A problem with this is of course, that the message itself must not contain this delimiter

Which is why most game protocols use the size-first approach. Also, for efficiency, they typically marshal data as binary, rather than as text.

For formats that have to be textual by convention or definition (email, JSON, etc) the two options are to either encode your payload as text using something like base64 encoding, or introducing a quoting mechanism.
For example, URLs use a quoting mechanism where "%xx" will replace a URL-reserved character (slash, ampersand, equals, percent, space, etc) with its hexadecimal equivalent.
You could do this as well -- whenever you see a '<' or a ':' or a '%' in the payload, insert the appropriate %xx code. Then, in the protocol decoder, when you see a %, read the next two characters and decode. When you see a '<' or a ':' you know that it's part of the protocol.

All that being said -- I think the way you're doing this is not optimal, and the netcode that you're working on will never be "great" except possibly for slow, turn-based games like chess or whatever.
If that's OK by you, then you should keep going. If you want "great" netcode for games with significant data volume or significant latency requirements, you need to take the advice in this thread about using binary marshaling and reducing the size of data that you need to send.
But, not everything needs to be "great," because "good enough and shipping" beats "great and not shipping" :-)

#5288975 Network Library that supporst RPCs

Posted by hplus0603 on 27 April 2016 - 01:51 PM

there always has to be transferred something over the network

True, but your job is to minimize what that is.
For example, giving each method a small integer instead of a string name, would reduce the size needed in the network packet.
Similarly, building a wrapper that introspects the server code, and generates a class that exposes exactly the methods that the server exports, and then marshals the arguments using known-types (only the data) will save a lot of space over marshaling arguments with type information like default .NET Serialization does.
You should aim for the overhead of a method invocation to be a few bytes (say, five at most,) and for each argument in an invocation to only need the size of the data (4 bytes for an int, num-chars bytes for a string, etc.)

#5288932 Network Library that supporst RPCs

Posted by hplus0603 on 27 April 2016 - 10:36 AM

I found RPCs are the easiest way to communicate.

RPC is convenient, but it does have known failure modes. If you synchronously block for an answer, for example, that's really bad from a performance point of view. If you assume that all function calls will succeed, that's another problem, as networks are unreliable. What does the RPC do when the client goes away?
Structuring game networking as a bidirectional stream of "fire and forget" updates is a LOT more robust than RPC.

I don't want to manually add every function to a list of methods

I don't want to manually have to lock my door when I leave the house, either, but I do it, because the cost is worth the benefit.

Note that, with default RPC function-and-arguments, a client can invoke any of the functions on your server with any argument at any time. For example, they can invoke "player X takes damage" at will, if there is such a function.
Sending a stream of messages and structuring your simulation to pay attention to (and validate) those messages, is, again, more robust and has less accidental-invocation surface area.

#5288157 How do I keep track of nearby objects?

Posted by hplus0603 on 22 April 2016 - 10:47 AM

I'm having a hard time figuring out which cells should be updated.

There are two ways to view this.
One is: An object should be in each cell that it can be visible from.
Another is: An object is in "its own" cell, and visibility queries cover many cells.

Implementation is easier for the second option.

Quad trees are great theoretically because of the ability to adjust dynamically to object load.
I find that hash grids work great in practice. They are like a fixed grid, but don't pay storage for empty cells.