Skip to content

Instantly share code, notes, and snippets.

@0xm0
Created March 28, 2021 08:01
Show Gist options
  • Save 0xm0/ef09fb774e5da2178fd846659226389a to your computer and use it in GitHub Desktop.
Save 0xm0/ef09fb774e5da2178fd846659226389a to your computer and use it in GitHub Desktop.
Simple client server chat using C
#!/bin/bash
g++ client.cc -std=c++14 -march=native -o client
#!/bin/bash
### Server
g++ -std=c++14 server.cc -march=native -o server
#include "client.h"
std::string cl::Callback(void* data) {
std::string& str = *(static_cast<std::string*>(data));
return str;
}
template <typename ClientType>
bool cl::Client<ClientType>::ValidateSocket(ClientType sock) {
if (sock <= DEF_SUCCESS_CODE) {
throw std::runtime_error("socket() - fatal");
}
return true;
}
template <typename ClientType>
bool cl::Client<ClientType>::ConnectSocket(ClientType sock, ClientType portnumber) {
server = gethostbyname(localhost.c_str());
if (server == nullptr) {
throw std::runtime_error("gethostbyname() - fatal");
}
bzero(reinterpret_cast<char*> (&serv_addr), sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
bcopy(reinterpret_cast<char*> (server->h_addr), reinterpret_cast<char*> (&serv_addr.sin_addr.s_addr), server->h_length);
serv_addr.sin_port = htons(portnumber);
if (connect(sock, reinterpret_cast<sockaddr*> (&serv_addr), sizeof(serv_addr)) <= DEF_ERROR_CODE) {
throw std::runtime_error("connect() - fatal\n");
}
connected = true;
return connected;
}
template <typename ClientType>
bool cl::Client<ClientType>::SendData(ClientType sock) {
char recievestream[DEF_BUFFER_SIZE];
char sendstream[DEF_BUFFER_SIZE];
while (std::cin.getline(sendstream, DEF_BUFFER_SIZE)) {
send(sock, sendstream, sizeof(sendstream) + 1, DEF_SUCCESS_CODE);
if (strcmp(sendstream, "exit\n") == DEF_SUCCESS_CODE) {
break;
}
recv(sock, recievestream, sizeof(recievestream), DEF_SUCCESS_CODE);
std::cout << "From Server: " << recievestream << '\n';
memset(sendstream, 0, sizeof(sendstream));
memset(recievestream, 0, sizeof(recievestream));
}
close(sock);
return false;
}
int main(void) {
cl::Client<__socket__> clnt;
clnt.socketfd = socket(AF_INET, SOCK_STREAM, DEF_SUCCESS_CODE);
clnt.portnumber = 7001;
if (clnt.ValidateSocket(clnt.socketfd)) {
clnt.ConnectSocket(clnt.socketfd, clnt.portnumber);
clnt.SendData(clnt.socketfd);
}
}
#ifndef CLIENT_H
#define CLIENT_H
#include <iostream>
#include <string>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <thread>
#include <sys/types.h>
#include <sys/stat.h>
#include <vector>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <netdb.h>
#define DEF_BUFFER_SIZE 0x400
#define DEF_SUCCESS_CODE 0
#define DEF_ERROR_CODE -1
typedef int __socket__;
namespace cl {
const std::string localhost = "127.0.0.1";
std::string Callback(void* data);
template <typename ClientType>
class Client {
public:
bool ValidateSocket(ClientType sock);
bool ConnectSocket(ClientType sock, ClientType portnumber);
bool SendData(ClientType sock);
public:
ClientType socketfd;
ClientType portnumber;
bool connected = false;
private:
std::array<char, DEF_BUFFER_SIZE> buffer;
struct sockaddr_in serv_addr;
struct hostent* server;
};
}
#endif
#include "server.h"
template <typename ServerType>
bool srv::Server<ServerType>::ValidateSocket(ServerType sock) {
if (sock == DEF_ERROR_CODE) {
throw std::runtime_error("socket() - fatal\n");
}
return true;
}
template <typename ServerType>
bool srv::Server<ServerType>::ConnectClients(ServerType sock, sockaddr_in server_address, sockaddr_in clientaddress) {
server_address.sin_family = AF_INET;
server_address.sin_port = htons(portnumber);
server_address.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock, reinterpret_cast<sockaddr*> (&server_address), sizeof(server_address)) == DEF_ERROR_CODE) {
throw std::runtime_error("bind() - fatal\n");
}
if (listen(sock, QUEUE) <= DEF_ERROR_CODE) {
throw std::runtime_error("listen() - fatal\n");
}
socketlength_client = sizeof(clientaddress);
connection = accept(sock, reinterpret_cast<sockaddr*> (&clientaddress), &socketlength_client);
if (connection <= DEF_ERROR_CODE) {
throw std::runtime_error("Cannot Accept Connection\n");
}
return true;
}
template <typename ServerType>
void srv::Server<ServerType>::GetClientHost(ServerType portnumber, sockaddr_in clientaddress)
{
char hostbuffer[srv::__max_host__];
char servicebuffer[srv::__max_service__];
memset(hostbuffer, 0, sizeof(hostbuffer));
memset(servicebuffer, 0, sizeof(servicebuffer));
if (getnameinfo(reinterpret_cast<sockaddr*> (&clientaddress), sizeof(clientaddress), hostbuffer, srv::__max_host__,
servicebuffer, srv::__max_service__, DEF_SUCCESS_CODE) == DEF_SUCCESS_CODE) {
std::cout << hostbuffer << " : connected on port: " << servicebuffer << " (SRV: " << portnumber
<< ") " << '\n';
} else {
inet_ntop(AF_INET, &clientaddress.sin_addr, hostbuffer, srv::__max_host__);
std::cout << hostbuffer << " : connected on port: " << ntohs(clientaddress.sin_port) << '\n';
}
}
template <typename ServerType>
bool srv::Server<ServerType>::BroadcastClients(ServerType sock, bool connected) {
while (connected) {
memset(sendbuffer, 0, sizeof(sendbuffer));
data_length = recv(connection, recievebuffer, sizeof(recievebuffer) + 1, 0);
std::cout << "Recieved: " << recievebuffer << '\n';
if (strcmp(sendbuffer, "exit\n") == DEF_SUCCESS_CODE) {
break;
}
std::cin.getline(sendbuffer, DEF_BUFFER_SIZE);
send(connection, sendbuffer, data_length + 1, DEF_SUCCESS_CODE);
}
close(connection);
close(sock);
return true;
}
int main(void)
{
srv::Server<__socket__> server;
server.socketfd = socket(AF_INET, SOCK_STREAM, DEF_SUCCESS_CODE);
server.portnumber = 7001;
struct sockaddr_in server_address, clientaddress;
if (server.ValidateSocket(server.socketfd)) {
if (server.ConnectClients(server.socketfd, server_address, clientaddress)) {
server.conn_active = true;
server.GetClientHost(server.portnumber, clientaddress);
server.BroadcastClients(server.socketfd, server.conn_active);
}
return DEF_ERROR_CODE;
}
}
#ifndef SERVER_H
#define SERVER_H
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <thread>
#include <netdb.h>
#include <iostream>
#define DEF_SUCCESS_CODE 0
#define DEF_ERROR_CODE -1
#define DEF_BUFFER_SIZE 4096
#define QUEUE 20
#define DEF_SET_VALUE(s_val, k_val) ((s_val) = (k_val))
typedef int __socket__;
namespace srv {
constexpr short __max_host__ = 1025;
constexpr short __max_service__ = 32;
template <typename ServerType>
class Server {
public:
bool ValidateSocket(ServerType sock);
void GetClientHost(ServerType portnumber, sockaddr_in clientaddress);
bool ConnectClients(ServerType sock, sockaddr_in server_address, sockaddr_in clientaddress);
bool BroadcastClients(ServerType sock, bool connected);
public:
ServerType socketfd, portnumber;
bool conn_active = false;
private:
char sendbuffer[DEF_BUFFER_SIZE];
char recievebuffer[DEF_BUFFER_SIZE];
socklen_t socketlength_client;
__socket__ data_length, connection;
};
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment