tweakoz / kissnet

Keep It Simple Stupid NETwork - C++17 wrapping of your OS's native socket API

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

kissnet Build Status Build status Total alerts Language grade: C/C++ License: MIT

Keep It Simple Stupid NETwork.

A lightweight, header only, crossplatform C++17 socket library.

Wrap all annoying C api calls to the OS inside a socket template class

Features:

  • Stupidly simple
  • TCP socket
  • UDP socket
  • ipv4 and ipv6 support
  • Error reporting with and without exceptions
    • You can deactivate exception support. If you do so, library will by default log to stderr (without iostream), and abort program
    • You can provide a custom error handling callback, and you can deactivate the automatic abort by the error handler
  • Communicate with buffers of C++17 std::byte
  • Manage required library (e.g. WinSock2) initialization and cleanup for you RAII style. Network is de-initialized when last socket object goes out of scope
  • Use familiar names for socket operations as methods: send, recv, connect, bind, listen, accept...

Supported platforms:

kissnet was desinged to be a slingle API for using low level tcp and udp sockets on any platform where you can run a modern C++ compiler. Kissnet currently supports

  • Windows (via the WSA/WinSock2 libraries)
  • Linux
  • FreeBSD
  • Haiku OS (needs to be linked to libnetwork. either use target_link_libraries(target network) with cmake, or -lnetwork in yoru compile command), networking will use the posix headers shiped with the OS, not the BeOS-like C++ network kit.

kissnet should probably work "as is" on other UNIX platform.

Short docs

Volontary contrived examples showing how the library looks like:

You can take a look a some of the programs in the examples directory

  • Basic client usage, tcp connect and read, udp send, udp read
#include <iostream>
#include <thread>
#include <chrono>

#include <kissnet.hpp>
using namespace std::chrono_literals;
namespace kn = kissnet;

int main()
{
	{
		//Create a kissnet tco ipv4 socket
		kn::tcp_socket a_socket(kn::endpoint("avalon.ybalrid.info:80"));
		a_socket.connect();

		//Create a "GET /" HTTP request, and send that packet into the socket
		auto get_index_request = std::string{ "GET / HTTP/1.1\r\nHost: avalon.ybalird.info\r\n\r\n" };

		//Send request
		a_socket.send(reinterpret_cast<const std::byte*>(get_index_request.c_str()), get_index_request.size());

		//Receive data into a buffer
		kn::buffer<4096> static_buffer;

		//Useless wait, just to show how long the response was
		std::this_thread::sleep_for(1s);

		//Print how much data our OS has for us
		std::cout << "bytes available to read : " << a_socket.bytes_available() << '\n';

		//Get the data, and the lengh of data
		const auto [data_size, status_code] = a_socket.recv(static_buffer);

		//To print it as a good old C string, add a null terminator
		if(data_size < static_buffer.size())
			static_buffer[data_size] = std::byte{ '\0' };

		//Print the raw data as text into the terminal (should display html/css code here)
		std::cout << reinterpret_cast<const char*>(static_buffer.data()) << '\n';
	}

	/*No more socket here, this will actually close WSA on Windows*/

	{
		//Socket used to send, the "endpoint" is the destination of the data
		kn::udp_socket a_socket(kn::endpoint("127.0.0.1", 6666));

		//Socket used to receive, the "endpoint" is where to listen to data
		kn::udp_socket b_socket(kn::endpoint("0.0.0.0", 6666));
		b_socket.bind();

		//Byte buffer
		kn::buffer<16> buff;

		//Build data to send (flat array of bytes
		for(unsigned char i = 0; i < 16; i++)
			buff[i] = std::byte{ i };

		//Send data
		a_socket.send(buff.data(), 16);

		//Same deal as above
		std::this_thread::sleep_for(1s);

		//We do know, for the sake of the example, that there are 16 bytes to get from the network
		kn::buffer<16> recv_buff;

		//Actually print bytes_available
		std::cout << "avaliable in UDP socket : " << b_socket.bytes_available() << " bytes\n";

		//You receive in the same way
		auto [received_bytes, status] = b_socket.recv(recv_buff);
		const auto from = b_socket.get_recv_endpoint();

		//Print the data
		std::cout << "Received: ";

		for(unsigned char i = 0; i < 16; i++)
		{
			std::cout << std::hex << std::to_integer<int>(recv_buff[i]) << std::dec << ' ';
		}

		//Print who send the data
		std::cout << "From: " << from.address << ' ' << from.port << '\n';
	}

	//So long, and thanks for all the fish
	return 0;
  • TCP listener
#include <kissnet.hpp>
#include <iostream>

namespace kn = kissnet;

int main()
{
	//setup socket
	kn::socket<kissnet::protocol::tcp> server(kn::endpoint("0.0.0.0:8080"));
	server.bind();
	server.listen();

	//Wait for one co
	auto client = server.accept();

	//Read once in a 1k buffer
	kn::buffer<1024> buff;
	const auto [size, status] = client.recv(buff);

	//Add null terminator, and print as string
	if(size < buff.size()) buff[size] = std::byte{ 0 };
	std::cout << reinterpret_cast<const char*>(buff.data()) << '\n';

	return 0;
}

About

Keep It Simple Stupid NETwork - C++17 wrapping of your OS's native socket API

License:MIT License


Languages

Language:C++ 96.6%Language:CMake 3.4%