• Announcements

    • khawk

      Download the Game Design and Indie Game Marketing Freebook   07/19/17

      GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
Sign in to follow this  
Followers 0
Mitchell314

[solved] Calling recv() in a loop

4 posts in this topic

When reading a tcp socket for arbitrarily sized packets, is it safe to keep calling recv() until it returns a negative number? For simplicity's sake, I'm assuming no other error is raised, just that return value of 0 means connection closed, and -1 means there's no data left to be read at the time.

 

For example, would the following code properly read all of the socket's contents? The other end of the connection is sending data in the format of "<text> \n <text> \n <text> \n .... <text> \n"

/* Make believe string structure */
struct resizableString string;

int bufferSize = 100;
int socket = connectToOtherHost();

while (-1){
    char *pBuffer = calloc(bufferSize);
    int bytesRead = recv(socket, pBuffer, bufferSize, 0);

    if (bytesRead == 0) {
        printf("Client closed connection\n");

    } else if (bytesRead >0) {
        /* Appends fix-length buffer to a string */
        appendBufferToString(string, pBuffer, bufferSize);

    } else {
        /* Done reading */
        free(pBuffer);
        break;
    }
}
parsePacket(&string);
0

Share this post


Link to post
Share on other sites
First, if you loop more than once, then you will leak a pBuffer per iteration except for the last.

Second, a recv value of 0 or -1 may indicate the connection has been closed in some way.

Third, recv() will block if there is no data waiting in the receive buffer. And, if a client crashes out or somehow becomes "non-nicely" disconnected, that means recv() will block forever (or until the connection times out, which will typically take hours.)

To know whether recv() will block or not, use the select() call. Generally, a networked program will replace whatever the main loop top-level thing is with select(). If there is a delay to wait for simulating or rendering, for example, then that delay is done using select(). If everything just runs as fast as possible, call select() with a 0 timeout. When data is available to be read, call recv() once on that socket, into whatever buffer you're currently working on filling. You may need to call recv() more than once to fill the buffer you want. Also, you may receive the end of one buffer, and the beginning of the next buffer, in the same call to recv().
1

Share this post


Link to post
Share on other sites

Ah thanks. That code was made up for this thread for simplicity's sake, the actual code does use select() and handles the memory buffers. The strategy I'm using is to keep a linked list of buffers per connection, where each recv() reads data into a new buffer, and if any data is written it is added to the end of the linked list. The buffers are freed when the parser processes the list later. According to the man pages for recv(2):

 

 

All three routines return the length of the message on successful  completion.   If  a  message  is  too  long to fit in the supplied buffer, excess bytes may be discarded depending on the type of socket the message is received from.

 

 

But it doesn't say which. And since I've been having networking-related bugs, I want to make sure that I'm not accidentally dropping data while not being susceptible to buffer overflow bugs/exploits. Blocking isn't too much of an issue; the program is supposed to be a daemon anyways. The program is connecting to game server instances, which may stream small or large amounts of data, and connecting to admin tools, which stream short commands. However, there is no set packet size, so I want to know if I can play it safe by reading from a socket into a growing list of buffers until it is dry.

0

Share this post


Link to post
Share on other sites

But it doesn't say which. And since I've been having networking-related bugs, I want to make sure that I'm not accidentally dropping data while not being susceptible to buffer overflow bugs/exploits. Blocking isn't too much of an issue; the program is supposed to be a daemon anyways. The program is connecting to game server instances, which may stream small or large amounts of data, and connecting to admin tools, which stream short commands. However, there is no set packet size, so I want to know if I can play it safe by reading from a socket into a growing list of buffers until it is dry.

 

TCP (SOCK_STREAM) never drops data from the internal buffer, and will only give you what you request, leaving the rest available for subsequent calls to recv (I think internally it asks the remote host to send the data again if it can't keep up). So in that case you don't need to worry about losing bytes. What you do need to worry about is your stream getting fragmented, so you need to maintain some state during the connection, e.g. "ok so I've received 50 bytes of this 100-byte string, I still need 50 bytes..", because simply checking recv()'s return value as an indicator that a send() call on the remote host has been received is unreliable - TCP is stream-oriented, so it's possible that a remote host sends "hello" and then "test", and you, in your recv() loop, receive first "he", then "l", then "lote" and finally "st" (*this is a simplification, in reality this exact scenario does not really happen because packets have a minimum size before being fragmented, but it occurs all the time for longer streams). You cannot use recv()'s return value as an indicator that all data has made it to you, unless the remote host immediately closes afterwards (and even then I am not sure - someone will have to confirm this but I believe it's possible for the socket to close while data is still in transit to you, so you need some synchronization).

 

On the other hand UDP (SOCK_DGRAM) gives you no guarantees. The packet may have been discarded anywhere between source and destination, and that includes your system's internal buffer if it happens to run out of space. That's part of the deal, and it is a reality you will have to accept if you do UDP networking.

1

Share this post


Link to post
Share on other sites

Thanks, that clears up my question. The protocols I'm using are just based around arbitrarily-length string messages separated by delimiters; message size is not communicated by any process. I've been burnt quite badly in the past by assuming that TCP preserves packet boundaries, hence the rotating buffers. :P

 

I've just never seen anybody else do it that way.

0

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0