SDL_Net Socket error on creation - c++

I'm trying to create a socket for my SDL server.
Problem is that I get an access violation crash because my socket called server is unable to open itself properly.
My class:
#pragma once
#include <SDL_net.h>
#include <thread>
#include <vector>
#include <string>
#include <iostream>
using namespace std;
const Uint16 SERVER_PORT = 1234;
const int TICKS_PER_SECOND = 1000;
const int REQUIRED_PLAYERS = 1;
class ServerTCP {
private:
//Thread data
thread *threadListen;
bool threadExit;
//Server data
IPaddress serverIP;
TCPsocket server;
vector <string> feedback;
//Client data
vector <TCPsocket> clients;
vector <string> events;
static void threadLoop(ServerTCP *self);
public:
ServerTCP();
~ServerTCP();
};
Source:
#include "ServerTCP.h"
ServerTCP::ServerTCP() {
printf("Starting server...\n");
if (SDLNet_ResolveHost(&serverIP, NULL, SERVER_PORT) == -1) {
printf("SDLNet_ResolveHost: %s\n", SDLNet_GetError());
}
server = SDLNet_TCP_Open(&serverIP);
if (!server) {
printf("SDLNet_TCP_Open: %s\n", SDLNet_GetError());
}
threadExit = false;
threadListen = new thread(&ServerTCP::threadLoop, this);
}
ServerTCP::~ServerTCP() {
printf("Shutting down server...\n");
threadExit = true;
threadListen->join();
for (int i = 0; i < clients.size(); i++) {
string warning = "Server has shut down, you was disconnected!\n";
SDLNet_TCP_Send(clients[i], warning.c_str(), warning.size());
SDLNet_TCP_Close(clients[i]);
}
SDLNet_TCP_Close(server);
}
void ServerTCP::threadLoop(ServerTCP *self) {
printf("Waiting for players...\n");
TCPsocket newClient;
//Run thread until orderered to stop
while (!self->threadExit) {
//Look for new clients
newClient = SDLNet_TCP_Accept(self->server);
if (newClient) {
self->clients.push_back(newClient);
string warning = "You have connected to the server!\n";
SDLNet_TCP_Send(newClient, warning.c_str(), warning.size());
printf("Player %i has connected!\n", self->clients.size());
}
if (self->clients.size() >= REQUIRED_PLAYERS) {
for (int i = 0; i < REQUIRED_PLAYERS; i++) {
string warning = "You found an opponent!\n";
SDLNet_TCP_Send(self->clients[i], warning.c_str(), warning.size());
SDLNet_TCP_Close(self->clients[i]);
}
}
}
}
Output:
Starting server...
SDLNet_TCP_Open: Couldn't create socket

Never mind, I forgot I had the SDLNet_Init function in my sub class i removed in the server file.

Related

SFML UdpSockets not sending/receiving without error?

