How to correctly response to HTTP request - c++

I am trying to create simple server which will repond to every HTTP request with 200 OK. I write code below, but when I called the server with Postman I ended with wrong result. If I do NOT call closesocket(clientSocket), Postman is waiting infinitely long for response with Sending requst.... I i do call closesocket(clientSocket), Postman shows Error: socket hang up.
What I have to do to correctly close connection?
void main()
{
std::cout << "Start..." << std::endl;;
int port = 54000;
// Initialize WinSock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
std::cout << "Can't start Winsock, Err #" << wsResult << std::endl;
return;
}
// Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "Can't create socket, Err #" << WSAGetLastError() << std::endl;
WSACleanup();
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(sock, (sockaddr*)&hint, sizeof(hint));
listen(sock, SOMAXCONN);
// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
// While loop: accept and echo message back to client
char buf[16384];
while (true)
{
SOCKET clientSocket = accept(sock, (sockaddr*)&client, &clientSize);
//print(client);
ZeroMemory(buf, 16384);
// Wait for client to send data
int bytesReceived = recv(clientSocket, buf, 16384, 0);
if (bytesReceived == SOCKET_ERROR)
{
std::cout << "Error in recv(). Quitting" << std::endl;
break;
}
const char* reply =
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Content-Length: 0\n"
"Keep - Alive: timeout=1, max=1\n"
"Accept-Ranges: bytes\n"
"Connection: close\n";
send(clientSocket, reply, strlen(reply), 0);
//closesocket(clientSocket);
} |
}
edit. Edited code. I corrected line endings, added better check for recv result and also I am checking number of sent bytes (and yes, all bytes are send). I also tried to add shutdown function, but result is still the same - infinite waiting or error. When I try to add do / while section, I will stuck in infinite waiting for another request. Do you have any other advice?
void main()
{
std::cout << "Start..." << std::endl;;
int port = 54000;
// Initialize WinSock
WSAData data;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &data);
if (wsResult != 0)
{
std::cout << "Can't start Winsock, Err #" << wsResult << std::endl;
return;
}
// Create socket
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock == INVALID_SOCKET)
{
std::cout << "Can't create socket, Err #" << WSAGetLastError() << std::endl;
WSACleanup();
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(port);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(sock, (sockaddr*)&hint, sizeof(hint));
listen(sock, SOMAXCONN);
// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
// While loop: accept and echo message back to client
char buf[16384];
while (true)
{
SOCKET clientSocket = accept(sock, (sockaddr*)&client, &clientSize);
//print(client);
ZeroMemory(buf, 16384);
// Wait for client to send data
//do {
bytesReceived = recv(clientSocket, buf, 16384, 0);
if (bytesReceived > 0)
{
std::cout << std::string(buf, 0, bytesReceived) << std::endl;
}
else if (bytesReceived == 0)
{
std::cout << "Connection closed" << std::endl;
}
else
{
std::cout << "Error in recv(). Quitting = " << WSAGetLastError() << std::endl;
break;
}
//} while (bytesReceived > 0);
const char* reply =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/html\r\n"
"Content-Length: 0\r\n"
"Accept-Ranges: bytes\r\n"
"Connection: close";
bytesSent = send(clientSocket, reply, strlen(reply), 0);
if (bytesSent < 0)
{
std::cout << "Send failed = " << WSAGetLastError() << std::endl;
}
std::cout << "Sent: " << bytesSent << " (" << strlen(reply) << ")" << std::endl;
shutdown(clientSocket, SD_BOTH);
closesocket(clientSocket);
} |
}

