Thread: When recv() can't

  1. #1
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709

    When recv() can't

    Just a quick question about recv() - sorry, I swear I found it on google earlier but I can't remember exactly what the search string was.

    Since you can't (afaik) know the length of the data to be received from the server I was going to use an STL vector so I can push_back() single bytes as I read them, but I don't know what recv() returns (if at all) when there's nothing left to return from the server so I can break the loop I plan to use.

    Tips?
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

  2. #2
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    That depends on weather you're using blocking or non-blocking sockets. If you're using blocking sockets then recv won't return untill there is some data, the connection is closed or there was an error. If it's non-blocking recv will return SOCKET_ERROR and a call to WSAGetLastError will return WASWOULDBLOCK

  3. #3
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709
    I'm using blocking sockets, so what could I do?
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    You can use the ioctlsocket function with the FIONREAD argument to get the amount of data waiting to be received and only call recv if their is some data waiting. This isn't the amount of data the server is sending it's how much has been received so far.

  5. #5
    Supermassive black hole cboard_member's Avatar
    Join Date
    Jul 2005
    Posts
    1,709
    Could somebody have a loot at this (a tad long ~140 lines). As far as I can tell the use of ioctlsocket as a counter is making the receival lag behind... or something.

    Code:
    #include "stdafx.h"
    using namespace std;
    
    #pragma warning (disable :4267)         // conversion from 'size_t' to 'unsigned int', possible loss of data
    
    // contains connection information to be used elsewhere
    // after server_connect() call
    typedef struct {
            LPHOSTENT       host_info;
            SOCKADDR_IN     serv_info;
            SOCKET          sock;
    
    } serv_host_t;
    
    
    // server_connect
    //
    // returns: 0 on error, filled out serv_host_t otherwise
    serv_host_t *server_connect (char *name)
    {
            WORD            sock_ver;
            WSADATA         wsa_data;
            int             ret;
            LPHOSTENT       host;
            SOCKET          sock;
            SOCKADDR_IN     server_info;
            serv_host_t     *sh_info = new serv_host_t;
    
            sock_ver = MAKEWORD (1, 1);
            WSAStartup (sock_ver, &wsa_data);
            host = gethostbyname (name);
            if (! host) {
                    char    err[128];
    
                    memset (err, 0, 128);
                    sprintf (err, "Could not resolve host name '%s'\n", name);
                    cout << "\nERROR: " << err << "\n";
    
                    WSACleanup ();
                    return 0;
            }
    
            cout << "Connecting to " << name << "...\n";
    
            sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
            if (sock == INVALID_SOCKET) {
                    cout << "\nERROR: Could not create socket\n";
                    WSACleanup ();
                    return 0;
            }
    
            cout << "Created socket...\n";
    
            server_info.sin_family = AF_INET;
            server_info.sin_addr = *((LPIN_ADDR) *host->h_addr_list);
            server_info.sin_port = htons (21);
    
            ret = connect (sock, (LPSOCKADDR) &server_info, sizeof (sockaddr));
            if (ret == SOCKET_ERROR) {
                    cout << "\nERROR: Could not connect to host\n";
                    WSACleanup ();
                    return 0;
            }
    
            cout << "Connection complete.\n";
    
            sh_info->host_info = host;
            sh_info->serv_info = server_info;
            sh_info->sock = sock;
            return sh_info;
    }
    
    // server_send
    //      Send data to the server
    //
    // returns: 0 if successfull, 1 otherwise
    int server_send (char *data, SOCKET sock)
    {
            unsigned        len = 0;
            int             ret;
            char            *c = data;
    
            if (sock == INVALID_SOCKET) {
                    cout << "\nERROR: Invalid socket passed to server_send()\n";
                    return 1;
            }
    
            //cout << "Sending data...\n    >> " << data << "\n";
    
            // append \r\n\r\n
            c += strlen (data);
            *c++ = '\r';
            *c++ = '\n';
            *c++ = '\r';
            *c++ = '\n';
    
            len = strlen (data);
            ret = send (sock, data, len, 0);
            if (ret == SOCKET_ERROR) {
                    ret = WSAGetLastError ();
                    cout << "\nERROR: Unabled to send data to server [" << ret << "]\n";
                    return 1;
            }
    
            cout << "Sent.\n";
            return 0;
    }
    
    // server_recv
    //      Receive data from the server
    //
    // returns: the data received
    char *server_recv (SOCKET sock)
    {
            unsigned long   len = 0;
            unsigned        i = 0;
            vector<char>    v;
            char            ch = 0;
            int             ret;
            char            *buffer = 0;
    
            ioctlsocket (sock, FIONREAD, &len);
    
            for (; i < len; i++) {
                    ret = recv (sock, &ch, 1, 0);
    
                    if (ret == SOCKET_ERROR) {
                            ret = WSAGetLastError ();
                            cout << "\nERROR: Socket error [" << ret << "]\n";
                            return 0;
                    } else if (ret == 0) {
                            cout << "\nERROR: Connection 'gracefully closed'\n";
                            return 0;
                    }
    
                    v.push_back (ch);
            }
    
            v.push_back ('\0');
            buffer = new char[v.size ()];
    
            for (i = 0; i < v.size (); i++) buffer[i] = v[i];
            return buffer;
    }
    
    int main (int argc, char *argv[])
    {
            serv_host_t     *sh_info = 0;
            char            *serv_name = new char[256];
            char            *command = new char[64];
            int             ret;
            char            *received = 0;
    
            memset (serv_name, 0, 256);
            memset (command, 0, 64);
    
            cout << "Basic FTP Client\n(C) Lee Thomas\n\n";
            cout << "server name\n ] ";
            cin.get (serv_name, 256);
    
            sh_info = server_connect (serv_name);
            cout << "\n";
    
            sprintf (command, "USER ahlukalt");
            server_send (command, sh_info->sock);
            received = server_recv (sh_info->sock);
            cout << received << "\n";
    
            closesocket (sh_info->sock);
            WSACleanup ();
            return 0;
    }
    Good class architecture is not like a Swiss Army Knife; it should be more like a well balanced throwing knife.

    - Mike McShaffry

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    When you say lag behind I'm assuming you mean you don't get all the data. Thats likely because ioctlsocket returns the amount of data that is available when it is called, by the time that data is recieved there could be some more waiting. The next time you call ioctlsocket it will report the next lot of data.

    What you need to do is keep recieving data untill you reach a deliminator (\r\n or whatever it is) and then deal with that line (display it, take action, etc)
    the program logic would be like this
    Code:
    while(connected)
    {
       getuserinput
       checkfordata
       if you have a complete line display it, take some action
    }
    you are probably safe assuming that no line will be longer then a given length say 1024 bytes so you could just store bytes in a buffer untill you get a complete line then deal with it.
    Last edited by Quantum1024; 02-09-2006 at 01:30 PM.

  7. #7
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    I send a 'packet', a self defined structure.

    The packet contains the size of the following/attached data and details for processing it ie type of data.

    Can send an int first and then keep recv() until you get that much data.

    ie
    recv() int (4 bytes) == size
    alloc buffer
    recv() size
    process
    free buffer
    recv() int (4 bytes) == size

    ect
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. recv() returns 0 the second time
    By Overlord in forum Networking/Device Communication
    Replies: 7
    Last Post: 07-10-2009, 04:09 AM
  2. Question about recv
    By carrotcake1029 in forum Networking/Device Communication
    Replies: 2
    Last Post: 02-26-2009, 02:10 PM
  3. recv()
    By afisher in forum Networking/Device Communication
    Replies: 3
    Last Post: 03-24-2004, 05:32 PM
  4. recv() problem
    By Massive in forum C Programming
    Replies: 5
    Last Post: 06-26-2003, 04:58 AM
  5. non blocking recv
    By rohit in forum Linux Programming
    Replies: 4
    Last Post: 03-05-2002, 09:35 PM