I am working on a primitive multiplayer battleship game for my CS class. I am able to get it running and send out information over LAN. To test whether this communication is working, I created a loop with a listener function that will stop when the packet is verified to have been received from the other computer's listen thread.
When I do this, it seems to send the packet, but the loop keeps running forever without any errors and without receiving confirmation that the packets were received by the other computer. Do you have any idea what might be happening?
//SFML headers
#include <SFML/Network.hpp>
//standard headers
#include <vector>
#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <exception>
std::atomic_bool running;
unsigned short port;
//Functions for threading
void startListen(sf::UdpSocket *sock, std::atomic_bool *r, sf::IpAddress *ip)
{
std::cout<<"Listener started"<<std::endl;
while(*r == true)
{
sf::sleep(sf::microseconds(50));
std::cout<<"Wait done"<<std::endl;
std::cout<<std::to_string(port)<<" port from the listen thread."<<std::endl;
sf::IpAddress sender;
sf::Packet p;
std::cout<<"tryna receive packet"<<std::endl;
if (sock->receive(p, sender, port) != sf::Socket::Done)
{
std::cout<<"Attempt at packet retrieval but packet retrieval failed! Error code 23./nPlease contact developer at mldevelopingstudios#gmail.com to report this failure."<<std::endl;
}
std::cout<<"Packet received!"<<std::endl;
std::string type;
p >> type;
std::cout<<"packet recieved, type: "<<type<<std::endl;
}
}
int main()
{
port = 4343;
sf::UdpSocket sock;
sf::UdpSocket recSock;
if (recSock.bind(port) != sf::Socket::Done)
{
std::cout<<"Whoops we crashed!!!!!!!!!!";
return 0;
}
//sock.unbind();
std::string ip;
sf::IpAddress IP1 = sf::IpAddress::getLocalAddress();
sf::String ip11 = IP1.toString();
std::cout<<"You LAN IP is: "<<ip11.toAnsiString()<<std::endl;
std::cout<<"Please enter the target IP address of the computer you'd like to play with."<<std::endl;
std::string iiii;
std::cin>>iiii;
sf::String o(iiii);
ip = o;
sf::IpAddress IP(ip);
std::thread listen(startListen, &recSock, &running, &IP);
listen.detach();
std::cout<<"Connection check"<<std::endl;
running = true;
std::string name;
std::cout<<"Name? "<<std::endl;
std::cin>>name;
while(running == true)
{
std::string mess = name;
sf::Packet packk;
std::string temp;
std::cout<<"Message: "<<std::endl;
std::cin>>temp;
if(temp == "!!STOP!!")
{
running = false;
}
else
{
mess = mess+ ": "+ temp;
packk<<mess;
if(sock.send(packk, IP, port)!= sf::Socket::Done)
{
std::cout<<"Sending error in test loop!!!!"<<std::endl;
}
}
}
recSock.unbind();
return 0;
}
Any help is greatly appreciated,
thank you and have a nice day.
EDIT: New code is the "minimalist code" and still no errors but nothing is received on either end.
EDIT: Added code to show whats happening
//SFML headers
#include <SFML/Network.hpp>
//standard headers
#include <vector>
#include <iostream>
#include <string>
#include <thread>
#include <atomic>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <exception>
std::atomic_bool running;
unsigned short port;
//Functions for threading
void startListen(sf::UdpSocket *sock, std::atomic_bool *r, sf::IpAddress *ip)
{
std::cout<<"Listener started"<<std::endl;
while(*r == true)
{
unsigned short por = 4343;
sock->setBlocking(false);
std::cout<<std::to_string(por)<<" port from the listen thread."<<std::endl;
sf::IpAddress sender;
sf::Packet p;
std::cout<<"tryna receive packet"<<std::endl;
sf::Socket::Status stat = sock->receive(p, sender, por);
switch(stat)
{
case(sf::Socket::Done):
{
std::cout<<"Packet receiving completed!"<<std::endl;
std::cout<<"Packet received!"<<std::endl;
std::string type;
p >> type;
std::cout<<"packet recieved, type: "<<type<<std::endl;
break;
}
case(sf::Socket::NotReady):
std::cout<<"Socket not ready to received!"<<std::endl;
break;
case(sf::Socket::Partial):
std::cout<<"socket Kinda received?"<<std::endl;
break;
case(sf::Socket::Disconnected):
std::cout<<"Socket disconnected!"<<std::endl;
break;
case(sf::Socket::Error):
std::cout<<"Errorrrrrrrrrrrrrrrrrrr"<<std::endl;
break;
default:
std::cout<<"Oh noooooo"<<std::endl;
break;
}
}
}
int main()
{
port = 4343;
sf::UdpSocket sock;
sf::UdpSocket recSock;
if (recSock.bind(port) != sf::Socket::Done)
{
std::cout<<"Whoops we crashed!!!!!!!!!!";
return 0;
}
std::string ip;
sf::IpAddress IP1 = sf::IpAddress::getLocalAddress();
sf::String ip11 = IP1.toString();
std::cout<<"You LAN IP is: "<<ip11.toAnsiString()<<std::endl;
std::cout<<"Please enter the target IP address of the computer you'd like to play with."<<std::endl;
std::string iiii;
std::cin>>iiii;
sf::String o(iiii);
ip = o;
sf::IpAddress IP(ip);
std::thread listen(startListen, &recSock, &running, &IP);
listen.detach();
std::cout<<"Connection check"<<std::endl;
running = true;
std::string name;
std::cout<<"Name? "<<std::endl;
std::cin>>name;
while(running == true)
{
std::string mess = name;
sf::Packet packk;
std::string temp;
std::cout<<"Message: "<<std::endl;
std::cin>>temp;
if(temp == "!!STOP!!")
{
running = false;
}
else
{
mess = mess+ ": "+ temp;
packk<<mess;
sf::Socket::Status stat = sock.send(packk, IP, port);
switch(stat)
{
case(sf::Socket::Done):
std::cout<<"Packet Sending completed!"<<std::endl;
break;
case(sf::Socket::NotReady):
std::cout<<"Socket not ready to send!"<<std::endl;
break;
case(sf::Socket::Partial):
std::cout<<"socket Kinda sent?"<<std::endl;
break;
case(sf::Socket::Disconnected):
std::cout<<"Socket disconnected!"<<std::endl;
break;
case(sf::Socket::Error):
std::cout<<"Errorrrrrrrrrrrrrrrrrrr"<<std::endl;
break;
default:
std::cout<<"Oh noooooo"<<std::endl;
}
}
}
recSock.unbind();
return 0;
}
The socket on the receiving end is constantly reporting sf::Socket::NotReady
The sending reports sf::Socket::Done
Nothing is received on either end, when blocking is set to true or false
I somehow solved the problem through repetitive testing. I believe my error came from the operator overloads to load my classes into the packet. Or it was my IP entry. One of the two, fixed it. Sadly I did not document the fix though I am sure that was one of the two issues.