const char* reply =
"HTTP/1.1 200 OK\n"
...
"Keep - Alive: timeout=1, max=1\n"
...
"Connection: close\n";
send(clientSocket, reply, strlen(reply), 0);
This is not a valid HTTP response for multiple reasons:
The line ending should be \r\n not \n.
The HTTP header should end with an additional \r\n (i.e. empty line). This means the HTTP response you send is not complete and thus Postman hangs on waiting for the rest.
The Keep - Alive header has not the valid syntax for a HTTP header. The field name is not allowed to contain spaces.
Apart from that,
send is not guaranteed to send everything in the given buffer, i.e. you should check the return code.
A Keep-Alive header makes no sense at all if Connection: close is used.
Note that HTTP is not an ad-hoc protocol but an actual standard. Implementations should follow the standard and thus the developers would need to study the actual standard and not blindly rely on (wrong) assumptions of how things might work. Even if it works with some client it might not work with another one, since some clients adhere more to the standard while others are more tolerant regarding errors.

There are multiple problems with the shown code.
int bytesReceived = recv(clientSocket, buf, 16384, 0);
On any TCP socket, HTTP or not, you get no guarantees whatsoever that whatever the other side of the socket sent you, it will get returned in a single recv() call.
If, for example, the client sent you the following HTTP request:
GET / HTTP/1.0<CR><LF>
Host: localhost<CR><LF>
<CR><LF>
Nobody is going to guarantee you that this recv() will return this entire thing to you. recv() could, for example, return only the "GET" part, and return the value of 3 to indicate that only 3 bytes were received. You are required to call recv() as many times as necessary to receive the complete message. The 2nd call to recv() could, theoretically, return " /" and the value of 2 to indicate that two more bytes were received.
You cannot completely ignore the return code from recv(), which tells you what was actually read, and you will need to implement appropriate logic to keep recv()ing until you received the entire message. Your code needs to understand that an HTTP message consists of a message line, an arbitrary list of headers, then a single blank line, all terminated by <CR><LF>, or "\r\n", and keep trying until it receives the complete message.
const char* reply =
"HTTP/1.1 200 OK\n"
"Content-Type: text/html\n"
"Content-Length: 0\n"
"Keep - Alive: timeout=1, max=1\n"
"Accept-Ranges: bytes\n"
"Connection: close\n";
HTTP uses <CR><LF> as the end of line terminator, all of these should be \r\n.
"Keep - Alive:" is not a valid HTTP header name. Header names cannot contain spaces.
A blank line, a single \r\n, should follow the last HTTP header. It is missing fom your response. Even though you're closing the socket immediately, without a well-formed HTTP response message the client can rightfully conclude that the HTTP server is faulty and did not send a valid response.
send(clientSocket, reply, strlen(reply), 0);
Like with recv(), you are not guaranteed that send() will transmit the requested number of bytes. Just like with recv() you must check the return value of send() to see how many bytes were sent, and then try again to send the remaining part of the message, if there's any, until you send the entire message.
You must fix all of these problems in order to properly implement HTTP over TCP.

Related

No response from the UDP server

