HTTP GET winsock

Small HTTP client console app trying to understand GET requests.
It always connects every single time I get a reply
1
2
HTTP/1.1 200 OK
Date: Fri, 24 Sep 2021 17:25:52 GMT


But I only get the reply I'm expecting maybe 1 in 5 attemps

EXPECTED
1
2
3
4
5
6
7
8
9
10
11
12
13
HTTP/1.1 200 OK
Date: Fri, 24 Sep 2021 17:28:20 GMT
Cache-Control: no-cache, no-store, must-revalidate, private, max-age=0
Pragma: no-cache
Expires: 0
Last-Modified: Fri, 24 Sep 2021 17:28:20 GMT
Etag: "614e0ab4.1"
Content-Type: text/plain
Content-Length: 1
Connection: close
Accept-Ranges: bytes

0



Am I missing some sort of house keeping/clean up that's causing this?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#pragma comment (lib, "Ws2_32.lib")
#include <iostream>
#include <string.h>
#include <sstream>
#include <WinSock2.h>
#include <WS2tcpip.h>
//#include "stdafx.h"
using namespace std;


int main()
{
	WSAData wsaData;
	WORD DllVersion = MAKEWORD(2, 1);
	if (WSAStartup(DllVersion, &wsaData) != 0) {
		cout << "Winsock Connection Failed!" << endl;
		WSACleanup();
		exit(1);
	}

	//string getInput = "";
	SOCKADDR_IN addr;
	int addrLen = sizeof(addr);
	IN_ADDR ipvalue;
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	addr.sin_port = htons(8282);
	addr.sin_family = AF_INET;

	SOCKET connection = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (connect(connection, (SOCKADDR*)&addr, addrLen) == 0) {
		cout << "Connected!" << endl;
		
			string getInput = "GET /parameter/hd1/spk/volume%3f HTTP/1.1\r\nHost: 127.0.0.1:8282\r\nContent-Type: text/plain\r\n\r\n";
			send(connection, getInput.c_str(), strlen(getInput.c_str()), 0);
			cout << getInput << endl;
			int resp_leng;
#define BUFFERSIZE 1024
			char buffer[BUFFERSIZE];
			std::string response;
			response = "";
			resp_leng = BUFFERSIZE;
			while (resp_leng == BUFFERSIZE)
			{
				resp_leng = recv(connection, (char*)&buffer, BUFFERSIZE, 0);
				if (resp_leng > 0)
					response += std::string(buffer).substr(0, resp_leng);
			}
			closesocket(connection);
			cout << response << endl;
		getline(cin, getInput);
		WSACleanup();
		exit(0);
	}
	else {
		cout << "Error Connecting to Host" << endl;
		WSACleanup();
		exit(1);
	}
	return 0;
}
Last edited on
But I only get the reply I'm expecting maybe 1 in 5 attemps
What happens when you don't get the reply you expect?

I see you've not quite applied what I suggested in the past.

Also, you're not null terminating the buffer used to receive the reply.
Sometimes I get

1
2
HTTP/1.1 200 OK
Date: Fri, 24 Sep 2021 17:25:52 GMT


sometimes
1
2
3
4
5
6
7
8
9
10
11
HTTP/1.1 200 OK
Date: Fri, 24 Sep 2021 17:28:20 GMT
Cache-Control: no-cache, no-store, must-revalidate, private, max-age=0
Pragma: no-cache
Expires: 0
Last-Modified: Fri, 24 Sep 2021 17:28:20 GMT
Etag: "614e0ab4.1"
Content-Type: text/plain
Content-Length: 1
Connection: close
Accept-Ranges: bytes


last digit is the data I want [well I'd need content length too as my content could to 1-3 digits]

let me go back in threads see what I've missed from you
Last edited on
ah right

int nbytes = send(...)
ok added that not sure how it helps, but I'll trust you
you said also zero out addr

I couldn't figure what you meant

Also null terminating buffer,

buffer[resp_leng] = '\0'; something like that?
Last edited on
Picture / thousand words ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#pragma comment (lib, "Ws2_32.lib")

#include <WinSock2.h>
#include <WS2tcpip.h>

#include <iostream>
#include <string>

#include <string.h>

struct WsaStuff {
    WSAData wsaData;

    WsaStuff() {
        WORD DllVersion = MAKEWORD(2, 1);
        WSAStartup(DllVersion, &wsaData); // never seen this fail
    }
    ~WsaStuff() {
        WSACleanup();
    }
};

int main() {
    WsaStuff winsockStuff;
    int rc;
    int nbytes;

    SOCKADDR_IN addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");
    addr.sin_port = htons(8282);
    addr.sin_family = AF_INET;

    auto connection = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

    rc = connect(connection, (SOCKADDR*)&addr, sizeof(addr));
    if (rc != 0) {
        std::clog << "fatal: connect() failed" << std::endl;
    }

    std::string query = "GET /parameter/hd1/spk/volume%3f HTTP/1.1\r\nHost: 127.0.0.1\r\nContent-Type: text/plain\r\n\r\n";
    nbytes = send(connection, query.c_str(), query.size(), 0);
    if (nbytes != query.size()) {
        std::clog << "warning: send() not all data sent" << std::endl;
    }

    constexpr size_t BUFFERSIZE{1024};
    char buffer[BUFFERSIZE];
    nbytes = recv(connection, buffer, sizeof(buffer), 0);
    if (nbytes > 0) {
        buffer[nbytes] = 0;
        std::cout << buffer << std::endl;
    } else {
        std::clog << "fatal: recv() failed" << std::endl;
    }

    shutdown(SD_SEND);
    closesocket(connection);
}
I haven't tried to compile it, I don't have easy access to Windows.
Last edited on
Ah right memset addr to zero, now I get it.

Thanks for the code a few errors but I can work backwards
@kbw
1
2
3
    nbytes = recv(connection, buffer, sizeof(buffer), 0);
    if (nbytes > 0) {
        buffer[nbytes] = 0;

If recv fills the buffer completely, then the \0 is written out of bounds.

@lostdog
If you'd used the right string constructor, your code would have worked as is.
https://www.cplusplus.com/reference/string/string/string/
Namely
 
response += std::string(buffer,resp_length);

There's no need to keep memsetting buffer with zeros.


@salem c

thanks, I just didn't understand that recv() could return data in pieces.
It was pure luck that sometimes when I sent the request the server was ready.



thanks to all, solved
> thanks, I just didn't understand that recv() could return data in pieces.
You should also be aware that send() can also do the same thing.
send() returns the number of characters successfully sent. If that's less than you expected, then you need to call send() again with the remainder of the buffer, until all the data is sent (or the remote disconnects).
Topic archived. No new replies allowed.