Winsock API - send and receive data simultaneously in two threads - c++

I'm trying to build a client and a server in the same program. For example, user 1 sends a packet of data to user 2, user 2 after receiving the packet sends back a different packet to user 1. The problem is, after running the program neither user receives the packets.If I build the client in a separate program from the server it works
#pragma comment(lib,"ws2_32.lib")
#include <WinSock2.h>
#include <iostream>
#include <thread>
static const int num_threads = 2;
static char buffer[8096 + 1];
char a[256] = {};
char MOTD[256];
void call_from_thread(int tid) {
// ---------- Server code: ---------- //
if( tid == 0 ){
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0){MessageBoxA(NULL, "WinSock startup failed", "Error", MB_OK | MB_ICONERROR);}
SOCKADDR_IN addr;
int addrlen = sizeof(addr);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(1112);
addr.sin_family = AF_INET;
SOCKET sListen = socket(AF_INET, SOCK_STREAM, NULL);
bind(sListen, (SOCKADDR*)&addr, sizeof(addr));
listen(sListen, SOMAXCONN);
SOCKET newConnection;
newConnection = accept(sListen, (SOCKADDR*)&addr, &addrlen);
if (newConnection == 0){
std::cout << "Failed to accept the client's connection." << std::endl;
}else{
std::cout << "Client Connected!" << std::endl;
}
while (true){
std::cin >> a;
send(newConnection, a, sizeof(a), NULL);
}
}else if( tid == 1 ){
// ---------- Client code: ---------- //
WSAData wsaData;
WORD DllVersion = MAKEWORD(2, 1);
if (WSAStartup(DllVersion, &wsaData) != 0){MessageBoxA(NULL, "Winsock startup failed", "Error", MB_OK | MB_ICONERROR);}
SOCKADDR_IN addr;
int sizeofaddr = sizeof(addr);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
addr.sin_port = htons(1111);
addr.sin_family = AF_INET;
SOCKET Connection = socket(AF_INET, SOCK_STREAM, NULL); //Set Connection socket
if (connect(Connection, (SOCKADDR*)&addr, sizeofaddr) != 0) //If we are unable to connect...
{
MessageBoxA(NULL, "Failed to Connect", "Error", MB_OK | MB_ICONERROR);
//return 0; //Failed to Connect
}
std::cout << "Connected!" << std::endl;
char MOTD[256];
while (true){
recv(Connection, MOTD, sizeof(MOTD), NULL); //Receive Message of the Day buffer into MOTD array
std::cout << "MOTD:" << MOTD << std::endl;
}
}
// ---------- Thread selection: ---------- //
int main() {
std::thread t[num_threads];
for (int i = 0; i < num_threads; ++i) {
t[i] = std::thread(call_from_thread, i);
}
for (int i = 0; i < num_threads; ++i) {
t[i].join();
}
}