I am not an expert in C ++ nor in socket communication.
I need to connect to a server and this server should respond to my request with an XML format stream.
I have created the client (inspired by other programs) with which I try to connect to the correct IP address and port by sending a RTSP call. The connection seems to be fine, but the problem is that when I run recvfrom() I don't get any data. I tried to make a UDP client and recvfrom() returns -1.
This is the code of the UDP client:
void main(int argc, char* argv[]) {
WSADATA data;
WORD version = MAKEWORD(2, 2);
int wsOk = WSAStartup(version, &data);
if (wsOk != 0) {
cout << "can't start winsock!" << wsOk << endl;
return;
}
//create a hint structure for the server
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(80);
inet_pton(AF_INET, "192.0.0.1", &server.sin_addr);
//socket creation
SOCKET out = socket(AF_INET, SOCK_DGRAM, 0);
// write out to that socket
string s = "rtsp://pluto:paperino#192.0.0.1/media.amp?video=0&audio=0&event=on";
int sendOk = sendto(out, s.c_str(), s.size() + 1, 0, (sockaddr*)&server, sizeof(server));
if (sendOk == SOCKET_ERROR) {
cout << "That didn't work!" << WSAGetLastError() << endl;
}
else
{
cout << "connection from server is ok: " << sendOk << endl;
}
int len = sizeof(server);
char buffer[1024];
ZeroMemory(buffer, sizeof(buffer));
int recOk = 0;
recOk = recvfrom(out, buffer, sizeof(buffer), 0, (sockaddr*)&server, &len);
if (recOk != SOCKET_ERROR)
{
printf("Receive response from server: %s\n", buffer);
}
//close the socket
closesocket(out);
WSACleanup();
}
In comments, you say that recvfrom() is reporting error 10054, which is WASECONNRESET. The recvfrom() documentation on MSDN says the following about that:
Error code
Meaning
WSAECONNRESET
The virtual circuit was reset by the remote side executing a hard or abortive close. The application should close the socket; it is no longer usable. On a UDP-datagram socket this error indicates a previous send operation resulted in an ICMP Port Unreachable message.
In other words, you sent your request to a port that is not listening for UDP messages. Which makes sense, as you sent your request to port 80, which is typically used for HTTP traffic over TCP, not RTSP traffic over UDP.
For that matter, what you sent wasn't even a valid RTSP request to begin with. I suggest you read up on how the RTSP protocol actually works (hint: you don't send a rtsp:// URL with it).

winsock server send and receive simultaniously

I'm new to WinSock, and I'm trying something out. I have client and server programs that are communicating with each other. If the client types something, the server will just echo it back. I want them to receive and send at the same time, so I put the client in non-blocking mode, and it works kind-of OK. But when I try to put the server in non-blocking, it crashes saying that recv() == SOCKET_ERROR.
So the question is : why can the client work in non-blocking, but the server can't? How can I solve this?
TCP_SERVER:
#include <iostream>
#include <WS2tcpip.h>
#include <Windows.h>
#pragma comment (lib,"ws2_32.lib")
using namespace std;
string receive(SOCKET clientSocket, char* buf)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
string bufStr = buf;
cout << "bytes received: " << bytesReceived << endl;
if (bytesReceived == SOCKET_ERROR)
{
cerr << "error met recv() in de reciev() functie" << endl;
exit(EXIT_FAILURE);
}
if (bytesReceived == 0)
{
cout << "client disconnected" << endl;
exit(EXIT_FAILURE);
}
return bufStr;
}
void main()
{
//initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0) {
cerr << "can't initialize winsock ABORT";
return;
}
//create socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "cant create socket ABORT" << std::endl;
}
//bind IP adress and port to socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; //could also inet_pton
bind(listening, (sockaddr*)&hint, sizeof(hint));
//tell winsock the socket is for listening
listen(listening, SOMAXCONN);
//wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET) {
cerr << "somthing went wrong with client socket accept ABORT";
exit(EXIT_FAILURE);
}
char host[NI_MAXHOST]; //client remote name
char service[NI_MAXSERV]; //service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << " connected on port " << service << endl;
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on port " << ntohs(client.sin_port) << endl;
}
//close listening socket
closesocket(listening);
//non blocking socket leads to error
u_long mode = 1; // 1 to enable non-blocking socket
ioctlsocket(clientSocket, FIONBIO, &mode);
//non blocking socket
//while loop: accept and echo message to client
char buf[4096];
string inputTxt;
while (true)
{
inputTxt = receive(clientSocket,buf);
send(clientSocket, buf, inputTxt.size() + 1, 0);
}
closesocket(clientSocket);
WSACleanup();
}
TCP_CLIENT:
#include <iostream>
#include <WS2tcpip.h>
#include <Windows.h>
#pragma comment (lib,"ws2_32.lib")
using namespace std;
string receive(SOCKET clientSocket, char* buf)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
string bufStr = buf;
cout << "bytes received: " << bytesReceived << endl;
if (bytesReceived == SOCKET_ERROR)
{
cerr << "error met recv() in de reciev() functie" << endl;
exit(EXIT_FAILURE);
}
if (bytesReceived == 0)
{
cout << "client disconnected" << endl;
exit(EXIT_FAILURE);
}
return bufStr;
}
void main()
{
//initialize winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0) {
cerr << "can't initialize winsock ABORT";
return;
}
//create socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "cant create socket ABORT" << std::endl;
}
//bind IP adress and port to socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; //could also inet_pton
bind(listening, (sockaddr*)&hint, sizeof(hint));
//tell winsock the socket is for listening
listen(listening, SOMAXCONN);
//wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
if (clientSocket == INVALID_SOCKET) {
cerr << "somthing went wrong with client socket accept ABORT";
exit(EXIT_FAILURE);
}
char host[NI_MAXHOST]; //client remote name
char service[NI_MAXSERV]; //service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
cout << host << " connected on port " << service << endl;
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on port " << ntohs(client.sin_port) << endl;
}
//close listening socket
closesocket(listening);
/*
//non blocking socket leads to error
u_long mode = 1; // 1 to enable non-blocking socket
ioctlsocket(clientSocket, FIONBIO, &mode);
//non blocking socket
*/
//while loop: accept and echo message to client
char buf[4096];
string inputTxt;
while (true)
{
inputTxt = receive(clientSocket,buf);
send(clientSocket, buf, inputTxt.size() + 1, 0);
}
closesocket(clientSocket);
WSACleanup();
}
You are not handling the case where send()/recv() are failing due to a WSAEWOULDBLOCK error, which is NOT a fatal error. It just means there is no work to be done at that moment, try again later.
For recv(), that means there are no bytes available to read from the socket's receive buffer. The socket will be in a readable state when there are bytes available to read from it, or the peer has performed a graceful disconnect.
For send(), it means the peer's receive buffer is full and can't receive new bytes until the peer reads some bytes to clear up buffer space. Any unsent bytes will have to be passed to send() again at a later time. The socket will be in a writable state when new bytes can be sent to the peer, and not in a writable state when the peer's buffer is full.
When your server accepts a client and tries to receive() from it, recv() is going to keep failing with WSAEWOULDBLOCK until the client actually sends something.
So, you need to handle WSAEWOULDBLOCK properly and retry as needed. Or better, use select() (or WSAAsyncSelect(), or WSAEventSelect(), or Overlapped I/O) to detect the socket's actual state to know when send()/recv() can be safely called without causing an WSAEWOULDBLOCK error.

