简体   繁体   中英

How to make mutiple socket writes with one active socket connection to an express web server?

I am trying to do multiple write requests with one active socket connection to an express server running on localhost. I am making a http request to a express web server running on localhost. The message is sent like so:

GET /temp?sensorId=1&value=71 HTTP/1.1
Content-Type: text/html; charset=utf-8
Connection: keep-alive

I made sure to include "Connection: keep-alive" header in the message (though, it's not necessary since I am using HTTP/1.1).

Code for sending request

void sendRequest (char** message, int* socket_ref) {
int total = strlen(*message);
int bytes, sent = 0;
do {
    bytes = write(*socket_ref, *message + sent, total - sent);
    if (bytes < 0) {
        perror("ERROR writing message to socket yo");
        exit(EXIT_FAILURE);
    }
    if (bytes == 0) break;
    sent += bytes;
} while (sent < total);

   printf("Data sent. %d\n\n", sent);
}

Driver code

 char* dummy[80] = {"GET", "localhost", "3001", "/temp", "?sensorId=1&value=71"};
        setMessage(a, dummy);
        makeRequest(a);

        getResponse(&a);
        sleep(2);

        makeRequest(a);
        getResponse(&a);

I am expected to get two "71" on my express server end, but I am only receiving the first one. The first write request gives a successful response back, but the next one sends no response (http connection is kept alive).

The two write commands do return the expected number of bytes written.

The makeRequest(a) is a wrapper to call sendRequest() as shown above.
The getRequest(&a) is a wrapper to call read on the socket.

UPDATE The getResponse(&a) simply makes a call to the following code

#define RESPONSE_SIZE 4096
char* receiveResponse(int* socket_ref) {
char* response = malloc(RESPONSE_SIZE);
int total, bytes, received = 0;

memset(response, 0, RESPONSE_SIZE);
total = RESPONSE_SIZE - 1;
do {
    bytes = read(*socket_ref, response + received, total - received);
    if (bytes < 0) {
        perror("ERROR reading response from socket yo");
        exit(EXIT_FAILURE);
    }
    if (bytes == 0) break;
    received += bytes;
} while (received < total);
if (received == total) {
    perror("ERROR storing complete response from socket yo");
    exit(EXIT_FAILURE);
}
return response;

}

UPDATE 2 Having called getResponse(&a)after each makeRequest(a) call results in the following response:

Data sent. 125

Response:
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-d2PTd7kl/AFtn95E/ir6IzKjD9I"
Date: Thu, 03 Jan 2019 01:51:12 GMT
Connection: keep-alive

GOOD
Data sent. 125

Response:

However, if a getResponse(&a) is called after the two makeRequest(a) then both writes occur successfully, but I get the following for response:

Data sent. 125

Data sent. 125

Response:
HTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-d2PTd7kl/AFtn95E/ir6IzKjD9I"
Date: Thu, 03 Jan 2019 02:00:43 GMT
Connection: keep-alive

GOODHTTP/1.1 200 OK
X-Powered-By: Express
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Content-Length: 4
ETag: W/"4-d2PTd7kl/AFtn95E/ir6IzKjD9I"
Date: Thu, 03 Jan 2019 02:00:43 GMT
Connection: keep-alive

GOOD

I am trying to do multiple write requests with one active socket connection to an express server running on localhost.

Your receiveResponse() function is not suited for use with a persistent (aka keep-alive) connection. Consider this fragment:

 int total, bytes, received = 0; memset(response, 0, RESPONSE_SIZE); total = RESPONSE_SIZE - 1; do { bytes = read(*socket_ref, response + received, total - received); if (bytes < 0) { perror("ERROR reading response from socket yo"); exit(EXIT_FAILURE); } if (bytes == 0) break; received += bytes; } while (received < total); 

Under what conditions does the loop terminate? Well, it terminates

  • if the receive buffer fills.

  • if read() returns a negative number, signaling an error.

  • if read() returns 0, signaling end-of-file.

No other in-program condition causes the loop to terminate. Each of the first two possibilities triggers an error message and program termination, so if one of those were occurring then you would know (right?). Therefore, you must be seeing the last alternative ... or are you ?

What exactly does end-of-file mean for a socket? As with any other file, it means that no more data can (ever) be obtained from the socket -- for natural reasons, else you would get an error instead. For a socket specifically, that means the remote peer has closed the connection, or at least has shut down its output side of that connection. And that's exactly what does not happen with a persistent connection, at least not quickly. When it eventually does happen, if you wait that long, the connection is gone -- you need to establish a new one to receive another response.

So,

I am expected to get two "71" on my express server end, but I am only receiving the first one.

This is because the second request is not attempted until after the server closes the connection (the read loop blocks until then), at which point the second request cannot be delivered, or at minimum, no response to it can be received.

The first write request gives a successful response back, but the next one sends no response (http connection is kept alive).

The response to the first request is successfully received as expected. No response to the second is received because the second is not successfully delivered to the server, which is also consistent with what you see on the server side. I am at a loss to explain why the client does not emit an error message in this case, which is why I pressed you for more information, but it is certain that getResponse() will return successfully at most once for any given connection, and it is improbable that any further requests can successfully be sent over the connection after that.

You commented,

if I comment the first getResponse(&a) call both writes go in successfully. Now, the last response call returns a string where the two responses are concatenated.

That's perfectly natural. You're using a persistent connection, so the response to each successfully delivered request is readable from the same connection. In this case, you defer reading the data until after both requests have been sent, so the server responds to both.

To handle persistent connections, an HTTP client needs to be able to recognize message boundaries other than at EOF. The standard way to do this is by parsing the response headers as they come in, finding and parsing the content-length among them, and after reaching the response body, reading the number of bytes given by the content length.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM