Created
March 28, 2021 08:01
-
-
Save 0xm0/ef09fb774e5da2178fd846659226389a to your computer and use it in GitHub Desktop.
Simple client server chat using C
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
g++ client.cc -std=c++14 -march=native -o client |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
### Server | |
g++ -std=c++14 server.cc -march=native -o server |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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