Link to home
Start Free TrialLog in
Avatar of CSecurity
CSecurityFlag for Iran, Islamic Republic of

asked on

Socket recv doesn't receive anything

Hi

I have coded a socket client which sends some data to web server (apache and PHP).

It works fine if I don't use recv. If I don't wait for response of server and simply after sending all data close the socket, I see received data in PHP and it works properly. But now I need to check server's response, so I need to do recv.

I tried to set socket option with SO_RCVTIMEO also. I don't receive anything at all!

I can't receive anything from server. If I don't set SO_RCVTIMEO, my program waits on recv forever. If I set the SO_RCVTIMEO I get in numbytes = -1

Please advice! I'm sure PHP replies with some data AT LEAST HTTP header. How I can solve it?

Even if it's possible to solved using PHP code I would do it. I already added exit() call in PHP code, so I think it will close connection. But it doesn't work.


I tried Connection: Close and Connection: Keep-Alive, NONE worked.

Please advice
Avatar of Infinity08
Infinity08
Flag of Belgium image

Could you show the C++ client code ?
Could you also show the PHP code on the other end ?
Avatar of CSecurity

ASKER

if ((h=gethostbyname2(THESERVER.c_str())) == NULL) return FALSE;
if ((sock = socket2(AF_INET, SOCK_STREAM, 0)) == -1) return FALSE;
    int iVal=0;

    unsigned int  sz = sizeof(iVal);
      iVal = 6000;
      int ret = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&iVal, sz);

if (connect(sock, (struct sockaddr *)&their_addr,sizeof(struct sockaddr)) == -1) return FALSE;

send(sock, slast, 49, 0);

numbytes=recv(sock, bufrec, DATASIZE-1, 0);    <-- Here it hangs! If I set timeout, I get out of hang but without ANY data!

DATASIZE is also defined as 100
#define DATASIZE 100



After timeout I get -1 in numbytes. If I don't set timeout with setsockopt I wait for ever!



PHP part does nothing and works well if I don't do recv and directly close socket with closesocket(sock);

but if I hang on recv PHP won't work also. I should close socket with closesocket(sock); then PHP works and receives what I send.
I assume that socket2 is just an alias for socket.

SO_RCVTIMEO is not supported on all systems (only more recent systems support it), but I assume it is on yours.
Either way, if you use it on Linux, you need to pass a struct timeval as argument for setsockopt, not an int :

        struct timeval timeout = { 0 };
        timeout.tv_sec = 6;
        setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*) &timeout, sizeof(timeout));

If you use it on Windows, it is indeed an int parameter. And you can use it like you did.

Make sure that a 6 second timeout is sufficient (it should be, but depends on the connection between client and server, as well as the load on the server).

I assume their_addr is set correctly, since the connection succeeds. But in any case, here's an example of what you should have :

        struct addrinfo hints;
        memset(&hints, 0, sizeof(hints));
        hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_STREAM;

        struct addrinfo *their_addrinfo = 0;
        getaddrinfo(THESERVER.c_str(), "80", &hints, &their_addrinfo);

        int sock = socket(their_addrinfo->ai_family, their_addrinfo->ai_socktype, their_addrinfo->ai_protocol);

        connect(sock, their_addrinfo->ai_addr, their_addrinfo->ai_addrlen);

of course you'll need to add error handling everywhere.


Once the connection has succeeded, you can send and recv as the protocol dictates. For standard HTTP, you send the request, and receive the response. Then you usually end the connection (assuming keep-alive is not specified).

BUT, you need to specify the right sizes when you do. I assume you're sending 49 bytes because that is what you specified. Double-check that that is indeed the amount of data you send.
For recv, you don't know how much data you need to receive of course, so you specify a maximum. You specified 100. Make sure that the response is smaller than 100, or you won't receive everything.

Then we get to the error you experience. You say that recv returns -1. In that case, simply check what errno is set to to know what the exact error was that occurred.


>> PHP part does nothing and works well if I don't do recv and directly close socket with closesocket(sock);

Are you sure that the PHP part actually sends back a response ? You can use a network sniffer to see what is actually sent over the network. Use it on both ends to see which packets are sent/received on both ends. That will give you an accurate picture of what's happening.


You can also try your client code with another web server, like www.google.com eg. to see if it works as it should.
I fixed the problem, solution is:

shutdown(socket, SD_SEND);

It closes sender socket and then I got received some data using recv. That's all
This indicates that there's something else going on. It shouldn't be necessary to shut down all sending operations just to be able to receive something.

I would recommend you check everything I pointed out in my previous post, because right now you've just hidden the bug, rather than solved it.
All things you worried about was correct, like socket2 is socket, size of data is 49, 6 second is enough as I was testing it with local apache server, etc.

I think we need to flush socket to apache, so apache starts processing. Flushing and ending sent packet occurs when you close send socket. Nothing to worry, I think. What do you think?
ASKER CERTIFIED SOLUTION
Avatar of Infinity08
Infinity08
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Got it working... Don't worry! I also had another problem which was adding \r\n in end of HTTP request twice
>> I also had another problem which was adding \r\n in end of HTTP request twice

That's not another problem. That's probably one of the reasons you saw the behavior you did. An extra \r\n could mean that the size was wrong and/or that the receiving end is waiting for more data before continuing.

Even if your problem is solved now, I do recommend to use a network sniffer to double check that all packets sent over the network now are actually how you expect them to be.
I checked with sniffer which caused to find source of problems! Now everything works like a charm! :) Thanks
>> I checked with sniffer which caused to find source of problems! Now everything works like a charm! :)

Great :) A sniffer is a great tool ! It's almost always the first thing I use to verify/analyse network behavior/issues.