Cannot solve this error in my TCP server code

So, I was trying to code this simple TCP server, but I'm stucked with this error
error: 'inet_ntop' was not declared in this scope; did you mean 'inet_ntoa'
I know that I have to use ntop and not ntoa. But I can't find out how to get rid of this error. I searched everywhere and couldn't find anything. I hope someone can help me. My code is below.
#define _WIN32_WINNT 0x501
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
using namespace std;
int main(void){
//initialize winsock
WSADATA WSData;
WORD ver = MAKEWORD(2, 2);
int WSOK = WSAStartup(ver, &WSData);
if (WSOK != 0){
cerr << "Can't initialize winsock! Quitting" << endl;
return 0;
}
//create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET)
{
cerr << "Can't create a socket! Quitting" << endl;
return 0;
}
// bind the socket to an ip adress an port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // could also use inet_pton...
bind(listening, (sockaddr*)&hint, sizeof(hint));
//tell winsock the socket is for listening
listen(listening, SOMAXCONN);
//wait for connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
char host[NI_MAXHOST]; // client's remote name
char service[NI_MAXSERV]; // Service (i.e port) the client is connected on
ZeroMemory(host, NI_MAXHOST);
ZeroMemory(service, NI_MAXSERV);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << "connected on port" << service << endl;
}
else
{
inet_ntop(AF_INET, &client.sin_addr), host, NI_MAXHOST);
cout << host << "connecte on port" <<
ntohs(client.sin_port) << endl;
}
//close listening socket
closesocket(listening);
//while loop: accept and echo message bac to client
char buf[4096];
while (true)
{
ZeroMemory(buf, 4096);
//wait for client send data
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == SOCKET_ERROR)
{
cerr << "Error in recv(). Quitting" << endl;
break;
}
if (bytesReceived == 0)
{
cout << "Client disconnected " << endl;
break;
}
//echo message back to client
send(clientSocket, buf, bytesReceived + 1, 0);
}
//close socket
closesocket(clientSocket);
// cleanup winsock
WSACleanup();
}
inet_ntop() requires Windows Vista and later at runtime, but you are setting _WIN32_WINNT to 0x501, which represents Windows XP, so the declaration of inet_ntop() in <w32tcpip.h> gets disabled at compile-time to prevent the program from failing to start at runtime.
You need to set _WIN32_WINNT to at least 0x600 instead to enable inet_ntop().
However, even after you fix that issue, your code will still fail to compile, because you have a syntax mistake in your call to inet_ntop() - your parenthesis are unbalanced in the 2nd parameter. You have either a missing (, or an erroneous ), depending on which of the following syntaxes you were trying to use:
inet_ntop(AF_INET, &(client.sin_addr), host, NI_MAXHOST);
inet inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
You also have other logic errors that won’t show up until runtime. You are not doing any error handling on bind(), listen(), and send(). And you have a potential buffer overflow on send(), too.

