CPP=g++ -std=c++14
all:server client
echo "ok"
server: server.cpp config.h socket.o
${CPP} server.cpp socket.o -o server
client: client.cpp config.h socket.o
${CPP} client.cpp socket.o -o client
socket.o: socket.h socket.cpp
${CPP} -c socket.cpp -o socket.o
#pragma once
#include <cstdint>
#include <string>
#include <functional>
class Socket
{
public:
Socket(const std::string & _ip = "0.0.0.0",
uint16_t _port=8080,
bool verbose=false);
~Socket();
void serve(std::function<bool(Socket*)> handler);
bool isVerbose() const;
void connect();
void read(char * buff, size_t len);
void write(const char * buff, size_t len);
uint64_t read_uint64();
uint8_t read_uint8();
void write_uint64(const uint64_t & value);
void write_uint8(const uint8_t & value);
private:
int sockfd;
int connfd;
uint16_t port;
struct sockaddr_in * servaddr;
std::string ip;
bool verbose;
};
#include "socket.h"
#include <stdexcept>
#include <iostream>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
Socket::Socket(const std::string & _ip, uint16_t _port, bool _verbose)
: ip(_ip), port(_port), verbose(_verbose)
{
socklen_t len;
servaddr = nullptr;
// socket create and verification
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1)
{
throw std::runtime_error("socket creation failed");
}
else
{
if(verbose)
{
std::cout << "Socket successfully created" << std::endl;
}
}
servaddr = new sockaddr_in;
bzero(servaddr, sizeof(struct sockaddr_in));
// assign IP, PORT
servaddr->sin_family = AF_INET;
if(ip == "0.0.0.0")
{
servaddr->sin_addr.s_addr = htonl(INADDR_ANY);
}
else
{
servaddr->sin_addr.s_addr = inet_addr(ip.c_str());
}
servaddr->sin_port = htons(port);
}
Socket::~Socket()
{
// After chatting close the socket
close(sockfd);
if(servaddr)
{
delete servaddr;
}
}
bool Socket::isVerbose() const
{
return verbose;
}
void Socket::serve(std::function<bool(Socket*)> handler)
{
// Binding newly created socket to given IP and verification
if ((bind(sockfd, (struct sockaddr*)servaddr, sizeof(sockaddr_in))) != 0)
{
throw std::runtime_error("socket bind failed");
}
else
{
if(verbose)
{
std::cout << "socket successfully binded" << std::endl;
}
}
// Now server is ready to listen and verification
if ((listen(sockfd, 5)) != 0)
{
throw std::runtime_error("Listen failed");
}
else
{
if(verbose)
{
std::cout << "Server listening" << std::endl;
}
}
struct sockaddr_in cli_addr;
socklen_t clilen = sizeof(cli_addr);
bool running = true;
while(running)
{
connfd = accept(sockfd,
(struct sockaddr *) &cli_addr,
&clilen);
if (connfd < 0)
{
throw std::runtime_error("ERROR on accept");
}
running = handler(this);
close(connfd);
}
}
void Socket::connect()
{
if(::connect(sockfd,(struct sockaddr *)servaddr, sizeof(sockaddr_in)) < 0)
{
throw std::runtime_error("ERROR connecting");
}
connfd = sockfd;
}
void Socket::read(char * buff, size_t len)
{
::read(connfd, buff, len);
}
void Socket::write(const char * buff, size_t len)
{
::write(connfd, buff, len);
}
char * Socket::read()
{
std::size_t len = this->read_uint64();
char * ch = new char[len];
this->read(ch, len);
return ch;
}
void Socket::write(const char * str)
{
uint64_t len = strlen(str) + 1;
this->write_uint64(len);
this->write(str, len);
}
uint64_t Socket::read_uint64()
{
char buff[8];
this->read(buff, 8);
uint64_t res = 0;
for(int i = 0; i < 8; i++)
{
res += uint64_t(buff[i]) << 8*(7-i);
}
return res;
}
uint8_t Socket::read_uint8()
{
char buff;
this->read(&buff, 1);
return (uint8_t)buff;
}
void Socket::write_uint64(const uint64_t & value)
{
char buff[8];
for(int i = 0; i < 8; i++)
{
buff[i] = uint8_t((value >> 8*(7 - i)) & 0xFF);
}
this->write(buff, 8);
}
void Socket::write_uint8(const uint8_t & value)
{
this->write((const char*)&value, 1);
}
#pragma once
#define BUFFER_SIZE 80
#include "socket.h"
#include "config.h"
#include <string.h>
#include <iostream>
bool handler(Socket * sock)
{
char buff[BUFFER_SIZE];
bool connected = true;
bool keep_listening = true;
while(connected)
{
bzero(buff, BUFFER_SIZE);
sock->read(buff, sizeof(buff));
buff[BUFFER_SIZE-1] = 0;
std::cout << "from client " << buff << std::endl;
if (strcmp("exit", buff) == 0)
{
if(sock->isVerbose())
{
std::cout << "exit" << std::endl;
}
connected = false;
keep_listening = false;
sock->write("disconnect", strlen("disconnect") + 1);
}
else if (strcmp("disconnect", buff) == 0)
{
connected = false;
keep_listening = true;
sock->write("disconnect", strlen("disconnect") + 1);
if(sock->isVerbose())
{
std::cout << "disconnect" << std::endl;
}
}
else
{
printf(">");
bzero(buff, BUFFER_SIZE);
for(int i =0; i < BUFFER_SIZE-1; i++)
{
char ch = getchar();
if(ch != '\n')
{
buff[i] = ch;
}
else
{
break;
}
}
sock->write(buff, sizeof(buff));
}
}
return keep_listening;
}
int main(int argc, const char ** argv)
{
int port = 8080;
std::string ipaddr = "0.0.0.0";
bool printHelp = false;
bool argError = false;
bool verbose = false;
for(int i = 0; i < argc; ++i)
{
std::string arg(argv[i]);
if(arg == "--port" || arg == "-p")
{
++i;
if(i < argc)
{
try
{
port = stoi(std::string(argv[i]));
}
catch(std::exception ex)
{
std::cerr << "invalid port number " << argv[i] << std::endl;
argError = true;
}
}
else
{
std::cerr << "missing argument " << argv[i] << " PORT" << std::endl;
argError = true;
}
}
if(arg == "--addr" || arg == "-a")
{
++i;
if(i < argc)
{
ipaddr = argv[i];
}
else
{
std::cerr << "missing argument " << argv[i] << " IPv4" << std::endl;
argError = true;
}
}
if(arg == "--help" || arg == "-h")
{
printHelp = true;
}
if(arg == "--verbose" || arg == "-v")
{
verbose = true;
}
}
if(printHelp || argError)
{
std::cout << argv[0] << "[OPTIONS]" << std::endl;
std::cout << "OPTIONS:" << std::endl;
std::cout << "--port|-p PORT" << std::endl;
std::cout << "--addr|-a IPv4" << std::endl;
std::cout << "--verbose|-v" << std::endl;
std::cout << "--help|-h" << std::endl;
if(argError)
{
return 1;
}
else
{
return 0;
}
}
try
{
Socket sock(ipaddr, port, verbose);
sock.serve(handler);
}
catch(const std::exception & ex)
{
std::cerr << "server failed:" << ex.what() << std::endl;
return 8;
}
return 0;
}
#include "socket.h"
#include "config.h"
#include <iostream>
#include <string>
#include <string.h>
#include <stdlib.h>
void conversation(const std::string ipaddr,
int port,
bool verbose)
{
Socket sock(ipaddr, port, verbose);
sock.connect();
char buff[BUFFER_SIZE];
int n;
bool connected = true;
while(connected)
{
bzero(buff, sizeof(buff));
std::cout << ">";
for(int i =0; i < BUFFER_SIZE-1; i++)
{
char ch = getchar();
if(ch != '\n')
{
buff[i] = ch;
}
else
{
break;
}
}
sock.write(buff, sizeof(buff));
bzero(buff, sizeof(buff));
sock.read(buff, sizeof(buff));
buff[BUFFER_SIZE-1] = 0;
std::cout << "from server:" << buff << std::endl;
if(strcmp("disconnect", buff) == 0)
{
connected = false;
}
}
}
int main(int argc, const char ** argv)
{
int port = 8080;
std::string ipaddr = "127.0.0.1";
bool printHelp = false;
bool argError = false;
bool verbose = false;
for(int i = 0; i < argc; ++i)
{
std::string arg(argv[i]);
if(arg == "--port" || arg == "-p")
{
++i;
if(i < argc)
{
try
{
port = stoi(std::string(argv[i]));
}
catch(std::exception ex)
{
std::cerr << "invalid port number " << argv[i] << std::endl;
argError = true;
}
}
else
{
std::cerr << "missing argument " << argv[i] << " PORT" << std::endl;
argError = true;
}
}
if(arg == "--addr" || arg == "-a")
{
++i;
if(i < argc)
{
ipaddr = argv[i];
}
else
{
std::cerr << "missing argument " << argv[i] << " IPv4" << std::endl;
argError = true;
}
}
if(arg == "--help" || arg == "-h")
{
printHelp = true;
}
if(arg == "--verbose" || arg == "-v")
{
verbose = true;
}
}
if(printHelp || argError)
{
std::cout << argv[0] << "[OPTIONS]" << std::endl;
std::cout << "OPTIONS:" << std::endl;
std::cout << "--port|-p PORT" << std::endl;
std::cout << "--addr|-a IPv4" << std::endl;
std::cout << "--verbose|-v" << std::endl;
std::cout << "--help|-h" << std::endl;
if(argError)
{
return 1;
}
else
{
return 0;
}
}
try
{
conversation(ipaddr, port, verbose);
}
catch(const std::exception & ex)
{
std::cerr << "conversation failed:" << ex.what() << std::endl;
return 8;
}
return 0;
}