The server is listening on port 1112, but the client is connecting to port 1111. This means the client and server cannot possibly be connected to each other at all, whether they are in the same application or not.
I also see a number of other problems with your code, including:
WSAStartup() should be called once at app startup, not per thread.
Neither thread quits cleanly if any WinSock function fails.
The client thread does not wait for the server thread to open its listening port before the client can then connect to it.
Potential buffer overflows.
Resource leaks.
A lack of decent error handling.
On the server side, you are completely ignoring errors reported by socket(), bind(), listen(), and send(), and you are not checking the return value of accept() correctly.
On the client side, you are completely ignoring errors reported by socket() and recv(). And, you are not ensuring the MOTD buffer is null-terminated before printing it to std::cout.
Try something more like this:
#include <winsock2.h>
#include <windows.h>
#pragma comment(lib,"ws2_32.lib")
#include <iostream>
#include <thread>
#include <string>
#include <cstdint>
#include <stdexcept>
#include <limits>
#include <algorithm>
// The below variables are used to let the client wait for the server
// port to be opened. If you don't want to use these, especially if the
// client and server are ever run on different machines, you can omit
// these and instead just have the client call connect() in a loop
// until successful...
//
#include <mutex>
#include <condition_variable>
#include <chrono>
static std::condition_variable server_cv;
static std::mutex server_mtx;
static bool server_is_listening = false;
//
static const int num_threads = 2;
static const u_short server_port = 1111;
class winsock_error : public std::runtime_error
{
public:
int errCode;
std::string funcName;
winsock_error(int errCode, const char *funcName) : std::runtime_error("WinSock error"), errCode(errCode), funcName(funcName) {}
};
void WinSockError(const char *funcName, int errCode = WSAGetLastError())
{
throw winsock_error(errCode, funcName);
}
class connection_closed : public std::runtime_error
{
public:
connection_closed() : std::runtime_error("Connection closed") {}
};
class socket_ptr
{
public:
socket_ptr(SOCKET s) : m_sckt(s) {}
socket_ptr(const socket_ptr &) = delete;
socket_ptr(socket_ptr &&src) : m_sckt(src.m_sckt) { src.m_sckt = INVALID_SOCKET; }
~socket_ptr() { if (m_sckt != INVALID_SOCKET) closesocket(m_sckt); }
socket_ptr& operator=(const socket_ptr &) = delete;
socket_ptr& operator=(socket_ptr &&rhs) { m_sckt = rhs.m_sckt; rhs.m_sckt = INVALID_SOCKET; return *this; }
operator SOCKET() { return m_sckt; }
bool operator!() const { return (m_sckt == INVALID_SOCKET); }
private:
SOCKET m_sckt;
}
template <typename T>
T LimitBufferSize(size_t size)
{
return (T) std::min(size, (size_t) std::numeric_limits<T>::max());
}
void sendRaw(SOCKET sckt, const void *buffer, size_t buflen)
{
const char *ptr = static_cast<const char*>(buffer);
while (buflen > 0)
{
int numToSend = LimitBufferSize<int>(buflen);
int numSent = ::send(sckt, ptr, numToSend, 0);
if (numSent == SOCKET_ERROR)
WinSockError("send");
ptr += numSent;
buflen -= numSent;
}
}
void recvRaw(SOCKET sckt, void *buffer, size_t buflen)
{
char *ptr = static_cast<char*>(buffer);
while (buflen > 0)
{
int numToRecv = LimitBufferSize<int>(buflen);
int numRecvd = ::recv(sckt, ptr, numToRecv, 0);
if (numRecvd == SOCKET_ERROR)
WinSockError("recv");
if (numRecvd == 0)
throw connection_closed();
ptr += numRecvd;
buflen -= numRecvd;
}
}
void sendStr(SOCKET sckt, const std::string &str)
{
uint32_t len = LimitBufferSize<uint32_t>(str.size());
uint32_t tmp = htonl(len);
sendRaw(sckt, &tmp, sizeof(tmp));
if (len > 0)
sendRaw(sckt, str.c_str(), len);
}
std::string recvStr(SOCKET sckt)
{
std::string str;
uint32_t len;
recvRaw(sckt, &len, sizeof(len));
len = ntohl(len);
if (len > 0)
{
str.resize(len);
recvRaw(sckt, &str[0], len);
}
return str;
}
void server_thread()
{
std::cout << "[Server] Starting ..." << std::endl;
try
{
socket_ptr sListen(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
if (!sListen)
WinSockError("socket");
SOCKADDR_IN addr = {};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ::inet_addr("127.0.0.1");
addr.sin_port = ::htons(server_port);
int addrlen = sizeof(addr);
if (::bind(sListen, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR)
WinSockError("bind");
if (::listen(sListen, 1) == SOCKET_ERROR)
WinSockError("listen");
// this is optional...
{
std::unique_lock<std::mutex> lk(server_mtx);
server_is_listening = true;
}
server_cv.notify_all();
//
std::cout << "[Server] Listening for Client ..." << std::endl;
socket_ptr newConnection(::accept(sListen, (SOCKADDR*)&addr, &addrlen));
if (!newConnection)
WinSockError("accept");
std::cout << "[Server] Client Connected!" << std::endl;
try
{
std::string a;
while (std::cin >> a)
sendStr(newConnection, a);
}
catch (const connection_closed &)
{
}
catch (const winsock_error &e)
{
std::cerr << "[Server] Client error: " << e.errCode << " on WinSock function: " << e.funcName << std::endl;
}
std::cout << "[Server] Client Disconnected!" << std::endl;
}
catch (const winsock_error &e)
{
std::cerr << "[Server] Error: " << e.errCode << " on WinSock function: " << e.funcName << std::endl;
}
catch (const std::exception &e)
{
std::cerr << "[Server] Unexpected Error! " << e.what() << std::endl;
}
std::cout << "[Server] Stopped!" << std::endl;
}
void client_thread()
{
std::cout << "[Client] Starting ..." << std::endl;
try
{
// this is optional, could call connect() below in a loop instead...
std::cout << "[Client] Waiting for Server ..." << std::endl;
{
std::unique_lock<std::mutex> lk(server_mtx);
if (!server_cv.wait_for(lk, std::chrono::seconds(5), []{ return server_is_listening; }))
throw std::runtime_error("Server not listening after 5 seconds!");
}
//
socket_ptr sConnection(::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
if (!sConnection)
WinSockError("socket");
SOCKADDR_IN addr = {};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ::inet_addr("127.0.0.1");
addr.sin_port = ::htons(server_port);
if (::connect(sConnection, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR)
WinSockError("connect");
std::cout << "[Client] Connected!" << std::endl;
try
{
std::string MOTD;
while (true)
{
MOTD = recvStr(sConnection);
std::cout << "[Client] MOTD: " << MOTD << std::endl;
}
}
catch (const connection_closed &)
{
}
catch (const winsock_error &e)
{
std::cerr << "[Client] Server error: " << e.errCode << " on WinSock function: " << e.funcName << std::endl;
}
std::cout << "[Client] Disconnected!" << std::endl;
}
catch (const winsock_error &e)
{
std::cerr << "[Client] Error: " << e.errCode << " on WinSock function: " << e.funcName << std::endl;
}
catch (const std::exception &e)
{
std::cerr << "[Client] Unexpected Error! " << e.what() << std::endl;
}
std::cout << "[Client] Stopped!" << std::endl;
}
int main()
{
WSADATA wsaData;
int ret = ::WSAStartup(MAKEWORD(2, 1), &wsaData);
if (ret != 0)
{
std::cerr << "WinSock Startup failed with error: " << ret << std::endl;
return -1;
}
std::cout << "WinSock Startup successful" << std::endl;
std::thread t[num_threads];
t[0] = std::thread(server_thread);
t[1] = std::thread(client_thread);
for (int i = 0; i < num_threads; ++i) {
t[i].join();
}
::WSACleanup();
return 0;
}

Related

recv() keeps returning -1

I am creating a server proxy between a client and a server. Currently I have found a base of the idea in python, and I'm trying to convert it to C++. However, I'm struggling since my code doesn't seem to work correctly.
Apparently recv keeps returning SOCKET_ERROR, so I am thinking that maybe I've done something wrongly with winsock.
#include <iostream>
#include <string>
#include <WinSock2.h>
#include <ws2tcpip.h>
#include <thread>
#include <vector>
#include <sstream>
#pragma comment(lib, "Ws2_32.lib")
void parse(char* data, int len, int port, const std::string& origin) {
std::cout << "[" << origin << "(" << port << ")] " << data << std::endl;
}
struct ProxyToServer {
SOCKET m_client;
SOCKET m_server;
int m_port;
ProxyToServer() = default;
ProxyToServer(const char* host, int port) {
m_port = port;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0) {
sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(port);
inet_pton(AF_INET, host, &server_addr.sin_addr);
if ((m_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
std::cerr << "[Proxy2Server] Could not create socket!\n";
}
if (connect(m_server, reinterpret_cast<sockaddr*>(&server_addr), sizeof(server_addr)) != 0) {
std::cerr << "[Proxy2Server] Could not connect socket!\n";
}
if (WSACleanup() != 0) {
std::cerr << "Cleanup failed!\n";
}
}
else {
std::cerr << " Winsock startup failed!\n";
}
}
void execute() {
char data[4096];
while (true) {
int totalRecv = recv(m_server, data, 4096, 0);
if (totalRecv == SOCKET_ERROR) std::cout << "Socket error... (recv)" << std::endl;
if (totalRecv > 0) {
parse(data, 4096, m_port, "server");
send(m_client, data, totalRecv, 0);
}
}
}
};
struct ClientToProxy {
SOCKET m_server;
SOCKET m_client;
int m_port;
ClientToProxy() = default;
ClientToProxy(const char* host, int port) {
m_port = port;
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) == 0) {
if (LOBYTE(wsaData.wVersion) >= 2) {
SOCKET sock;
if ((sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) {
std::cerr << "[Client2Proxy] Could not create socket!\n";
}
const int enable = 1;
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (const char*) & enable, sizeof(enable));
sockaddr_in sock_addr;
sock_addr.sin_family = AF_INET;
sock_addr.sin_port = htons(port);
inet_pton(AF_INET, host, &sock_addr.sin_addr);
if (bind(sock, (sockaddr*)&sock_addr, sizeof(sock_addr)) != 0) {
std::cerr << "[Client2Proxy] Could not bind socket!\n";
}
if (listen(sock, 100) != 0) {
std::cerr << "[Client2Proxy] Could not listen!\n";
}
sockaddr_in clientSockAddr;
int clientSockSize = sizeof(clientSockAddr);
m_client = accept(sock,reinterpret_cast<sockaddr*>(&clientSockAddr),&clientSockSize);
if (m_client == INVALID_SOCKET) std::cerr << "Invalid Client! " << std::endl;
}
else {
std::cerr << "Requested winsock ver is not supported! \n";
}
if (WSACleanup() != 0) {
std::cerr << "Cleanup failed!\n";
}
}
else {
std::cerr << " Winsock startup failed!\n";
}
}
void execute() {
while (true) {
char data[4096];
int totalRecv = recv(m_client, data, sizeof(data), 0);
if (totalRecv == SOCKET_ERROR) std::cout << "Socket error... (recv) " << std::endl;
if (totalRecv > 0) {
parse(data, 4096, m_port, "client");
send(m_server, data, sizeof(data), 0);
}
}
}
};
struct Proxy {
const char* m_from_host;
const char* m_to_host;
int m_port;
ClientToProxy g2p;
ProxyToServer p2s;
Proxy(const char* from_host, const char* to_host, int port) : m_from_host(from_host), m_to_host(to_host), m_port(port) {}
void execute() {
while (true) {
std::cout << "[proxy(" << m_port << ")] setting up" << std::endl;
g2p = ClientToProxy(m_from_host, m_port);
p2s = ProxyToServer(m_to_host, m_port);
std::cout << "[proxy(" << m_port << ")] connection established" << std::endl;
p2s.m_client = g2p.m_client;
g2p.m_server = p2s.m_server;
std::thread t1(&ClientToProxy::execute, &g2p);
std::thread t2(&ProxyToServer::execute, &p2s);
t1.join();
t2.join();
}
}
};
int main() {
Proxy master_server("127.0.0.1", "183.211.202.94", 13011);
std::thread t3(&Proxy::execute, &master_server);
t3.join();
/*
std::vector<Proxy> game_servers;
for (int port = 13000; port < 13006; port++) {
Proxy game_server("127.0.0.1", "185.212.200.90", port);
std::thread t4(&Proxy::execute, &game_server);
game_servers.push_back(game_server);
t4.join();
}*/
}
I don't know how to reduce this code unfortunately. The issues are in all recv calls in both classes seemingly...
N.B I am very sure that all the IPs are correcty and the port as well.

c++ multithreaded tcp server using futures and async

I recently started studying c++ and I'm following some tutorials. I was looking into sockets and I decided as a side project to create a small multithreaded server as you can see below.
I was trying to close the servers listening socket once CLIENTS_MAX_NUM reached and then reopen it once a socket disconnects, however this is giving me an error 10022 (WSAEINVAL) and I'm not quite sure what I'm doing wrong.
In case you want to reproduce the error just connect using telnet and close the client connection (ctrl+] , quit).
Any help would be greatly appreciated.
#include <iostream>
#include <vector>
#include <string>
#include <future>
#include <chrono>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
static constexpr const unsigned int PORT = 5000;
static constexpr const unsigned int CLIENTS_MAX_NUM = 1;
static constexpr const unsigned int CLIENTS_QUEUE_NUM = 10;
SOCKET server_sock;
std::vector<std::future<void>> futures;
std::mutex mtx;
void initialize_winsock() {
WSAData wsData;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &wsData);
if (wsResult != 0) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
exit(EXIT_FAILURE);
}
}
void bind_server_socket() {
int keep_alive = 1;
int re_use = 1;
if (setsockopt(server_sock, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keep_alive, sizeof(keep_alive)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&re_use, sizeof(re_use)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.S_un.S_addr = INADDR_ANY;
memset(&server.sin_zero, 0, 8);
if (bind(server_sock, (sockaddr*)&server, sizeof(sockaddr)) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
}
void open_server_socket(bool &listening) {
server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
listening = false;
WSACleanup();
exit(EXIT_FAILURE);
}
listening = true;
}
void close_server_socket(bool &listening) {
closesocket(server_sock);
listening = false;
}
void handle_client(SOCKET client_sock, sockaddr_in client) {
char buf[4096];
char host[NI_MAXHOST];
char service[NI_MAXHOST];
memset(host, 0, NI_MAXHOST);
memset(service, 0, NI_MAXHOST);
//std::cout << std::this_thread::get_id() << std::endl;
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
std::cout << host << " connected on port " << service << std::endl;
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::cout << host << " connected on port " << ntohs(client.sin_port) << std::endl;
}
while (true) {
memset(&buf, 0, 4096);
const int bytes_received = recv(client_sock, buf, 4096, 0);
if (bytes_received == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
}
else if (bytes_received == 0) {
std::cout << "client disconnected" << std::endl;
break;
}
else {
send(client_sock, buf, bytes_received + 1, 0);
}
}
}
int main(int argc, const char* argv[]) {
bool listening = false;
initialize_winsock();
open_server_socket(listening);
bind_server_socket();
// -----------------------------------------------------------
if (listen(server_sock, CLIENTS_QUEUE_NUM) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
else {
std::cout << "listening for incoming connections on port " << PORT << std::endl;
while (true) {
unsigned int removed = 0;
for (int i = 0; i < futures.size(); i++) {
auto status = futures.at(i).wait_for(std::chrono::milliseconds(0));
if (status == std::future_status::ready) {
futures.erase(futures.begin() + i);
removed++;
}
}
if (removed > 1) {
std::cout << removed << " clients removed" << std::endl;
}
else if (removed) {
std::cout << removed << " client removed" << std::endl;
}
if (futures.size() < CLIENTS_MAX_NUM && !listening) {
std::cout << "re-opening server socket" << std::endl;
open_server_socket(listening);
// BOOM <--- 10022 (WSAEINVAL) - https://learn.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2
}
if (listening) {
sockaddr_in client;
memset(&client.sin_zero, 0, 8);
int client_size = sizeof(client);
SOCKET client_sock = accept(server_sock, (sockaddr*)&client, &client_size);
if (client_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
else {
futures.emplace_back(std::async(std::launch::async, &handle_client, client_sock, client));
if (futures.size() >= CLIENTS_MAX_NUM && listening) {
std::cout << "closing server socket" << std::endl;
close_server_socket(listening);
}
std::cout << futures.size() << " clients connected" << std::endl;
}
}
}
}
// ----------------------------------------------------------
std::cout << "bye!" << std::endl;
WSACleanup();
exit(EXIT_SUCCESS);
}
After some digging I found a couple silly errors, below is the working code:
update
Also fixed the vector loop
#include <iostream>
#include <vector>
#include <string>
#include <future>
#include <chrono>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
static constexpr const unsigned int PORT = 5000;
static constexpr const unsigned int CLIENTS_MAX_NUM = 5;
static constexpr const unsigned int CLIENTS_QUEUE_NUM = 0;
void handle_client(SOCKET client_sock, sockaddr_in client) {
char buf[4096];
char host[NI_MAXHOST];
char service[NI_MAXHOST];
memset(host, 0, NI_MAXHOST);
memset(service, 0, NI_MAXHOST);
//std::cout << std::this_thread::get_id() << std::endl;
if (getnameinfo((sockaddr*)&client, sizeof(client), host, NI_MAXHOST, service, NI_MAXSERV, 0) == 0) {
std::cout << host << " connected on port " << service << std::endl;
}
else {
inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::cout << host << " connected on port " << ntohs(client.sin_port) << std::endl;
}
while (true) {
memset(&buf, 0, 4096);
const int bytes_received = recv(client_sock, buf, 4096, 0);
if (bytes_received == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
}
else if (bytes_received == 0) {
std::cout << "client disconnected" << std::endl;
break;
}
else {
send(client_sock, buf, bytes_received + 1, 0);
}
}
}
void initialize_winsock() {
WSAData wsData;
WORD ver = MAKEWORD(2, 2);
int wsResult = WSAStartup(ver, &wsData);
if (wsResult != 0) {
std::cerr << WSAGetLastError() << std::endl;
WSACleanup();
exit(EXIT_FAILURE);
}
}
void bind_server_socket(SOCKET &server_sock) {
int keep_alive = 1;
int re_use = 1;
if (setsockopt(server_sock, SOL_SOCKET, SO_KEEPALIVE, (const char*)&keep_alive, sizeof(keep_alive)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
if (setsockopt(server_sock, SOL_SOCKET, SO_REUSEADDR, (const char*)&re_use, sizeof(re_use)) == SOCKET_ERROR) {
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
sockaddr_in server;
server.sin_family = AF_INET;
server.sin_port = htons(PORT);
server.sin_addr.S_un.S_addr = INADDR_ANY;
memset(&server.sin_zero, 0, 8);
if (bind(server_sock, (sockaddr*)&server, sizeof(sockaddr)) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
}
void open_server_socket(SOCKET &server_sock, bool &accepting) {
server_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (server_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
accepting = false;
WSACleanup();
exit(EXIT_FAILURE);
}
accepting = true;
}
void close_server_socket(SOCKET &server_sock, bool &accepting) {
closesocket(server_sock);
accepting = false;
}
void clear_futures(std::vector<std::future<void>> &futures) {
std::vector<std::future<void>>::iterator it = futures.begin();
while (it != futures.end()) {
auto status = (*it).wait_for(std::chrono::milliseconds(0));
if (status == std::future_status::ready) {
it = futures.erase(it);
}
else {
++it;
}
}
}
void wait_for_connections(std::vector<std::future<void>> &futures, SOCKET &server_sock, bool& accepting) {
if (listen(server_sock, CLIENTS_QUEUE_NUM) == SOCKET_ERROR) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
else {
std::cout << "accepting for incoming connections on port " << PORT << std::endl;
while (true) {
if (futures.size() < CLIENTS_MAX_NUM && !accepting) {
std::cout << "re-opening server socket" << std::endl;
open_server_socket(server_sock, accepting);
bind_server_socket(server_sock);
wait_for_connections(futures, server_sock, accepting);
break;
}
if (accepting) {
sockaddr_in client;
memset(&client.sin_zero, 0, 8);
int client_size = sizeof(client);
SOCKET client_sock = accept(server_sock, (sockaddr*)&client, &client_size);
if (client_sock == INVALID_SOCKET) {
std::cerr << WSAGetLastError() << std::endl;
closesocket(server_sock);
WSACleanup();
exit(EXIT_FAILURE);
}
clear_futures(futures);
futures.emplace_back(std::async(std::launch::async, &handle_client, client_sock, client));
if (futures.size() >= CLIENTS_MAX_NUM && accepting) {
std::cout << "closing server socket" << std::endl;
close_server_socket(server_sock, accepting);
}
std::cout << futures.size() << " clients connected" << std::endl;
}
}
}
}
int main(int argc, const char* argv[]) {
std::vector<std::future<void>> futures;
bool accepting = false;
SOCKET server_sock;
initialize_winsock();
open_server_socket(server_sock, accepting);
bind_server_socket(server_sock);
wait_for_connections(futures, server_sock, accepting);
std::cout << "bye!" << std::endl;
WSACleanup();
exit(EXIT_SUCCESS);
}

Simple non-blocking multi-threaded tcp server

I'm studying C++, and this weekend I started to play around with sockets and threads. Bellow is a simple multi threaded server that I'm making based on some tutorials.
The issue that I'm facing is that when I'm connecting with 2 telnet clients only the keystrokes form the first connection appear on the server. Any keystroke sent from the second telnet connection appears suddenly once the first telnet connection closes. Could someone explain to me what have I done wrong here?
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
void clientSocketHandler(SOCKET clientSocket, std::string client_ip) {
char buf[4096];
std::thread::id thread_id = std::this_thread::get_id();
std::cout << thread_id << " - " << client_ip << ": connected" << std::endl;
while (true)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == 0)
{
std::cout << thread_id << " - " << client_ip << ": disconnected" << std::endl;
break;
}
if (bytesReceived > 0)
{
std::cout << thread_id << " - " << client_ip << ": " << std::string(buf, 0, bytesReceived) << std::endl;
//send(clientSocket, buf, bytesReceived + 1, 0);
}
}
std::cout << thread_id << " - " << client_ip << ": closing client socket & exiting thread..." << std::endl;
closesocket(clientSocket);
}
void waitForConnections(SOCKET serverSocket) {
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(1337);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(serverSocket, (sockaddr*)&hint, sizeof(hint));
listen(serverSocket, SOMAXCONN);
while (true) {
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);
if (clientSocket != INVALID_SOCKET)
{
char host[NI_MAXHOST]; // Client's remote name
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
std::string client_ip = inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::thread t(clientSocketHandler, clientSocket, client_ip);
t.join();
}
Sleep(100);
}
}
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
std::cerr << "Can't Initialize winsock! Quitting..." << std::endl;
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Can't create a socket! Quitting..." << std::endl;
return 1;
}
// If serverSocketMode = 0, blocking is enabled;
// If serverSocketMode != 0, non-blocking mode is enabled.
u_long serverSocketMode = 1;
if (ioctlsocket(serverSocket, FIONBIO, &serverSocketMode) != NO_ERROR)
{
WSACleanup();
std::cerr << "Can't set socket to non-blocking mode! Quitting..." << std::endl;
return 1;
}
// Disables the Nagle algorithm for send coalescing.
// This socket option is included for backward
// compatibility with Windows Sockets 1.1
BOOL flag = TRUE;
if (setsockopt(serverSocket, IPPROTO_TCP, TCP_NODELAY, (const char *)&flag, sizeof(flag)) != NO_ERROR)
{
WSACleanup();
std::cerr << "Can't set socket NO_DELAY option! Quitting..." << std::endl;
return 1;
}
// Start listening for connections
waitForConnections(serverSocket);
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}
This should work. I removed pointless things like setting the socket to non-blocking and disabling the Nagle algorithm. The latter should only be done for things that need low-millisecond interactivity.
But, the substantial change that should fix your problem is changing join to detach. Using join causes your program to wait for the thread to finish before continuing. Using detach says "This thread is going to run in the background doing things, and I don't care about learning its fate later.".
If you don't use one of the two, and the ::std::thread object is destroyed, the system throws an exception because you're destroying the only means you have of getting information about whether or not a thread exited with an error of some kind with saying that either you don't care about such information, or explicitly asking for it.
I don't have Windows, so I can't test it:
#include <iostream>
#include <string>
#include <thread>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment (lib, "ws2_32.lib")
void clientSocketHandler(SOCKET clientSocket, std::string client_ip)
{
char buf[4096];
std::thread::id thread_id = std::this_thread::get_id();
std::cout << thread_id << " - " << client_ip << ": connected" << std::endl;
while (true)
{
ZeroMemory(buf, 4096);
int bytesReceived = recv(clientSocket, buf, 4096, 0);
if (bytesReceived == 0)
{
std::cout << thread_id << " - " << client_ip << ": disconnected" << std::endl;
break;
}
if (bytesReceived > 0)
{
std::cout << thread_id << " - " << client_ip << ": " << std::string(buf, 0, bytesReceived) << std::endl;
//send(clientSocket, buf, bytesReceived + 1, 0);
}
}
std::cout << thread_id << " - " << client_ip << ": closing client socket & exiting thread..." << std::endl;
closesocket(clientSocket);
}
void waitForConnections(SOCKET serverSocket)
{
sockaddr_in hint;
hint.sin_family = AF_INET;
hint.sin_port = htons(1337);
hint.sin_addr.S_un.S_addr = INADDR_ANY;
bind(serverSocket, (sockaddr*)&hint, sizeof(hint));
listen(serverSocket, SOMAXCONN);
while (true) {
sockaddr_in client;
int clientSize = sizeof(client);
SOCKET clientSocket = accept(serverSocket, (sockaddr*)&client, &clientSize);
if (clientSocket != INVALID_SOCKET)
{
char host[NI_MAXHOST]; // Client's remote name
ZeroMemory(host, NI_MAXHOST); // same as memset(host, 0, NI_MAXHOST);
std::string client_ip = inet_ntop(AF_INET, &client.sin_addr, host, NI_MAXHOST);
std::thread t(clientSocketHandler, clientSocket, client_ip);
t.detach();
}
Sleep(100);
}
}
int main()
{
// Initialze winsock
WSADATA wsData;
WORD ver = MAKEWORD(2, 2);
int wsOk = WSAStartup(ver, &wsData);
if (wsOk != 0)
{
std::cerr << "Can't Initialize winsock! Quitting..." << std::endl;
return 1;
}
// Create a socket
SOCKET serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
WSACleanup();
std::cerr << "Can't create a socket! Quitting..." << std::endl;
return 1;
}
// Start listening for connections
waitForConnections(serverSocket);
// Cleanup winsock
WSACleanup();
system("pause");
return 0;
}

Asynchronous socket client code and some doubts about getsockopt and error treatment

Here is the code I ended up doing for an asynchronous client:
struct addrinfo *currentAddress = NULL;
void GetAddresses(std::string hostname, int port)
{
struct addrinfo hints;
std::cout << "Get adresses for hostname " << hostname << " port " << port << std::endl;
std::memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC; /* Allow IPV4 or IPV6 */
hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
hints.ai_flags = 0;
hints.ai_protocol = 0; /* Any protocol */
std::string portStr;
portStr = std::to_string(port);
int status = getaddrinfo(hostname.c_str(), portStr.c_str(), &hints, &currentAddress);
if (status != 0)
{
std::stringstream ss;
ss << "Cannot resolve hostname " << hostname << ". Error: " << gai_strerror(status);
throw std::runtime_error(ss.str());
}
}
void StepNextAddress()
{
currentAddress = currentAddress->ai_next;
}
void Connect(const std::string& address, int port)
{
/*
* Get all addresses for connection
*/
GetAddresses(address, port);
bool success = false;
while (currentAddress != NULL)
{
int s = socket(currentAddress->ai_family, currentAddress->ai_socktype, currentAddress->ai_protocol);
if (s == -1)
{
freeaddrinfo(currentAddress);
std::stringstream ss;
ss << "Error creating socket. Out of resources.";
throw std::runtime_error(ss.str());
}
std::cout << "Socket created: " << s << std::endl;
#ifdef _WIN32
unsigned long on = 1;
ioctlsocket(s, FIONBIO, &on); // Make it non blocking
#else
fcntl(s, F_SETFL, O_NONBLOCK); Make if non blocking
#endif
/*
* Connect to socket
*/
int status = connect(s, currentAddress->ai_addr, currentAddress->ai_addrlen);
if (status < 0 && errno != EINPROGRESS)
{
freeaddrinfo(currentAddress);
std::stringstream ss;
ss << "Error connecting socket to " << address << " port " << port << ".";
throw std::runtime_error(ss.str());
}
/*
* Wait socket to get ready to select
*/
fd_set readSet, writeSet, exceptSet;
FD_ZERO(&readSet);
FD_ZERO(&writeSet);
FD_ZERO(&exceptSet);
timeval tout;
tout.tv_sec = CONNECT_TIMEOUT_SECONDS;
int retval = select (s + 1, &readSet, &writeSet, &exceptSet, &tout);
if (retval == -1)
{
freeaddrinfo(currentAddress);
std::stringstream ss;
ss << "Error selecting socket.";
throw std::runtime_error(ss.str());
}
/*
* Timeout. Try next resources
*/
if (retval == 0)
{
std::cout << "Connection timedout. Trying next resource." << std::endl;
#ifdef _WIN32
_close(s);
#else
close(s);
#endif
StepNextAddress();
continue;
}
/*
* Wait socket to be ready to work
*/
int result = 0;
socklen_t result_len = sizeof(result);
int sts = getsockopt(s, SOL_SOCKET, SO_ERROR, (char *) &result, &result_len);
if (sts < 0)
{
freeaddrinfo(currentAddress);
std::stringstream ss;
ss << "Error getting socket option.";
throw std::runtime_error(ss.str());
}
if (result != 0)
{
freeaddrinfo(currentAddress);
std::stringstream ss;
ss << "Error getting socket resources.";
throw std::runtime_error(ss.str());
}
}
freeaddrinfo(currentAddress);
std::cout << "CONNECTED!!!!!!!!!!!!" << std::endl;
}
int main()
{
Connect("test.test.com", 21);
}
I don´t understand yet the selectusage together with the getsockopt. Are they necessary or in my case select would be enough ?
In that case, the select is thowing an error... What is wrong with the select code ?
Also, what about the error treatments here... The only case I´m trying to connect the next address in list is on timeout... Does it make sense ?
To finish, comments in the code are well appreciated.

Client says it is connected to server, but server doesn't process client

I am writing a console chat program and I am learning the WinSock2 library as I write it. So far I have a working server and client, the only problem is that the server doesn't process the client, but the client says it is connected. Right now there is no functionality other than testing if the connection works which it doesn't. The server is suppose to print out a message when it has successfully accepted a client. I've been trying to figure this out but can't. Any help is greatly appreciated.
Server Header:
#pragma once
#ifndef SERVER_H
#define SERVER_H
#include <iostream>
#include <string>
#include "winsock.h"
class Server
{
public:
Server(int port);
~Server();
private:
const int port;
std::string error;
WORD wVersion;
WSADATA wsaData;
SOCKET hSocket;
bool init();
bool setupSocket();
void startServer();
void closeConnection();
};
#endif
Server:
#include "Server.h"
Server::Server(int port) : port(port), wVersion(MAKEWORD(2, 2))
{
if (init()) {
std::cout << "Server successfully setup" << std::endl << std::endl;
startServer();
} else {
std::cout << "Error: " + error << std::endl;
std::cin.get();
std::cin.get();
}
}
bool Server::init()
{
return setupSocket();
}
bool Server::setupSocket()
{
int iResult = WSAStartup(wVersion, &wsaData);
if (iResult) {
error = "Problem initializating WinSock2";
return false;
} else if (wsaData.wVersion != wVersion) {
error = "Incorrect WinSock version";
return false;
}
std::cout << "WinSock initialized" << std::endl;
sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(port);
sockAddr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
hSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET) {
error = "Problem setting up socket";
return false;
}
std::cout << "Socket setup" << std::endl;
if (bind(hSocket, (LPSOCKADDR) &sockAddr, sizeof(sockAddr)) == SOCKET_ERROR) {
error = "Problem binding socket";
return false;
}
std::cout << "Socket binded to port" << std::endl;
listen(hSocket, SOMAXCONN);
std::cout << "Server is now listening on port " << port << std::endl;
SOCKET client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (client == INVALID_SOCKET) {
error = "Problem setting up socket";
return false;
}
if (client = accept(hSocket, (SOCKADDR *)&sockAddr, NULL)) {
std::cout << "A client connected!";
}
return true;
}
void Server::startServer()
{
std::string consoleInput;
while (true) {
std::cin >> consoleInput;
std::cout << consoleInput << std::endl;
}
}
void Server::closeConnection()
{
if (hSocket) {
closesocket(hSocket);
}
WSACleanup();
}
Server::~Server()
{
closeConnection();
}
Client Header:
#pragma once
#ifndef CLIENT_H
#define CLIENT_H
#include <iostream>
#include <string>
#include "WinSock.h"
class Client
{
public:
Client(std::string name);
bool connectToServer(char ip[], int port);
~Client();
private:
std::string name;
std::string error;
WORD wVersion;
WSADATA wsaData;
SOCKET hSocket;
};
#endif
Client:
#include "Client.h"
Client::Client(std::string name) : name(name), wVersion(MAKEWORD(2,2))
{
}
bool Client::connectToServer(char ip[], int port)
{
int iResult = WSAStartup(wVersion, &wsaData);
if (iResult) {
error = "Problem initializating WinSock2";
return false;
} else if (wsaData.wVersion != wVersion) {
error = "Incorrect WinSock version";
return false;
}
std::cout << "WinSock initialized" << std::endl;
sockaddr_in sockAddr;
sockAddr.sin_family = AF_INET;
sockAddr.sin_port = htons(port);
sockAddr.sin_addr.S_un.S_addr = inet_addr(ip);
hSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (hSocket == INVALID_SOCKET) {
error = "Problem setting up socket";
return false;
}
std::cout << "Socket setup" << std::endl;
if (connect(hSocket, (SOCKADDR *)&sockAddr, sizeof(sockAddr)) == SOCKET_ERROR) {
error = "Problem connecting to server";
return false;
}
std::cout << "Connected to server!";
return true;
}
Client::~Client()
{
}