I have the following classes and functions:
#ifndef HTTP_NETWORK
#define HTTP_NETWORK
#include <string>
#include <arpa/inet.h>
//Dummy Value to be changed
#define MAXPENDING 5
class Exception {
public:
Exception(std::string message):message(message){}
std::string getMessage();
private:
std::string message;
};
class NetworkException:public Exception {
public:
NetworkException(std::string message) : Exception(message) {}
};
//A generic way to handle Network Connections
class ConnectionHandler {
public:
/**
* @return 0 Close Connection 1 do not close
*/
virtual int handle(int socketid) = 0;
};
/**
* Because the only job s to call the handle method of ConnectionHandler,
* I assume there's no need for a class.
*
* Is is used to call the handler in a std::thread.
*/
int callHandler(ConnectionHandler *c, int sockerId);
class TCPServer {
public:
TCPServer(int port, std::string address, ConnectionHandler *c);
~TCPServer();
void listen();
private:
int port;
//Socket file Descriptor
int servSock;
struct sockaddr_in ServAddr;
ConnectionHandler *c = NULL;
};
#endif
And are implemented like that:
#include"network.h"
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <iostream>
#include <cstring>
#include <string>
#include <thread>
std::string Exception::getMessage(){
return this->message;
}
TCPServer::TCPServer(int port,std::string address, ConnectionHandler *c)
:port(port){
if ((this->servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
throw NetworkException(std::string("SOCKET Error: could not create basic socket"));
}
memset(&this->ServAddr,0,sizeof(this->ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = inet_addr(address.c_str());
ServAddr.sin_port = htons(port);
if (bind(this->servSock, (struct sockaddr *) &this->ServAddr, sizeof(this->ServAddr)) < 0) {
throw NetworkException(std::string("SOCKET Error: Failed to bind a socket"));
}
if (::listen(this->servSock, MAXPENDING) < 0) {
throw NetworkException(std::string("SOCKET Error: Failed to Listen"));
}
if(c==NULL){
throw Exception("You should provice a connection Handler");
}
this->c=c;
}
void TCPServer::listen(){
struct sockaddr_in ClntAddr; /* Client address */
socklen_t clntLen = (socklen_t)sizeof(ClntAddr);
int clntSock; /* Socket descriptor for client */
for (;;) {
if ((clntSock = accept(servSock, (struct sockaddr *) &ClntAddr, &clntLen)) < 0) {
std::cout<<"Failed to fetch"<<std::endl;
}
std::cout << "Handling client: " << inet_ntoa(ClntAddr.sin_addr) << std::endl;
send(clntSock, "WELCOME", 6, 0);
std::thread handleConnectionThread(callHandler, this->c, clntSock);
// this->c->handle(clntSock);
close(clntSock);
}
}
TCPServer::~TCPServer(){
close(this->servSock);
}
int callHandler(ConnectionHandler *c, int socketId){
return c->handle(socketId);
}
But I get a segmentation fault at:
int callHandler(ConnectionHandler *c, int socketId){
return c->handle(socketId);
}
As Gdb shows:
(gdb) info args
c = 0x7fffffffdc30
socketId = 4
(gdb) continue
Continuing.
terminate called without an active exception
Command Sent:
[Thread 0x7ffff6e85700 (LWP 21845) exited]
Thread 1 "server" received signal SIGABRT, Aborted.
[Switching to Thread 0x7ffff7fd0740 (LWP 21840)]
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: Δεν υπάρχει τέτοιο αρχείο ή κατάλογος.
(gdb)
So I thought to use an std::shared_ptr for class assignment:
Therefore the TCPServer is now defined as:
class TCPServer {
public:
TCPServer(int port, std::string address, std::shared_ptr<ConnectionHandler> c);
~TCPServer();
void listen();
private:
int port;
//Socket file Descriptor
int servSock;
struct sockaddr_in ServAddr;
std::shared_ptr<ConnectionHandler> c;
};
And the callHandlerFunction functions is defined like that:
int callHandler(std::shared_ptr<ConnectionHandler> c, int sockerId);
On the constructor of the TCPServer class I initialize the shared pointer like that:
// On header file
class TCPServer {
public:
TCPServer(int port, std::string address, std::shared_ptr<ConnectionHandler> c);
~TCPServer();
void listen();
private:
int port;
//Socket file Descriptor
int servSock;
struct sockaddr_in ServAddr;
std::shared_ptr<ConnectionHandler> c;
};
//Constructor Implementation
TCPServer::TCPServer(int port,std::string address, std::shared_ptr<ConnectionHandler> c):port(port),c(c){
if ((this->servSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) {
throw NetworkException(std::string("SOCKET Error: could not create basic socket"));
}
memset(&this->ServAddr,0,sizeof(this->ServAddr));
ServAddr.sin_family = AF_INET;
ServAddr.sin_addr.s_addr = inet_addr(address.c_str());
ServAddr.sin_port = htons(port);
if (bind(this->servSock, (struct sockaddr *) &this->ServAddr, sizeof(this->ServAddr)) < 0) {
throw NetworkException(std::string("SOCKET Error: Failed to bind a socket"));
}
if (::listen(this->servSock, MAXPENDING) < 0) {
throw NetworkException(std::string("SOCKET Error: Failed to Listen"));
}
}
Whilst the function callHandler is defined and implemented like that:
int callHandler(std::shared_ptr<ConnectionHandler> c, int sockerId);
int callHandler(std::shared_ptr<ConnectionHandler> c, int socketId){
return c->handle(socketId);
}
A sample code of TCP server initialization is:
#include<iostream>
#include<string>
#include<memory>
#include "socket/network.h"
class SimpleCommandHandler:: public ConnectionHandler{
public:
int handle(int socketid){
// Handle connection here
}
}
int main(){
try {
std::shared_ptr<ConnectionHandler> c (new SimpleCommandHandler());
TCPServer server(7070, "127.0.0.1", c);
server.listen();
} catch(Exception e) {
std::cout<< e.getMessage();
return -1;
}
return 0;
}
But on gdb I get the following error:
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Handling client: 127.0.0.1
[New Thread 0x7ffff6e85700 (LWP 23889)]
terminate called without an active exception
Thread 1 "server" received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
51 ../sysdeps/unix/sysv/linux/raise.c: Δεν υπάρχει τέτοιο αρχείο ή κατάλογος.
SO do you know why I get the ABORT error?
Aucun commentaire:
Enregistrer un commentaire