C++ multi client chat using TCP socket

Im trying to do multi client chat in c++ using TCP socket.
i have download the source of the socket implementation from this site.
The problem is when i try to send message to the server from the client,
the "ecko" that i recive from the server is endless string of spaces.
i tried to debug the client code, the client read the input properly.
In the first few message the server send back to the client his message,
but after few messages the client get back endless spaces.
i tried to use memset to nullify(put zero in all the array), but its making it worse, the server dont recive messages at all.
Would appreciate help (:
This is the server side:
#include "PracticalSocket.h"
#include <stdio.h>
#include <process.h>
#include <Windows.h>
using namespace std;
#pragma comment(lib,"ws2_32.lib")
TCPSocket* MyClients[20];
int ClientCount = 0;
void connectCLient(void* pValue){
int nI,Flag;
char st[1024];
//memset(st,0,1024); // doing problems
TCPSocket* pServerClient = (TCPSocket*)pValue;
MyClients[ClientCount] = pServerClient;
ClientCount++;
try{
while (true)
{
Flag = pServerClient->recv(st,strlen(st));
if(Flag>1){
printf("%s\n",st);
for(nI = 0; nI< ClientCount ; nI++){
MyClients[nI]->send(st,strlen(st)+1);
}
}
}
}
catch(...){
puts("one client lefttt");
}
}
int main(int argc, char* argv[])
{
TCPServerSocket* pServer = new TCPServerSocket(8546);
int nClientCounter = 0;
printf("Start TCP Server ... on Port %d\n", 8546);
try{
while(true)
{
printf("Wait for new TCP Clients ... \n");
TCPSocket* pClient = pServer->accept();
_beginthread(connectCLient,0,(void*)pClient);
printf("Client %d Connected ... \n", ++nClientCounter);
}
}
catch(...){
puts("one client left");
}
return 0;
}
This is the Client side:
#include "PracticalSocket.h"
#include <stdio.h>
#include <process.h>
#include <Windows.h>
using namespace std;
#pragma comment (lib, "ws2_32.lib")
void ReciveMessages(void * pValue ){
char recvM[1024];
TCPSocket* pClient = (TCPSocket*)pValue;
while(true){
pClient->recv(recvM,strlen(recvM));
printf("%s\n",recvM);
}
}
int main(int argc, char* argv[])
{
try
{
TCPSocket * cClient = new TCPSocket();
cClient->connect("127.0.0.1",8546);
_beginthread(ReciveMessages,0,(void*)cClient);
char st[1024];
memset(st,0,1024);
while(true)
{
printf("Press Text -->");
fgets(st, sizeof st, stdin);
cClient->send(st,strlen(st)+2);
}
}
catch(...)
{
printf("Socket Error..!");
system("pause");//run cmd comment - stop the system
}
return 0;
}
There are a few mistakes in the code:
MyClients[ClientCount] = pServerClient;
ClientCount++;
Since the above happens in different threads, ClientCount++ is non-atomic and causes race conditions. Make ClientCount atomic or do that in one server thread.
In:
Flag = pServerClient->recv(st,strlen(st));
if(Flag>1) {
printf("%s\n",st);
for(nI = 0; nI< ClientCount ; nI++)
MyClients[nI]->send(st,strlen(st)+1);
st doesn't end with \0, because it can be a partial read, so that strlen(st) returns wrong results. Fix:
ssize_t received = pServerClient->recv(st, sizeof st - 1);
if(received > 0) {
st[received] = 0; // Zero-terminate.
printf("%s\n", st);
for(nI = 0; nI< ClientCount ; nI++)
MyClients[nI]->send(st, received);
Similar issue:
pClient->recv(recvM,strlen(recvM));
printf("%s\n",recvM);
Fix:
ssize_t received = pClient->recv(recvM, sizeof recvM - 1);
if(received > 0) {
recvM[received] = 0;
printf("%s\n",recvM);
}
And in:
cClient->send(st,strlen(st)+2);
No point in sending the zero terminator:
cClient->send(st, strlen(st));
TCP is a stream protocol which means that send and recv may send/receive partial data and there are no message boundaries. You may like to delimit your messages.

How to use the libuv to accept the tcp connection with multi-thread?

I write a C++ dome of tcp server with the libuv. When I check the cpu performance, I found the dome is a single thread running, how can I implement it with multi-thread?
Currently, the dome can hanlde 100,000+ tcp request per second, it can only eat 1 CPU.
Code:
#include <iostream>
#include <atomic>
#include "uv.h"
#include <thread>
#include <mutex>
#include <map>
using namespace std;
auto loop = uv_default_loop();
struct sockaddr_in addr;
typedef struct {
uv_write_t req;
uv_buf_t buf;
} write_req_t;
typedef struct {
uv_stream_t* client;
uv_alloc_cb alloc_cb;
uv_read_cb read_cb;
} begin_read_req;
void alloc_buffer(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) {
buf->base = (char*)malloc(suggested_size);
buf->len = suggested_size;
}
void free_write_req(uv_write_t *req) {
write_req_t *wr = (write_req_t*)req;
free(wr->buf.base);
free(wr);
}
void echo_write(uv_write_t *req, int status) {
if (status) {
fprintf(stderr, "Write error %s\n", uv_strerror(status));
}
free_write_req(req);
}
void echo_read(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) {
if (nread > 0) {
auto req = (write_req_t*)malloc(sizeof(write_req_t));
auto *aaa = (char*)malloc(5);
aaa[0] = '+';
aaa[1] = 'O';
aaa[2] = 'K';
aaa[3] = '\r';
aaa[4] = '\n';
req->buf = uv_buf_init(aaa, 5);
uv_write((uv_write_t*)req, client, &req->buf, 1, echo_write);
}
if (nread < 0) {
if (nread != UV_EOF)
fprintf(stderr, "Read error %s\n", uv_err_name(static_cast<unsigned int>(nread)));
uv_close((uv_handle_t*)client, nullptr);
}
free(buf->base);
}
void acceptClientRead(uv_work_t *req) {
begin_read_req *data = (begin_read_req *)req->data;
uv_read_start(data->client, data->alloc_cb, data->read_cb);
}
void on_new_connection(uv_stream_t *server, int status) {
if (status < 0) {
cout << "New connection error:" << uv_strerror(status);
return;
}
uv_tcp_t *client = (uv_tcp_t *)malloc(sizeof(uv_tcp_t));
uv_tcp_init(loop, client);
uv_work_t *req = (uv_work_t *)malloc(sizeof(uv_work_t));
begin_read_req *read_req = (begin_read_req *)malloc(sizeof(begin_read_req));
read_req->client = (uv_stream_t *)client;
read_req->read_cb = echo_read;
read_req->alloc_cb = alloc_buffer;
req->data = read_req;
if (uv_accept(server, (uv_stream_t *)client) == 0) {
uv_read_start((uv_stream_t *)client, alloc_buffer, echo_read);
// uv_queue_work(workloop[0], req, acceptClientRead, nullptr);
}
else {
uv_close((uv_handle_t *)client, nullptr);
}
}
void timer_callback(uv_timer_t* handle) {
cout << std::this_thread::get_id() << "---------" << "hello" << endl;
}
int main() {
uv_tcp_t server{};
uv_tcp_init(loop, &server);
uv_ip4_addr("0.0.0.0", 8790, &addr);
uv_tcp_bind(&server, (const struct sockaddr *) &addr, 0);
uv_listen((uv_stream_t *)&server, 511, on_new_connection);
uv_run(loop, UV_RUN_DEFAULT);
return 0;
}
Of course, I can make the write step asynchronous in the method "echo_read", but I didn't do anything before the write, can I make the demo multi-thread in another way to improve the throughput?

Attempting to reference a deleted function inside xmemory0 on threaded sockets class

I'm trying to finish this threaded sockets class. This is what I've got so far:
#pragma once
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <atomic>
#include <thread>
#include <vector>
#pragma comment(lib, "Ws2_32.lib")
//---------------------------------------------------CLASS
class AsyncSockets
{
public:
int StartSockets(int, void(*)(SOCKET, sockaddr*, int, std::atomic<bool>&));
static const int FAIL_SUCCESS, FAIL_INIT_WS, FAIL_BIND_SOCKET, FAIL_ASYNCSELECT, FAIL_LISTEN, FAIL_ACCEPT;
bool StopSockets();
private:
/*static*/ void(*Functiane)(SOCKET, sockaddr*, int, std::atomic<bool>&);
struct RunThread {
std::thread Thread;
std::atomic<bool> Running = true;
};
void AcceptLoop();
SOCKET Socket; std::atomic<bool> running = false;
std::vector<AsyncSockets::RunThread>ThreadList;
void StartFunc(SOCKET, sockaddr*, int, int);
std::thread loopaccepter;
std::thread deleteInvalid;
};
//-------------------------------------STARTFUNC---PRIVATE
void AsyncSockets::StartFunc(SOCKET socketa, sockaddr* sockaddra, int sockaddrinfolena, int BoolIndex) {
if (socketa != INVALID_SOCKET) {
(*Functiane)(socketa, sockaddra, sockaddrinfolena, ThreadList[BoolIndex].Running);
}else{
closesocket(socketa); ThreadList[BoolIndex].Running = false; return;
}
closesocket(socketa);
ThreadList[BoolIndex].Running = false;
return;
}
//------------------------------------ACCEPTLOOP---PRIVATE
void AsyncSockets::AcceptLoop() {
while (true) {
struct sockaddr *AddressInfo = NULL; int addrinfoLen;
if (running) {
int temp = ThreadList.size();
for (int i = 0; i < temp; i++){
if (i != temp - 1) {
if (!ThreadList[i].Running){
if (ThreadList[i].Thread.joinable()) ThreadList[i].Thread.join();
ThreadList[i].Running = true; ThreadList[i].Thread = std::thread(&AsyncSockets::StartFunc, this, accept(Socket, AddressInfo, &addrinfoLen), AddressInfo, addrinfoLen, i); }
}else{
if (!ThreadList[i].Running) {
if (ThreadList[i].Thread.joinable()) ThreadList[i].Thread.join();
ThreadList[i].Running = true; ThreadList[i].Thread = std::thread(&AsyncSockets::StartFunc, this, accept(Socket, AddressInfo, &addrinfoLen), AddressInfo, addrinfoLen, i);}
else { ThreadList.push_back({ std::thread(&AsyncSockets::StartFunc, this, accept(Socket, AddressInfo, &addrinfoLen), AddressInfo, addrinfoLen, i + 1), true });}
}
}
}else return;
}
}
//-----------------------------------STARTSOCKETS---PUBLIC
int AsyncSockets::StartSockets(int port, void(*functian)(SOCKET, sockaddr*, int, std::atomic<bool>&)) {
//DeclaringShiet
int recvbuflen = 512;
//InitWinsock
WSADATA WsaDat;
int nResult = WSAStartup(MAKEWORD(2, 2), &WsaDat);
if (nResult != 0)
{
return FAIL_INIT_WS;
}
//BuildAddr
SOCKADDR_IN SockAddr;
SockAddr.sin_port = htons(port);
SockAddr.sin_family = AF_INET;
SockAddr.sin_addr.s_addr = htonl(INADDR_ANY);
//BindSocket
if (bind(Socket, (LPSOCKADDR)&SockAddr, sizeof(SockAddr)) == SOCKET_ERROR)
{
return FAIL_BIND_SOCKET;
}
//StartListening
if (listen(Socket, 10) == SOCKET_ERROR)
{
return FAIL_LISTEN;
}
//StartAccepting
running = true;
Functiane = (*functian);
loopaccepter = std::thread(&AsyncSockets::AcceptLoop, this);
}
//------------------------------------STOPSOCKETS---PUBLIC
bool AsyncSockets::StopSockets() {
running = false;
loopaccepter.join();
closesocket(Socket);
for (unsigned int i = 0; i < ThreadList.size(); i++)ThreadList[i].Running = false;
for (unsigned int i = 0; i < ThreadList.size(); i++)if(ThreadList[i].Thread.joinable())ThreadList[i].Thread.join();
return true;
}
//------------------------------------ERRORCONSTS---PUBLIC
#pragma region DeclaringErrorConsts
const int
AsyncSockets::FAIL_SUCCESS = 0x0,
AsyncSockets::FAIL_INIT_WS = 0x1,
AsyncSockets::FAIL_BIND_SOCKET = 0x2,
AsyncSockets::FAIL_LISTEN = 0x3,
AsyncSockets::FAIL_ACCEPT = 0x4;
#pragma endregion
So, as you may have noticed, I'm trying to do this with std::thread, vectors, and winsock. And the point is to have a function as an argument for StartSockets, that'll do all the sending, receiving, and processing.
Thread objects will be stored in a vector of the RunThread type, that contains an atomic bool that tells whether or not the thread is/should be running, as well as the thread object.
My problem is I'm getting an
'AsyncSockets::RunThread::RunThread(const AsyncSockets::RunThread &)': attempting to reference a deleted function
in
xmemory0 (line 840)
(c:\program files (x86)\microsoft visual
studio\2017\community\vc\tools\msvc\14.10.24728\include\xmemory0)
I have no idea why, and since RunThread is a struct and not a function, along with the fact that RunThread::RunThread doesn't make sense, I don't, at all, understand what the profanity is going on. In case it can help any further, I'm on VS 2017 RC on windows 10, win32 console application.
What am I doing wrong?
Thank you.

C++ moving class with thread inside

i'm writing server with will handle client connection, but i have problem moving class with thread inside to vector, i know if i had only thread i can move it to vector with std::move(), but here i have thread inside a class and i'm getting a lot of errors because thread is non-movable object.
Core.cpp:
#define OS_LINUX
#include <iostream>
#include <vector>
#include <string>
#include <thread>
#include <csignal>
#include <cstdlib>
#include <TCPServer/TCPServer.h>
#include <TCPServer/TCPServerConnection.h>
#include <ProcessManip/ProcessManip.h>
#include <Log/Log.h>
#include "ConnectionHandler.h"
//Global
bool TERMNINATE = false;//If true loops must end
const int PORT = 8822;
//Proto
void terminate(int sig);
void receive_message(ConnectionHandler *handler,string message);
using namespace std;
int main(int argc,char *argv[])
{
//Add Terminate handler
signal(SIGINT,terminate);
//Load configuration
Log::logDebug("Starting ...");
//Init
vector<ConnectionHandler> connections;
//Init modules
//Main
Log::logDebug("Running");
TCPServer server;
if(!server._bind(PORT))
return 1;
if(!server._listen())
return 2;
ProcessManip::cleanProcess(); /* Clean dead processes */
server.setBlocking(false);/* accept returns invalid socket if no connection */
Log::logDebug("Listening ...");
while(!TERMNINATE)
{
TCPServerConnection conn = server._accept();
if(!conn.isValid())
continue;
Log::logDebug((string)"Got connection from: "+conn.getAddress());/* Print IP address of client */
ConnectionHandler ch(&TERMNINATE,std::move(conn));
ch.setCallback(receive_message);
ch.start();
connections.push_back(std::move(ch)); //here is problem
/*connections.push_back(ConnectionHandler(&TERMNINATE,conn)); /* Add it to vector */
/*connections.back().setCallback(receive_message);
connections.back().start();*/
Log::logDebug("Connection added to vector");
}
server.setBlocking(true);
//Dispose
Log::logDebug("Stopping ...");
/*for(auto it = connections.begin();it!=connections.end();)
{
Log::logDebug((string)"Closed connection with: "+(*it).getConnection().getAddress());/* Print IP address of client */
//(*it).close(); /* Close connetion */
// it = connections.erase(it); /* Delete ConnectionHandler from vector */
// }
server._close();
Log::logDebug("Closed");
return 0;
}
void terminate(int sig)
{
//Change global value to true
TERMNINATE = true;
}
void receive_message(ConnectionHandler *handler,string message)
{
Log::logDebug((string)"Message ("+handler->getConnection().getAddress()+") : "+message);
}
ConnectionHandler.h
#ifndef EXT_CONNECTIONHANDLER
#define EXT_CONNECTIONHANDLER
#include <TCPServer/TCPServerConnection.h>
#include <thread>
#include <string>
#include <iostream>
#include <functional>
using namespace std;
class ConnectionHandler
{
public:
ConnectionHandler(bool *pMainTerminate,TCPServerConnection pConnection);
ConnectionHandler(TCPServerConnection pConnection);
~ConnectionHandler();
void start(); /* Start listening */
void stop(); /* Stop listening */
void close(); /* Stops listening + close connection */
void setConnection(TCPServerConnection pConnection);
TCPServerConnection getConnection();
void setCallback(function<void(ConnectionHandler*,string)> pFunction);
private:
bool *mainTerminate = NULL;
bool handler_terminate = false;
short status = 0;
TCPServerConnection connection;
bool needTerminate();
void run();
void waitForEnd();
function<void(ConnectionHandler*,string)> callback = NULL;
std::thread m_thread;
};
#endif
ConnectionHandler.cpp
#include "ConnectionHandler.h"
ConnectionHandler::ConnectionHandler(bool *pMainTerminate,TCPServerConnection pConnection)
{
this->mainTerminate = pMainTerminate;
this->connection = pConnection;
}
ConnectionHandler::ConnectionHandler(TCPServerConnection pConnection)
{
this->mainTerminate = NULL;
this->connection = pConnection;
}
ConnectionHandler::~ConnectionHandler()
{
this->close();
}
void ConnectionHandler::start()
{
m_thread = std::thread(&ConnectionHandler::run, this);
this->status = 1;
}
void ConnectionHandler::waitForEnd()
{
if(this->m_thread.joinable())
this->m_thread.join();
}
bool ConnectionHandler::needTerminate()
{
if(mainTerminate!=NULL)
return this->handler_terminate||*(this->mainTerminate);
else
return this->handler_terminate;
}
void ConnectionHandler::run()
{
string message = "";
string tmp = "";
this->connection.setBlocking(false); // So we can terminate any time
while(!this->needTerminate())
{
message = this->connection._receive();
if(message!="")
{
do
{
tmp = this->connection._receive();
message+=tmp;
}while(tmp!=""); /* If we get longer message than we can grab at one time */
this->connection._send(message); /* TODO Remove */
if(this->callback!=NULL)
this->callback(this,message);
message = "";
}
}
this->connection.setBlocking(true);
}
void ConnectionHandler::stop()
{
this->handler_terminate = true; /* Signals thread to stop */
this->waitForEnd();
this->status = 2;
}
void ConnectionHandler::close()
{
this->stop();
this->connection._close(); /* Close connection */
this->status = 3;
}
TCPServerConnection ConnectionHandler::getConnection()
{
return this->connection;
}
void ConnectionHandler::setConnection(TCPServerConnection pConnection)
{
this->connection = pConnection;
}
void ConnectionHandler::setCallback(function<void(ConnectionHandler*,string)> pFunction)
{
this->callback = pFunction;
}
Because this class violates the Rule Of Three, even if the std::thread issue gets addressed, other problems will likely appear; most likely taking the form of mysterious runtime bugs.
The compilation issue with std::thread is not the problem, it's merely a symptom of the real problem: this class should not be moved or copied. This class should only be new-constructed, then stuffed into a std::shared_ptr (or a reasonable facsimile) and stay there until it gets destroyed. Only the std::shared_ptr should be passed around, stuffed into a vector, etc...