c++ irc server doesnt send ping

I trying to make a simple irc client with c++. i am sending PASS, NICK and USER messages but server doesnt send me PING. I cant register...
this is the code:
#include <iostream>
#include <string>
#include <WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
string ipadress = "91.217.189.58";
int port = 6667;
WSADATA ws_data;
SOCKET Skt;
int main()
{
int ws_result = WSAStartup(MAKEWORD(2, 2), &ws_data);
if (ws_result != 0)
cout << "socket cannot be initialized\n";
else
cout << "Soket initialized!\n";
Skt = socket(AF_INET, SOCK_STREAM, 0);
if (Skt == INVALID_SOCKET)
cout << "socket not created\n";
else
cout << "Socket created!\n";
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(6667);
inet_pton(AF_INET, ipadress.c_str(), &hint.sin_addr);
int connection_result = connect(Skt, (sockaddr*)&hint, sizeof(hint));
if (connection_result == SOCKET_ERROR)
cout << "Socket could not connect\n";
else
cout << "Socket Connected!\n";
string channel = "JOIN #dikes\r\n";
string Pass = "PASS PASSRE";
string user = "USER guest 0 * :IRCbot\r\n";
string nick = "NICK botzzz\r\n";
char buffer[4096];//buffer to recieve messages from irc server
send(Skt, Pass.c_str(), Pass.size(), 0);
send(Skt, nick.c_str(), nick.size() , 0);
send(Skt, user.c_str(), user.size(), 0);
while (true)
{
string Pong = "PONG";
ZeroMemory(buffer, 4096);
int bytes_recieved = recv(Skt, buffer, 4096, 0);
string msg = string(buffer, 0, bytes_recieved);
cout << msg;
if (msg == "PING")
{
send(Skt, Pong.c_str(), Pong.size() + 1, 0);
}
else if (msg == "001")
{
send(Skt, channel.c_str(), channel.size(), 0);
}
}
this is the output of this code:
Soket initialized!
Socket created!
Socket Connected!
:irc.portlane.se 020 * :Please wait while we process your connection.
ERROR :Closing Link: [unknown#176.43.204.170] (Ping timeout)
Your checks don't account for \r\n
Your checks don't account for the nick parameter on the PING command
Your PASS command isn't terminated by a \r\n
Your PONG response isn't terminated by a \r\n
You've assumed a one-to-one mapping of "received data" and "lines". This is not guaranteed. It is quite possible (likely, even) that a single call to recv fills the buffer with data from zero to many complete commands/messages, possibly followed by an incomplete message!
TCP/IP doesn't know about the IRC protocol; it doesn't care about its concept of a "command" and it does not break up packets into those itemised pieces for you. You have to do that. TCP/IP just streams bytes at you.
You need to add the received bytes to a secondary buffer when they are received, then iteratively parse that buffer to extract any complete lines that have become available. (Do this properly and it'll also take care of #1)
(However, I would still expect to see the ping request in your output, so something else must also be wrong.)

C++ socket error WSAENOTSOCK (10038) after including thread

I created TCP socket connection between client and server.
It is necessary for me to use threads because I'm getting x and y coordinates from another process, and drawing those values with OpenGL.
Only way I had in mind was to create thread for OpenGL drawing, and use main thread to recieve coordinates by socket.
My server side worked perfectly before adding #include <thread>, so I have no idea what could the problem be and why couldn't I use threads while using sockets.
After including thread, after calling recv(), I'm getting error:
WSAENOTSOCK 10038
by using WSAGetLastError();
I think that code is too long for me to post it so I can copy some parts of it that are necessary.
EDIT: code of creating socket and waiting for connection.
// Inicijaliziraj winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wSocket = WSAStartup(ver, &wsData);
if (wSocket != 0) {
cerr << "Problem with initialization of Winsock, exiting!" << endl;
return;
}
// Create a socket
SOCKET listening = socket(AF_INET, SOCK_STREAM, 0);
if (listening == INVALID_SOCKET) {
cerr << "Unable to create a socket! Quitting" << endl;
return;
}
// Bind the ip address and port to a socket
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(54000);
hint.sin_addr.S_un.S_addr = INADDR_ANY; // Could also use inet_pton
bind(listening, (sockaddr*)&hint, sizeof(hint));
// Tell winsock socket is for listening
listen(listening, SOMAXCONN);
// Wait for a connection
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(listening, (sockaddr*)&client, &clientSize);
/*
if (clientSocket == INVALID_SOCKET) {
cerr << "Unable to connect to client socket, Quitting!" << endl;
return;
}*/
char host[NI_MAXHOST]; // Client's remote name
char service[NI_MAXHOST]; // Service (PORT) the client is connected on
ZeroMemory(host, NI_MAXHOST); // Could use memset(host, 0, )
ZeroMemory(service, NI_MAXHOST);
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0)
{
cout << host << " connected on port " << service << endl;
}
else
{
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
cout << host << " connected on port " << ntohs(client.sin_port) << endl;
}
// Close listening socket
closesocket(listening);
// While loop: accept and echo message back to client
char buf[4096];
//Opens new thread with canvas because otherwise while loop for recieving will block drawing
//std::thread t1(setDrawing, &iArgc, cppArgv);
while (true) {
ZeroMemory(buf, 4096);
// Wait for client to send data
int bytesRecieved = recv(clientSocket, buf, 4096, 0);
if (bytesRecieved == SOCKET_ERROR) {
int err = WSAGetLastError();
cerr << "Error in recv(). Quitting!" << endl;
break;
}
if (bytesRecieved == 0) {
cout << "Client disconnected " << endl;
break;
}
My server side worked perfectly before adding #include <thread>, so I have no idea what could the problem be and why couldn't I use threads while using sockets.
One thing to pay attention to is that <thread> is a C++ STL header. If your code happens to have a using namespace std; statement, your socket code may end up calling the STL's std::bind() function instead of WinSock's bind() function, which would in turn cause listen() to fail with an WSAEINVAL error. Which you are not checking for since you are not doing any error handling on your bind() or listen() calls. So be aware of that. Avoid using namespace std; statements, or call WinSock's bind() as ::bind() instead. And ALWAYS do error handling on API calls.
You have also commented out your error handling on accept(). If bind() and listen() fail, so will accept(), causing it to return INVALID_SOCKET. Which could explain why you are then getting the WSAENOTSOCK error on recv().