I have a threaded server, usually one thread per client, so whatever packets I receive will be from the same source.
I am designing a protocol based on
struct Packet
{
int Data;
char Data2 [size];
} Packet;
and any other permutations I may need.
The only way I can distinguish between packets so far is based on their size. Since both the server and the client have a the same struct declarations, sizeof(Packet) on the server will be the same as sizeof(Packet) (assuming identical hardware) on the client, and when I call
int bytesReceived = recv(...);
switch (bytesReceived) { (...) }
I can pass on the buffer to a packet-specific function to handle it.
This is imperfect at best, because
Datatype sizes may differ per platform --> a mismatch can occur between server and client
I may have two different packets of identical size.
What is a good workaround this problem? How can I design a protocol in a better way?
Datatype sizes may differ per platform --> a mismatch can occur between server and client
Use types from <stdint.h>, e.g. uint32_t. Also, make sure your maintain your protocol byte-order (little or big endian), so that if platform's byte order is different, you reverse the integers before sending and after receiving.
I may have two different packets of identical size.
Send packet length along with the packet type in your packet header. Something like:
+----------------+--------------+----------------------------+
| message-length | message-type | message-payload |
| 4 bytes | 2 bytes | (message-length - 6) bytes |
+----------------+--------------+----------------------------+
Related
I'm trying to do a multiplayer game in c, but when I send multiple package like "ARV 2\n\0" and "POS 2 0 0\n\0" from the server to the client (with send()), when I try to read them with recv(), he only found 1 package that appear to be the 2 package in 1..
So I'm asking, is that normal ? And if yes, how could I force my client to read 1 by 1 the packages ? (or my server to send them 1 by 1 if the problem come from the call send)
Thanks !
Short answer: Yes, this is normal. You are using TCP/IP, I assume. It is a byte stream protocol, there are no "packets". Network and OS on either end may combine and split the data you send in any way that fits in some buffers, or parts of network. Only thing guaranteed is, that you get the same bytes in same order.
You need to use your own packet framing. For text protocol, separate packets with, for example, '\0' bytes or newlines. Also note that network or OS may give you partial packets per single "read", so you need to handle that in your code as well. This is easiest if packet separator is single byte.
Especially for a binary protocol where there are no "unused" byte values to mark packet boundaries, you could write length of packet as binary data, then that many data bytes, then again length, data, and so on. Note that the data stream may get split to different "read" calls even in the middle of the length info as well (unless length is single byte), so you may need a few lines more of code to handle receiving split packets.
Another option would be to use UDP protocol, which indeed sends packets. But UDP packets may get lost or delivered in wrong order (and have a few other problems), so you need to handle that somehow, and this often results in you re-inventing TCP, poorly. So unless you notice TCP/IP just won't cut it, stick with that.
I'm trying to count total send bytes from my program, but I can't get accurate value.
All my functions call a single function that send data to my server using send() function.
In this function, i get return of send() and sum into global counter. This is working fine.
But when I compare to 'iftop' utility (sudo iftop -f 'port 33755'), I'm getting more data on iftop then in my app....and my guess if because of tcp headers/protocol data. I really don't know how to calculate this. I'm sending packets using send() and variable data length, so I'm not sure if is possible to detect/calculate TCP packet size from there. I know that each TCP packet send TCP header, but I'm not sure how many packets is sent.
May I assume that every call to send(), if data length is less than 1518 (TCP packet size limite?), than it's only one TCP packet and I need to sum TCP Header length? Even if I sent one byte? If so, how much is these extra-bytes from TCP structure?!
For information: I'm using GCC on linux as compiler.
Tks!
How to count bytes using send() in C, including protocol size?
There is no reliable way to do so from within your program. You can compute a minimum total number of bytes required to transmit data of the total payload size you count, subject to a few assumptions, but you would need to monitor from the kernel side to determine the exact number of bytes.
May I assume that every call to send(), if data length is less than
1518 (TCP packet size limite?), than it's only one TCP packet and I
need to sum TCP Header length?
No, that would not be a safe assumption. The main problem is that the kernel does not necessarily match the data transferred by each send() call to its own sequence of packets. It may combine data from multiple send()s into a smaller number of packets. Additionally, however, it may use either a smaller MTU or a larger one than Ethernet's default of 1500 bytes, depending on various factors, and, furthermore, you need to fit packet headers into the chosen MTU, so the payload carried by one packet is smaller than that.
I suspect you're making this too hard. If this is a task that has been assigned to you -- a homework problem, for example -- then my first guess would be that it is intended that you count only the total payload size, not the protocol overhead. Alternatively, if you do need to account for the overhead, then my guess would be that you are supposed to estimate, based on measured or assumed characteristics of the network. If you've set this problem for yourself, then I can only say that people generally make one of the two computations I just described, not the one you asked about.
I came across this snippet of code which appeared in the guts of setting up a socket:
#define PORT xxxx
struct sockaddr_in self;
self.sin_family = PF_INET;
self.sin_port = htons(PORT);
I understand that we need to convert byte order of the data that we are transmitting over a network to Network Byte Order but I don't get why we need to convert port number to that as well when setting up a socket. I mean, when we do bind, isn't it a "local" thing? Say the port we intend to be bound is 1 and the machine actually uses little endian; now since we converted it into Network Byte Order, wouldn't we be binding a totally different port to the socket?
I think let's assume you are using TCP. The port number is going to be in the packet header. That is going to be transmitted. So it will be in Network Byte Order.
Are you asking why you the application programmer does it instead of the library doing it internally? If so, the only technical advantage I can think of is that it allows the application to do the conversion once and cache it and use it many times without requiring many conversions.
On TCP you only need to use it once per connection and typically won't make millions of connections. But on UDP you use it every time you send a packet, and it's reasonable to assume you'd make millions or billions of such calls.
Then, for myriad calls to say sendto() for UDP, or what have you, the re-ordered-if-necessary address is supplied to the OS which can copy it as-is directly into outgoing network packets.
The alternative of doing it in the kernel would require every call to sendto() to take what the app knows as the same address over and over, and reconvert it every time.
Since sendto() benefits from this, that was perhaps sufficient reason for them to have the rest of the API work the same way.
You transmit the port number over the network. It is a part of the IP packet for TCP. Look up the RFC (ietf.org/rfc/rfc793.txt)
The struct sockaddr_in is just a wrapper structure for struct sockaddr:
struct sockaddr {
unsigned short sa_family;
char sa_data[14];
};
The Port number and Ip-address are held together here. They are held together in sa_data[14]- the first 2 bytes holding the port number, and the next 4 bytes holding the ip-address. The remaining 8 bytes are unused. These are the 8 bytes you clear to zeroes via sin_zero[8] when you use sockaddr_in.
This in entirety is sent via network, including the port number in network order.
Machines can use different encodings little/big endian. To standardize that you should use a uniform encoding when communicating through the network. That's why you have to convert the encoding to Network Byte Order regardless of it being little/big endian, what matters is that it is uniform and it is understood correctly by every device and software in the network.
I'm writing a C/C++ client-server program under Linux. Assume a message m is to be sent from the client to the server.
Is it possible for the client to read the TCP sequence number of the packet which will carry m, before sending m?
In fact, I'd like to append this sequence number to m, and send the resulting packet. (Well, things are more complicated, but let's keep it that simple. In fact, I'd like to apply authentication info to this sequence number, and then append it to m.)
Moreover,
is it possible for the server to read the TCP sequence number of the packet carrying m?
You can do something very nearly equivalent to this. You can count all the bytes you send and put a count of all the bytes sent before the message at the end of your message.
I get really nervous anytime anybody talks about 'packets' with TCP. Because if you talk about packets and TCP at the same time you are mixing protocol levels that shouldn't be mixed. There is no meaningful correspondence between data you send in TCP and the packets that are sent via IP.
Yes, there are sequence numbers in IP packets used to send TCP information. These sequence numbers are a count of the number of bytes (aka octets) sent so far. They identify where in the stream the bytes in the packet belong, but they are otherwise unrelated to the packet.
If a resend happens, or if you're using the Nagle algorithm, or if the TCP stack feels like it that day, you may end up with two send operations ending up in the same packet. Or, you might end up with half of one send operation ending up in one packet, and half in another packet. And each of those packets will have their own sequence numbers.
As I said, there is absolutely no meaningful relationship between send operations you perform at the transport layer and the packets sent at the network layer. I'm not talking theoretically either. It's not 'really all packets underneath and the send generally, barring some weird condition, puts all the bytes in a single packet'. No, the scenarios I outlined above where the bytes from a single send operation are spread to multiple packets happen frequently and under unpredictable conditions.
So, I don't know why you want to know anything about the sequence numbers in packets. But if you were using the sequence number as a proxy for number of bytes sent, you can keep that count yourself and just stuff it into the stream yourself. And remember to count those bytes too.
no, you can't do that -- at least not with expected result
This is because:
TCP is stream based, not packet based.
TCP sequence number is in byte, not packet.
Underlying TCP layer do the segmentation for you.
TCP window size / packet size are dynamic
These means you might send a "packet" with the sequence number at the end of "packet". It turns out, the underlying magics re-segment your packet.
What you want:
1 2 3 4
+---+---+---+---+
| A | B | C |"1"| packet 1, seq=1, len=4
+---+---+---+---+
5 6 7 8
+---+---+---+---+
| A | B | C |"5"| packet 2, seq=5, len=4
+---+---+---+---+
What you might get:
1 2 3 4
+---+---+---+---+
| A | B | C |"1"| packet 1 (seq=1, len=4)
+---+---+---+---+
(packet 1 got lost)
1 2 3 4 5 6
+---+---+---+---+---+---+
| A | B | C |"1"| A | B | packet 1, resent, seq=1, len=6
+---+---+---+---+---+---+
7 8
+---+---+
| C |"5"| packet 2, seq=7, len=2
+---+---+
TCP/IP stack does all the things for you. You receive only payload. Stack removes all the headers and provides payload at user space.
If you really want to add or modify at packet header level, try out RAW sockets. RAW sockets receives/sends packet directly from Network card irrespective of transport type (TCP or UDP). In this case you have to strip/add all the headers (TCP/UDP Header, IP Header and Ethernet Header) with your payload.
Checkout a very good video tutorial on RAW Sockets
which is the beast approach to send packets that can be of different size using TCP sockets in C?
I wonder because we're trying to write a multiplayer games that needs a protocol which has many kinds of packets of different sizes.. according to recv documentation I can get how many bytes have been read but how should I manage to dispatch packets only when they are exaclty full?
Suppose that I have packets with a 5 bytes header that contains also the length of the payload.. should I use circular buffers or something like that to dispatch packets when ready and keep new partials?
Create a static variable which represents the packet header, this variable will be five bytes long. Create an associated integer which counts how many of those five bytes have yet been read. Create a second integer which counts how many bytes of the "content" have been read. Zero both those integers. Create an associated char * pointer which eventually will point to the received packet content.
As data arrives (e.g., select indicates so), read the five bytes of header. You may receive these bytes gradually, thus you need the first integer count variable. Account for the header bytes you have received here.
When you are done receiving the header, sanity check it. Are the size values possible to satisfy (e.g. not greater than 2^30)? If so, malloc a buffer of that size or that size plus the header. (If you want the header contiguous, allocate sufficient space, then memcpy it into your new buffer.)
Now, as data arrives, place it in your allocated buffer. Account for the received bytes in the second integer you created. When you have received all the bytes the header called for, then repeat all the above.
you can design a custom header for your packet transmission, which specifies packet length, indexing info (if packet fragmentation is implemented) and some hashing if you need.
some rough pseudocode as follows :
recv(socket, headerBuf, headerSize, MSG_WAITALL);
nPacketSize = headerBuf[16]; //sample
nByteRead = 0;
while (nByteRead != nPacketSize)
{
nByteToRead = nPacketSize - nByteRead;
nCurRead = recv(socket, someBuf, nByteToRead, MSG_PARTIAL);
nByteRead += nCurRead;
Sleep(0); // Yield processor
}
TCP is a stream based protocol, not a datagram one. That means that there isn't necessarily a one to one correspondence between the number and size of buffers passed to send and what comes out of receive. That means that you need to implement your own "protocol" on top of TCP.
Examples of such protocols include HTTP, where HTTP messages are delineated by two consecutive carriage return, line feed pairs. \r\n\r\n. The only concern with such delineation is to make sure that the pattern can't occur in the body of the message, either that or to make sure it is escaped. Other protocols create a header which contains the information necessary to correctly identify and read the next piece of information. I can't think of an application that does this off the top of my head. You could even go for a hybrid approach that combines the two.