diff --git a/.gitignore b/.gitignore index cdc6718..eb40e66 100644 --- a/.gitignore +++ b/.gitignore @@ -31,8 +31,10 @@ *.out *.app -examples/bin -benchmarks/easysocket/bin +examples/tcp-client +examples/tcp-server +examples/udp-client +examples/udp-server .vscode .idea cmake-build-debug diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index fa73ec5..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -cmake_minimum_required(VERSION 3.17) -project(async_sockets_cpp) - -set(CMAKE_CXX_STANDARD 14) - -add_library(async_sockets STATIC easysocket/include/basesocket.h - easysocket/include/DllHelper.h - easysocket/include/tcpserver.h - easysocket/include/tcpsocket.h - easysocket/include/udpserver.h - easysocket/include/udpsocket.h - easysocket/src/basesocket.cpp - easysocket/src/tcpserver.cpp - easysocket/src/tcpsocket.cpp - easysocket/src/udpserver.cpp - easysocket/src/udpsocket.cpp) -target_include_directories(async_sockets PUBLIC easysocket/include) - -add_executable(tcp-client examples/tcp-client.cpp) -add_executable(tcp-server examples/tcp-server.cpp) -add_executable(udp-client examples/udp-client.cpp) -add_executable(udp-server examples/udp-server.cpp) - -target_link_libraries(tcp-client async_sockets) -target_link_libraries(tcp-server async_sockets) -target_link_libraries(udp-client async_sockets) -target_link_libraries(udp-server async_sockets) diff --git a/MakeHelper b/MakeHelper deleted file mode 100644 index c4bd21b..0000000 --- a/MakeHelper +++ /dev/null @@ -1,55 +0,0 @@ -#!make - -#OS Commands -define NoTrailSlash -$(patsubst %\\,%,$(patsubst %/,%,$(1))) -endef -define MakeExe -$(1)$(EXEEXT) -endef - -#If Windows -ifeq ($(OS), Windows_NT) - -DLLEXT := .dll -EXEEXT := .exe - -define ReplaceSlash -$(subst /,\\,$(1)) -endef -define MakeLib -$(1)$(DLLEXT) -endef -define RM --del /F /Q $(call ReplaceSlash,$(call NoTrailSlash,$(1))) -endef -define MD --mkdir $(call ReplaceSlash,$(call NoTrailSlash,$(1))) -endef -define CP --robocopy $(call ReplaceSlash,$(1)) $(call ReplaceSlash,$(2)) /E /is -endef - -else -#If not Windows, assume Linux - -DLLEXT := .so -EXEEXT := - -define ReplaceSlash -$(subst \\,/,$(1)) -endef -define MakeLib -lib$(1)$(DLLEXT) -endef -define RM -rm -rf $(1) -endef -define MD -mkdir -p $(1) -endef -define CP -cp -rf $(1) $(2) -endef - -endif diff --git a/README.md b/README.md index dd16d5a..3edf842 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # Asynchronous Sockets for C++ -Simple, thread-based, non-blocking asynchronous Client-Server classes in C++ for TCP & UDP. +Simple, multithread-based(not thread safe), non-blocking asynchronous Client-Server classes in C++ for TCP & UDP. +Creates a thread for every connection. Use `mutex`es or `atomic` variables to provide thread-safe functions. ```cpp // Initialize a tcp socket. @@ -27,6 +28,7 @@ You can compile all the examples by just going in the `examples/` directory and - [examples/tcp-server.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/tcp-server.cpp) - [examples/udp-client.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/udp-client.cpp) - [examples/udp-server.cpp](https://github.com/eminfedar/async-sockets-cpp/blob/master/examples/udp-server.cpp) - -## Future TO-DOs: -- Add Windows support (the library is only for *nix based systems like Linux & MacOS.) + +## Supported Platforms: +- Linux +- MacOS (not tested) diff --git a/async-sockets/include/basesocket.hpp b/async-sockets/include/basesocket.hpp new file mode 100644 index 0000000..a2ca33f --- /dev/null +++ b/async-sockets/include/basesocket.hpp @@ -0,0 +1,72 @@ +#pragma once + +#if defined(__linux__) || defined(__APPLE__) +#include +#include +#include +#include +#include +#elif _WIN32 +#include +#endif + +#include +#include +#include + +#define FDR_UNUSED(expr){ (void)(expr); } +#define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} + +#ifndef AS_DEFAULT_BUFFER_SIZE +#define AS_DEFAULT_BUFFER_SIZE 0x1000 /*4096 bytes*/ +#endif + +class BaseSocket +{ +public: + enum SocketType + { + TCP = SOCK_STREAM, + UDP = SOCK_DGRAM + }; + sockaddr_in address; + + void Close() { + shutdown(this->sock, SHUT_RDWR); + close(this->sock); + } + + std::string remoteAddress() const { return ipToString(this->address); } + int remotePort() const { return ntohs(this->address.sin_port); } + int fileDescriptor() const { return this->sock; } + +protected: + int sock = 0; + + // Get std::string value of the IP from a `sockaddr_in` address struct + static std::string ipToString(const sockaddr_in& addr) + { + char ip[INET_ADDRSTRLEN]; + inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN); + + return std::string(ip); + } + + BaseSocket(FDR_ON_ERROR, SocketType sockType = TCP, int socketId = -1) + { + if (socketId == -1) + { + this->sock = socket(AF_INET, sockType, 0); + + if ( this->sock == -1 ) + { + onError(errno, "Socket creating error."); + } + } + else + { + this->sock = socketId; + } + } + virtual ~BaseSocket(){} +}; \ No newline at end of file diff --git a/async-sockets/include/tcpserver.hpp b/async-sockets/include/tcpserver.hpp new file mode 100644 index 0000000..e7beb59 --- /dev/null +++ b/async-sockets/include/tcpserver.hpp @@ -0,0 +1,87 @@ +#pragma once + +#include "tcpsocket.hpp" +#include + +template +class TCPServer : public BaseSocket +{ +public: + // Event Listeners: + std::function*)> onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; + + explicit TCPServer(FDR_ON_ERROR): BaseSocket(onError, SocketType::TCP) + { + int opt = 1; + setsockopt(this->sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int)); + setsockopt(this->sock,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(int)); + } + + // Bind the custom address & port of the server. + void Bind(const char* address, uint16_t port, FDR_ON_ERROR) + { + int status = inet_pton(AF_INET, address, &this->address.sin_addr); + switch (status) { + case -1: + onError(errno, "Invalid address. Address type not supported."); + return; + case 0: + onError(errno, "AF_INET is not supported. Please send message to developer."); + return; + default: + break; + } + + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + + if (bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)) == -1) + { + onError(errno, "Cannot bind the socket."); + return; + } + } + // Bind the address(0.0.0.0) & port of the server. + void Bind(uint16_t port, FDR_ON_ERROR) { this->Bind("0.0.0.0", port, onError); } + + // Start listening incoming connections. + void Listen(FDR_ON_ERROR) + { + if (listen(this->sock, 20) == -1) + { + onError(errno, "Error: Server can't listen the socket."); + return; + } + + std::thread t(Accept, this, onError); + t.detach(); + } + +private: + static void Accept(TCPServer* server, FDR_ON_ERROR) + { + sockaddr_in newSocketInfo; + socklen_t newSocketInfoLength = sizeof(newSocketInfo); + + int newSocketFileDescriptor = -1; + while (true) + { + newSocketFileDescriptor = accept(server->sock, (sockaddr*)&newSocketInfo, &newSocketInfoLength); + if (newSocketFileDescriptor == -1) + { + if (errno == EBADF || errno == EINVAL) return; + + onError(errno, "Error while accepting a new connection."); + + return; + } + + TCPSocket* newSocket = new TCPSocket(onError, newSocketFileDescriptor); + newSocket->deleteAfterClosed = true; + newSocket->setAddressStruct(newSocketInfo); + + server->onNewConnection(newSocket); + newSocket->Listen(); + } + } +}; \ No newline at end of file diff --git a/async-sockets/include/tcpsocket.hpp b/async-sockets/include/tcpsocket.hpp new file mode 100644 index 0000000..9ee8781 --- /dev/null +++ b/async-sockets/include/tcpsocket.hpp @@ -0,0 +1,129 @@ +#pragma once + +#include "basesocket.hpp" +#include +#include +#include +#include + +template +class TCPSocket : public BaseSocket +{ +public: + // Event Listeners: + std::function onMessageReceived; + std::function onRawMessageReceived; + std::function onSocketClosed; + + explicit TCPSocket(FDR_ON_ERROR, int socketId = -1) : BaseSocket(onError, TCP, socketId){} + + // Send raw bytes + ssize_t Send(const char* bytes, size_t byteslength) { return send(this->sock, bytes, byteslength, 0); } + // Send std::string + ssize_t Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } + + // Connect to a TCP Server with `uint32_t ipv4` & `uint16_t port` values + void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + { + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + this->address.sin_addr.s_addr = ipv4; + + this->setTimeout(5); + + // Try to connect. + int status = connect(this->sock, (const sockaddr*)&this->address, sizeof(sockaddr_in)); + if ( status == -1) + { + onError(errno, "Connection failed to the host."); + this->setTimeout(0); + return; + } + + this->setTimeout(0); + + // Connected to the server, fire the event. + onConnected(); + + // Start listening from server: + this->Listen(); + } + // Connect to a TCP Server with `const char* host` & `uint16_t port` values + void Connect(const char* host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + { + struct addrinfo hints, *res, *it; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + + // Get address info from DNS + int status = getaddrinfo(host, NULL, &hints, &res); + if ( status != 0 ) { + onError(errno, "Invalid address." + std::string(gai_strerror(status))); + return; + } + + for(it = res; it != NULL; it = it->ai_next) + { + if (it->ai_family == AF_INET) { // IPv4 + memcpy((void*)(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); + break; // for now, just get the first ip (ipv4). + } + } + + freeaddrinfo(res); + + this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); + } + // Connect to a TCP Server with `const std::string& ipv4` & `uint16_t port` values + void Connect(const std::string& host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR) + { + this->Connect(host.c_str(), port, onConnected, onError); + } + + // Start another thread to listen the socket + void Listen() + { + std::thread t(TCPSocket::Receive, this); + t.detach(); + } + + void setAddressStruct(sockaddr_in addr) {this->address = addr;} + sockaddr_in getAddressStruct() const {return this->address;} + + bool deleteAfterClosed = false; + +private: + static void Receive(TCPSocket* socket) + { + char tempBuffer[BUFFER_SIZE+1]; + ssize_t messageLength; + + while ((messageLength = recv(socket->sock, tempBuffer, BUFFER_SIZE, 0)) > 0) + { + tempBuffer[messageLength] = '\0'; + if(socket->onMessageReceived) + socket->onMessageReceived(std::string(tempBuffer, messageLength)); + + if(socket->onRawMessageReceived) + socket->onRawMessageReceived(tempBuffer, messageLength); + } + + socket->Close(); + if(socket->onSocketClosed) + socket->onSocketClosed(errno); + + if (socket->deleteAfterClosed && socket != nullptr) + delete socket; + } + + void setTimeout(int seconds) + { + struct timeval tv; + tv.tv_sec = seconds; + tv.tv_usec = 0; + + setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&tv, sizeof(tv)); + setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&tv, sizeof(tv)); + } +}; diff --git a/async-sockets/include/udpserver.hpp b/async-sockets/include/udpserver.hpp new file mode 100644 index 0000000..65ba250 --- /dev/null +++ b/async-sockets/include/udpserver.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "udpsocket.hpp" +#include + +template +class UDPServer : public UDPSocket +{ +public: + // Bind the custom address & port of the server. + void Bind(const char* address, std::uint16_t port, FDR_ON_ERROR) + { + int status = inet_pton(AF_INET, address, &this->address.sin_addr); + switch (status) { + case -1: + onError(errno, "Invalid address. Address type not supported."); + return; + case 0: + onError(errno, "AF_INET is not supported. Please send message to developer."); + return; + default: + break; + } + + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + + status = bind(this->sock, (const sockaddr*)&this->address, sizeof(this->address)); + if (status == -1) + { + onError(errno, "Cannot bind the socket."); + return; + } + } + + // Bind the address(0.0.0.0) & port of the server. + void Bind(uint16_t port, FDR_ON_ERROR) + { + this->Bind("0.0.0.0", port, onError); + } + + // Enable or disable the SO_BROADCAST flag + void setBroadcast(bool value, FDR_ON_ERROR) + { + int broadcast = static_cast(value); + int status = setsockopt(this->sock, SOL_SOCKET, SO_BROADCAST, &broadcast, sizeof broadcast); + if (status == -1) + { + onError(errno, "setsockopt(SO_BROADCAST) failed."); + return; + } + } +}; \ No newline at end of file diff --git a/async-sockets/include/udpsocket.hpp b/async-sockets/include/udpsocket.hpp new file mode 100644 index 0000000..f9b8b9a --- /dev/null +++ b/async-sockets/include/udpsocket.hpp @@ -0,0 +1,170 @@ +#pragma once + +#include "basesocket.hpp" +#include +#include + +template +class UDPSocket : public BaseSocket +{ +public: + std::function onMessageReceived; + std::function onRawMessageReceived; + + explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1): BaseSocket(onError, SocketType::UDP, socketId) + { + if (useConnect) + { + std::thread t(Receive, this); // usage with Connect() + t.detach(); + } + else + { + std::thread t(ReceiveFrom, this); + t.detach(); + } + } + + // Send raw bytes to a spesific `host` & `port` with no connection + ssize_t SendTo(const char* bytes, size_t byteslength, const char* host, uint16_t port, FDR_ON_ERROR) + { + sockaddr_in hostAddr; + + struct addrinfo hints, *res, *it; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + int status; + if ((status = getaddrinfo(host, NULL, &hints, &res)) != 0) + { + onError(errno, "Invalid address." + std::string(gai_strerror(status))); + return -1; + } + + for (it = res; it != NULL; it = it->ai_next) + { + if (it->ai_family == AF_INET) + { // IPv4 + memcpy((void* )(&hostAddr), (void* )it->ai_addr, sizeof(sockaddr_in)); + break; // for now, just get first ip (ipv4). + } + } + + freeaddrinfo(res); + + hostAddr.sin_port = htons(port); + hostAddr.sin_family = AF_INET; + + ssize_t sent_length = sendto(this->sock, bytes, byteslength, 0, (sockaddr*)&hostAddr, sizeof(hostAddr)); + if (sent_length == -1) + { + onError(errno, "Cannot send message to the address."); + return -1; + } + + return sent_length; + } + // Send raw bytes to a spesific `host` & `port` with no connection + ssize_t SendTo(const char* bytes, size_t byteslength, const std::string& host, uint16_t port, FDR_ON_ERROR) + { + return this->SendTo(bytes, byteslength, host.c_str(), port, onError); + } + // Send std::string to a spesific `host` & `port` with no connection + ssize_t SendTo(const std::string& message, const char* host, uint16_t port, FDR_ON_ERROR) + { + return this->SendTo(message.c_str(), message.length(), host, port, onError); + } + // Send std::string to a spesific `host` & `port` with no connection + ssize_t SendTo(const std::string& message, const std::string& host, uint16_t port, FDR_ON_ERROR) + { + return this->SendTo(message.c_str(), message.length(), host.c_str(), port, onError); + } + + // Send raw bytes to the `Connect()`ed server. + ssize_t Send(const char* bytes, size_t byteslength) { return send(this->sock, bytes, byteslength, 0); } + // Send std::string to the `Connect()`ed server. + ssize_t Send(const std::string& message) { return this->Send(message.c_str(), message.length()); } + + // Connect to a server with raw `uint32_t ipv4` and `uint16_t port` values. + void Connect(uint32_t ipv4, uint16_t port, FDR_ON_ERROR) + { + this->address.sin_family = AF_INET; + this->address.sin_port = htons(port); + this->address.sin_addr.s_addr = ipv4; + + // Try to connect. + int status = connect(this->sock, (const sockaddr* )&this->address, sizeof(sockaddr_in)); + if (status == -1) + { + onError(errno, "Connection failed to the host."); + return; + } + } + // Connect to a server with `host` address and `port` values. + void Connect(const char* host, uint16_t port, FDR_ON_ERROR) + { + struct addrinfo hints, *res, *it; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + int status = getaddrinfo(host, NULL, &hints, &res); + if (status != 0) + { + onError(errno, "Invalid address." + std::string(gai_strerror(status))); + return; + } + + for (it = res; it != NULL; it = it->ai_next) + { + if (it->ai_family == AF_INET) + { // IPv4 + memcpy((void* )(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); + break; // for now, just get first ip (ipv4). + } + } + + freeaddrinfo(res); + + this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onError); + } + // Connect to a server with `host` address and `port` values. + void Connect(const std::string& host, uint16_t port, FDR_ON_ERROR) { this->Connect(host.c_str(), port, onError); } + +private: + static void Receive(UDPSocket* udpSocket) + { + char tempBuffer[BUFFER_SIZE+1]; + ssize_t messageLength; + + while ((messageLength = recv(udpSocket->sock, tempBuffer, BUFFER_SIZE, 0)) != -1) + { + tempBuffer[messageLength] = '\0'; + if (udpSocket->onMessageReceived) + udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); + + if (udpSocket->onRawMessageReceived) + udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); + } + } + + static void ReceiveFrom(UDPSocket* udpSocket) + { + sockaddr_in hostAddr; + socklen_t hostAddrSize = sizeof(hostAddr); + + char tempBuffer[BUFFER_SIZE+1]; + ssize_t messageLength; + + while ((messageLength = recvfrom(udpSocket->sock, tempBuffer, BUFFER_SIZE, 0, (sockaddr* )&hostAddr, &hostAddrSize)) != -1) + { + tempBuffer[messageLength] = '\0'; + if (udpSocket->onMessageReceived) + udpSocket->onMessageReceived(std::string(tempBuffer, messageLength), ipToString(hostAddr), ntohs(hostAddr.sin_port)); + + if (udpSocket->onRawMessageReceived) + udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(hostAddr), ntohs(hostAddr.sin_port)); + } + } +}; \ No newline at end of file diff --git a/async-sockets/install.sh b/async-sockets/install.sh new file mode 100755 index 0000000..a6bdd4b --- /dev/null +++ b/async-sockets/install.sh @@ -0,0 +1,14 @@ +#!/bin/bash +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +rm -rf /usr/local/include/async-sockets +mkdir /usr/local/include/async-sockets +cp -fR ./include/* /usr/local/include/async-sockets/ + +echo "Info: The library has been copied to -> /usr/local/include"; +echo "" +echo "Example usage:" +echo "#include " diff --git a/async-sockets/remove.sh b/async-sockets/remove.sh new file mode 100755 index 0000000..f816502 --- /dev/null +++ b/async-sockets/remove.sh @@ -0,0 +1,7 @@ +#!/bin/bash +if [[ $EUID -ne 0 ]]; then + echo "This script must be run as root" + exit 1 +fi + +rm -rf /usr/local/include/async-sockets diff --git a/easysocket/Makefile b/easysocket/Makefile deleted file mode 100644 index 705783b..0000000 --- a/easysocket/Makefile +++ /dev/null @@ -1,86 +0,0 @@ -#!make -# This make needs: -# g++ -# - -include ../MakeHelper - -# Project name -NAME := $(patsubst %/,%,$(notdir $(CURDIR))) - -#The Target Binary Program -TARGET := $(call MakeLib,$(NAME)) - -#The Directories, Source, Includes, Objects, Binary and Resources -SRCDIR ?= $(CURDIR)/src -INCDIR ?= $(CURDIR)/include -BUILDDIR ?= $(CURDIR)/obj/$(BUILD) -TARGETDIR ?= $(CURDIR)/bin/$(BUILD) -RESDIR ?= $(CURDIR)/rsc -SRCEXT := .cpp -OBJEXT := .o - -#Compiler and Linker -BUILD ?= release -CC := g++ - -#Flags, Libraries and Includes -CFLAGS.common := -std=c++17 -fPIC -Wall -Wextra -DBUILD_EASYSOCKET -CFLAGS.debug := $(CFLAGS.common) -g -CFLAGS.release := $(CFLAGS.common) -Werror -O3 -CFLAGS ?= $(CFLAGS.$(BUILD)) -LIB := -L$(TARGETDIR) -INC := -I$(INCDIR) - -#--------------------------------------------------------------------------------- -#DO NOT EDIT BELOW THIS LINE -#--------------------------------------------------------------------------------- -SOURCES := $(wildcard $(SRCDIR)/*$(SRCEXT)) -OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(SOURCES:$(SRCEXT)=$(OBJEXT))) - -#Default Make -all: resources $(TARGET) tests docs - -#Remake -remake: cleaner all - -#Create template folder structure -template: directories - $(call MD,$(SRCDIR)) - $(call MD,$(INCDIR)) - $(call MD,$(RESDIR)) - -#Make the Directories -directories: - $(call MD,$(TARGETDIR)) - $(call MD,$(BUILDDIR)) - -#Copy Resources from Resources Directory to Target Directory -resources: template -# @$(call CP,$(RESDIR)/*,$(TARGETDIR)/) - -#Clean only Objecst -clean: - $(call RM,$(BUILDDIR)) - -#Full Clean, Objects and Binaries -cleaner: clean - $(call RM,$(TARGETDIR)) - -docs: -#TODO - -tests: -#TODO - -#Link the final executable/library -$(TARGET): $(OBJECTS) - $(CC) -shared -o $(TARGETDIR)/$(TARGET) $^ $(LIB) - -#Compile -$(BUILDDIR)/%$(OBJEXT): $(SRCDIR)/%$(SRCEXT) - $(call MD,$(dir $@)) - $(CC) $(CFLAGS) $(INC) -c -o $@ $< - -#Non-File Targets -.PHONY: all remake template directories resources clean cleaner diff --git a/easysocket/include/DllHelper.h b/easysocket/include/DllHelper.h deleted file mode 100644 index f553613..0000000 --- a/easysocket/include/DllHelper.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifdef BUILD_EASYSOCKET -#define EASYSOCKET_API EXPORT_EASYSOCKET -#else -#define EASYSOCKET_API IMPORT_EASYSOCKET -#endif - -#if defined(_MSC_VER) - // Microsoft - #define EXPORT_EASYSOCKET __declspec(dllexport) - #define IMPORT_EASYSOCKET __declspec(dllimport) -#elif defined(__GNUC__) - // GCC - #define EXPORT_EASYSOCKET __attribute__((visibility("default"))) - #define IMPORT_EASYSOCKET -#else - // do nothing and hope for the best? - #define EXPORT_EASYSOCKET - #define IMPORT_EASYSOCKET - #pragma warning Unknown dynamic link import/export semantics. -#endif diff --git a/easysocket/include/basesocket.h b/easysocket/include/basesocket.h deleted file mode 100644 index 0dfdc61..0000000 --- a/easysocket/include/basesocket.h +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef FDR_BASESOCKET_H -#define FDR_BASESOCKET_H - -#include "DllHelper.h" - -#if defined(__linux__) || defined(__APPLE__) -#include -#include -#include -#include -#include -#elif _WIN32 -#include -#endif - -#include -#include - -#define FDR_UNUSED(expr){ (void)(expr); } -#define FDR_ON_ERROR std::function onError = [](int errorCode, std::string errorMessage){FDR_UNUSED(errorCode); FDR_UNUSED(errorMessage)} - -class EASYSOCKET_API BaseSocket -{ -protected: - int sock = 0; - - static std::string ipToString(sockaddr_in addr); - -public: - const uint16_t BUFFER_SIZE = 0xFFFF; - enum EASYSOCKET_API SocketType - { - TCP = SOCK_STREAM, - UDP = SOCK_DGRAM - }; - - sockaddr_in address; - bool isClosed = false; - - explicit BaseSocket(FDR_ON_ERROR, SocketType sockType = TCP, int socketId = -1); - - virtual void Close(); - - std::string remoteAddress(); - int remotePort(); - int fileDescriptor() const { return this->sock; } -}; - -#endif diff --git a/easysocket/include/tcpserver.h b/easysocket/include/tcpserver.h deleted file mode 100644 index f6d83b3..0000000 --- a/easysocket/include/tcpserver.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FDR_TCPSERVER_H -#define FDR_TCPSERVER_H - -#include "DllHelper.h" - -#include "tcpsocket.h" -#include -#include -#include - -class EASYSOCKET_API TCPServer : public BaseSocket -{ -public: - // Event Listeners: - std::function onNewConnection = [](TCPSocket* sock){FDR_UNUSED(sock)}; - - explicit TCPServer(FDR_ON_ERROR); - - // Binding the server. - void Bind(int port, FDR_ON_ERROR); - void Bind(const char *address, uint16_t port, FDR_ON_ERROR); - - // Start listening the server. - void Listen(FDR_ON_ERROR); - - // Overriding Close to add shutdown(): - void Close() override; - -private: - static void Accept(TCPServer *server, FDR_ON_ERROR); -}; - -#endif diff --git a/easysocket/include/tcpsocket.h b/easysocket/include/tcpsocket.h deleted file mode 100644 index e0de8a6..0000000 --- a/easysocket/include/tcpsocket.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef FDR_TCPSOCKET_H -#define FDR_TCPSOCKET_H - -#include "DllHelper.h" - -#include "basesocket.h" -#include -#include -#include - -class EASYSOCKET_API TCPSocket : public BaseSocket -{ -public: - // Event Listeners: - std::function onMessageReceived; - std::function onRawMessageReceived; - std::function onSocketClosed; - - explicit TCPSocket(FDR_ON_ERROR, int socketId = -1); - - int Send(std::string message); - int Send(const char *bytes, size_t byteslength); - - void Connect(std::string host, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR); - void Connect(uint32_t ipv4, uint16_t port, std::function onConnected = [](){}, FDR_ON_ERROR); - - void Listen(); - - void setAddressStruct(sockaddr_in addr); - sockaddr_in getAddressStruct() const; - - void setTimeout(int seconds); - int getTimeout() const; - -private: - static void Receive(TCPSocket *socket); - - int timeout = 5; // 5 seconds timeout default. -}; - -#endif diff --git a/easysocket/include/udpserver.h b/easysocket/include/udpserver.h deleted file mode 100644 index 5a8922f..0000000 --- a/easysocket/include/udpserver.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef FDR_UDPSERVER_H -#define FDR_UDPSERVER_H - -#include "DllHelper.h" - -#include "udpsocket.h" -#include - -class EASYSOCKET_API UDPServer : public UDPSocket -{ -public: - UDPServer(); - - void Bind(int port, FDR_ON_ERROR); - void Bind(std::string IPv4, std::uint16_t port, FDR_ON_ERROR); -}; - -#endif diff --git a/easysocket/include/udpsocket.h b/easysocket/include/udpsocket.h deleted file mode 100644 index ecc5691..0000000 --- a/easysocket/include/udpsocket.h +++ /dev/null @@ -1,33 +0,0 @@ -#ifndef FDR_UDPSOCKET_H -#define FDR_UDPSOCKET_H - -#include "DllHelper.h" - -#include "basesocket.h" -#include -#include -#include - -class EASYSOCKET_API UDPSocket : public BaseSocket -{ -public: - std::function onMessageReceived; - std::function onRawMessageReceived; - - explicit UDPSocket(bool useConnect = false, FDR_ON_ERROR, int socketId = -1); - - void SendTo(std::string message, std::string host, uint16_t port, FDR_ON_ERROR); - void SendTo(const char *bytes, size_t byteslength, std::string host, uint16_t port, FDR_ON_ERROR); - - int Send(std::string message); - int Send(const char *bytes, size_t byteslength); - - void Connect(std::string host, uint16_t port, FDR_ON_ERROR); - void Connect(uint32_t ipv4, uint16_t port, FDR_ON_ERROR); - -private: - static void Receive(UDPSocket *udpSocket); - static void ReceiveFrom(UDPSocket *udpSocket); -}; - -#endif diff --git a/easysocket/install.sh b/easysocket/install.sh deleted file mode 100755 index a58e8e0..0000000 --- a/easysocket/install.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/sh - -rm -rf /usr/local/include/easysocket -mkdir /usr/local/include/easysocket -cp -f ./bin/release/libeasysocket.so /usr/lib/x86_64-linux-gnu/libeasysocket.so -cp -fR ./include/* /usr/local/include/easysocket/ diff --git a/easysocket/remove.sh b/easysocket/remove.sh deleted file mode 100755 index 2c7cbf8..0000000 --- a/easysocket/remove.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -rm -rf /usr/local/include/easysocket -rm /usr/lib/x86_64-linux-gnu/libeasysocket.so \ No newline at end of file diff --git a/easysocket/src/basesocket.cpp b/easysocket/src/basesocket.cpp deleted file mode 100644 index 2d99d2a..0000000 --- a/easysocket/src/basesocket.cpp +++ /dev/null @@ -1,40 +0,0 @@ -#include - -#include - -std::string BaseSocket::ipToString(sockaddr_in addr) -{ - char ip[INET_ADDRSTRLEN]; - inet_ntop(AF_INET, &(addr.sin_addr), ip, INET_ADDRSTRLEN); - - return std::string(ip); -} - -BaseSocket::BaseSocket(std::function onError, SocketType sockType, int socketId) : sock(socketId) -{ - if (socketId < 0) - { - if ((this->sock = socket(AF_INET, sockType, 0)) < 0) - { - onError(errno, "Socket creating error."); - } - } -} - -void BaseSocket::Close() -{ - if(isClosed) return; - - isClosed = true; - close(this->sock); -} - -std::string BaseSocket::remoteAddress() -{ - return ipToString(this->address); -} - -int BaseSocket::remotePort() -{ - return ntohs(this->address.sin_port); -} diff --git a/easysocket/src/tcpserver.cpp b/easysocket/src/tcpserver.cpp deleted file mode 100644 index f775fc9..0000000 --- a/easysocket/src/tcpserver.cpp +++ /dev/null @@ -1,77 +0,0 @@ -#include - -TCPServer::TCPServer(std::function onError) : BaseSocket(onError, TCP) -{ - int opt = 1; - setsockopt(this->sock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(int)); - setsockopt(this->sock,SOL_SOCKET,SO_REUSEPORT,&opt,sizeof(int)); -} - -void TCPServer::Bind(int port, std::function onError) -{ - this->Bind("0.0.0.0", port, onError); -} - -void TCPServer::Bind(const char *address, uint16_t port, std::function onError) -{ - if (inet_pton(AF_INET, address, &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; - } - - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - - if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) - { - onError(errno, "Cannot bind the socket."); - return; - } -} - -void TCPServer::Listen(std::function onError) -{ - if (listen(this->sock, 10) < 0) - { - onError(errno, "Error: Server can't listen the socket."); - return; - } - - std::thread acceptThread(Accept, this, onError); - acceptThread.detach(); -} - -void TCPServer::Close() -{ - shutdown(this->sock, SHUT_RDWR); - - BaseSocket::Close(); -} - -void TCPServer::Accept(TCPServer *server, std::function onError) -{ - sockaddr_in newSocketInfo; - socklen_t newSocketInfoLength = sizeof(newSocketInfo); - - int newSock; - while (!server->isClosed) - { - while ((newSock = accept(server->sock, (sockaddr *)&newSocketInfo, &newSocketInfoLength)) < 0) - { - if (errno == EBADF || errno == EINVAL) return; - - onError(errno, "Error while accepting a new connection."); - return; - } - - if (!server->isClosed && newSock >= 0) - { - TCPSocket *newSocket = new TCPSocket([](int e, std::string er) { FDR_UNUSED(e); FDR_UNUSED(er); }, newSock); - newSocket->setAddressStruct(newSocketInfo); - - server->onNewConnection(newSocket); - newSocket->Listen(); - } - } -} diff --git a/easysocket/src/tcpsocket.cpp b/easysocket/src/tcpsocket.cpp deleted file mode 100644 index cacc7be..0000000 --- a/easysocket/src/tcpsocket.cpp +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include -TCPSocket::TCPSocket(std::function onError, int socketId) : BaseSocket(onError, TCP, socketId) -{ - this->setTimeout(this->timeout); -} - -int TCPSocket::Send(std::string message) -{ - return this->Send(message.c_str(), message.length()); -} - -int TCPSocket::Send(const char *bytes, size_t byteslength) -{ - if (this->isClosed) - return -1; - - int sent = 0; - if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) - { - perror("send"); - } - return sent; -} - -void TCPSocket::Connect(std::string host, uint16_t port, std::function onConnected, std::function onError) -{ - struct addrinfo hints, *res, *it; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_STREAM; - - int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) { - onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; - } - - for(it = res; it != NULL; it = it->ai_next) - { - if (it->ai_family == AF_INET) { // IPv4 - memcpy((void*)(&this->address), (void*)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). - } - } - - freeaddrinfo(res); - - this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onConnected, onError); -} - -void TCPSocket::Connect(uint32_t ipv4, uint16_t port, std::function onConnected, std::function onError) -{ - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - this->address.sin_addr.s_addr = ipv4; - - // Try to connect. - if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) - { - onError(errno, "Connection failed to the host."); - return; - } - - // Connected to the server, fire the event. - onConnected(); - - // Start listening from server: - this->Listen(); -} - -void TCPSocket::Listen() -{ - // Start listening the socket from thread. - std::thread receiveListening(Receive, this); - receiveListening.detach(); -} - -void TCPSocket::setAddressStruct(sockaddr_in addr) -{ - this->address = addr; -} -sockaddr_in TCPSocket::getAddressStruct() const -{ - return this->address; -} - -void TCPSocket::setTimeout(int seconds) { - this->timeout = seconds; - struct timeval tv; - tv.tv_sec = seconds; - tv.tv_usec = 0; - - setsockopt(this->sock, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); - setsockopt(this->sock, SOL_SOCKET, SO_SNDTIMEO, (char *)&tv, sizeof(tv)); -} -int TCPSocket::getTimeout() const{ - return this->timeout; -} - -void TCPSocket::Receive(TCPSocket *socket) -{ - char tempBuffer[socket->BUFFER_SIZE]; - int messageLength; - - while ((messageLength = recv(socket->sock, tempBuffer, socket->BUFFER_SIZE, 0)) > 0) - { - tempBuffer[messageLength] = '\0'; - if(socket->onMessageReceived) - socket->onMessageReceived(std::string(tempBuffer).substr(0, messageLength)); - - if(socket->onRawMessageReceived) - socket->onRawMessageReceived(tempBuffer, messageLength); - } - - socket->Close(); - if(socket->onSocketClosed) - socket->onSocketClosed(); -} diff --git a/easysocket/src/udpserver.cpp b/easysocket/src/udpserver.cpp deleted file mode 100644 index f12e284..0000000 --- a/easysocket/src/udpserver.cpp +++ /dev/null @@ -1,27 +0,0 @@ -#include - -UDPServer::UDPServer() -{ -} - -void UDPServer::Bind(int port, std::function onError) { - this->Bind("0.0.0.0", port, onError); -} - -void UDPServer::Bind(std::string IPv4, std::uint16_t port, std::function onError) -{ - if (inet_pton(AF_INET, IPv4.c_str(), &this->address.sin_addr) <= 0) - { - onError(errno, "Invalid address. Address type not supported."); - return; - } - - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - - if (bind(this->sock, (const sockaddr *)&this->address, sizeof(this->address)) < 0) - { - onError(errno, "Cannot bind the socket."); - return; - } -} diff --git a/easysocket/src/udpsocket.cpp b/easysocket/src/udpsocket.cpp deleted file mode 100644 index 68924d6..0000000 --- a/easysocket/src/udpsocket.cpp +++ /dev/null @@ -1,171 +0,0 @@ -#include -#include - -UDPSocket::UDPSocket(bool useConnect, std::function onError, int socketId) : BaseSocket(onError, UDP, socketId) -{ - if (!useConnect) - { - std::thread recvfromThread(ReceiveFrom, this); - recvfromThread.detach(); - } - else - { - std::thread recvThread(Receive, this); - recvThread.detach(); - } -} - -void UDPSocket::SendTo(std::string message, std::string host, uint16_t port, std::function onError) -{ - this->SendTo(message.c_str(), message.length(), host, port, onError); -} - -void UDPSocket::SendTo(const char *bytes, size_t byteslength, std::string host, uint16_t port, std::function onError) -{ - sockaddr_in hostAddr; - - struct addrinfo hints, *res, *it; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - - int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) - { - onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; - } - - for (it = res; it != NULL; it = it->ai_next) - { - if (it->ai_family == AF_INET) - { // IPv4 - memcpy((void *)(&hostAddr), (void *)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). - } - } - - freeaddrinfo(res); - - hostAddr.sin_port = htons(port); - hostAddr.sin_family = AF_INET; - - if (sendto(this->sock, bytes, byteslength, 0, (sockaddr *)&hostAddr, sizeof(hostAddr)) < 0) - { - onError(errno, "Cannot send message to the address."); - return; - } -} - -int UDPSocket::Send(std::string message) -{ - return this->Send(message.c_str(), message.length()); -} -int UDPSocket::Send(const char *bytes, size_t byteslength) -{ - if (this->isClosed) - return -1; - - int sent = 0; - if ((sent = send(this->sock, bytes, byteslength, 0)) < 0) - { - perror("send"); - } - return sent; -} - -void UDPSocket::Connect(std::string host, uint16_t port, std::function onError) -{ - struct addrinfo hints, *res, *it; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; - - int status; - if ((status = getaddrinfo(host.c_str(), NULL, &hints, &res)) != 0) - { - onError(errno, "Invalid address." + std::string(gai_strerror(status))); - return; - } - - for (it = res; it != NULL; it = it->ai_next) - { - if (it->ai_family == AF_INET) - { // IPv4 - memcpy((void *)(&this->address), (void *)it->ai_addr, sizeof(sockaddr_in)); - break; // for now, just get first ip (ipv4). - } - } - - freeaddrinfo(res); - - this->Connect((uint32_t)this->address.sin_addr.s_addr, port, onError); -} -void UDPSocket::Connect(uint32_t ipv4, uint16_t port, std::function onError) -{ - this->address.sin_family = AF_INET; - this->address.sin_port = htons(port); - this->address.sin_addr.s_addr = ipv4; - - // Try to connect. - if (connect(this->sock, (const sockaddr *)&this->address, sizeof(sockaddr_in)) < 0) - { - onError(errno, "Connection failed to the host."); - return; - } -} - -void UDPSocket::Receive(UDPSocket *udpSocket) -{ - char tempBuffer[udpSocket->BUFFER_SIZE]; - - while (true) - { - int messageLength; - messageLength = recv(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0); - - if (messageLength < 0) - { - perror("recvfrom"); - return; - } - else - { - tempBuffer[messageLength] = '\0'; - if (udpSocket->onMessageReceived) - udpSocket->onMessageReceived(std::string(tempBuffer).substr(0, messageLength), ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - - if (udpSocket->onRawMessageReceived) - udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(udpSocket->address), ntohs(udpSocket->address.sin_port)); - } - } -} - -void UDPSocket::ReceiveFrom(UDPSocket *udpSocket) -{ - sockaddr_in hostAddr; - socklen_t hostAddrSize = sizeof(hostAddr); - - char tempBuffer[udpSocket->BUFFER_SIZE]; - - while (true) - { - int messageLength; - messageLength = recvfrom(udpSocket->sock, tempBuffer, udpSocket->BUFFER_SIZE, 0, (sockaddr *)&hostAddr, &hostAddrSize); - - if (messageLength < 0) - { - perror("recvfrom"); - return; - } - else - { - tempBuffer[messageLength] = '\0'; - if (udpSocket->onMessageReceived) - udpSocket->onMessageReceived(std::string(tempBuffer).substr(0, messageLength), ipToString(hostAddr), ntohs(hostAddr.sin_port)); - - if (udpSocket->onRawMessageReceived) - udpSocket->onRawMessageReceived(tempBuffer, messageLength, ipToString(hostAddr), ntohs(hostAddr.sin_port)); - } - } -} diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt new file mode 100644 index 0000000..3f18e53 --- /dev/null +++ b/examples/CMakeLists.txt @@ -0,0 +1,21 @@ +cmake_minimum_required(VERSION 3.18) +project(ExampleProgram) + +set(CMAKE_CXX_STANDARD 11) + +add_executable(tcp-client tcp-client.cpp) +add_executable(tcp-server tcp-server.cpp) +add_executable(udp-client udp-client.cpp) +add_executable(udp-server udp-server.cpp) + +# Add -lpthread +target_link_libraries(tcp-client pthread) +target_link_libraries(tcp-server pthread) +target_link_libraries(udp-client pthread) +target_link_libraries(udp-server pthread) + +# Add -I../async-sockets +target_include_directories(tcp-client PUBLIC ../async-sockets) +target_include_directories(tcp-server PUBLIC ../async-sockets) +target_include_directories(udp-client PUBLIC ../async-sockets) +target_include_directories(udp-server PUBLIC ../async-sockets) diff --git a/examples/Makefile b/examples/Makefile index 558158a..2cd389d 100644 --- a/examples/Makefile +++ b/examples/Makefile @@ -1,48 +1,27 @@ -#!make -# This make needs: -# g++ -# - -include ../MakeHelper - -#The Directories, Source, Includes, Objects, Binary and Resources -BUILDDIR ?= $(CURDIR)/obj/$(BUILD) -TARGETDIR ?= $(CURDIR)/bin/$(BUILD) - -#Compiler and Linker -BUILD ?= release -BITS ?= 64 CC := g++ +CFLAGS := --std=c++11 -Wall -Wextra -Werror=conversion +LIBS := -lpthread +INC := ../async-sockets/include +RM := rm -#Flags, Libraries and Includes -CFLAGS.common := -std=c++17 -m$(BITS) -Wall -Wextra -CFLAGS.debug := $(CFLAGS.common) -g -CFLAGS.release := $(CFLAGS.common) -Werror -O3 -CFLAGS ?= $(CFLAGS.$(BUILD)) -LIB := -L$(TARGETDIR) -leasysocket -lpthread -Wl,-rpath='$${ORIGIN}' -INC := -I$(CURDIR)/../easysocket/include +.PHONY: all clean -build: - (cd ../easysocket && make TARGETDIR="$(TARGETDIR)") - $(CC) $(CFLAGS) $(INC) tcp-client.cpp -o $(TARGETDIR)/$(call MakeExe,tcp-client) $(LIB) - $(CC) $(CFLAGS) $(INC) udp-client.cpp -o $(TARGETDIR)/$(call MakeExe,udp-client) $(LIB) - $(CC) $(CFLAGS) $(INC) tcp-server.cpp -o $(TARGETDIR)/$(call MakeExe,tcp-server) $(LIB) - $(CC) $(CFLAGS) $(INC) udp-server.cpp -o $(TARGETDIR)/$(call MakeExe,udp-server) $(LIB) +all: tcp-client tcp-server udp-client udp-server -template: - $(call MD,$(TARGETDIR)) - $(call MD,$(BUILDDIR)) +tcp-client: tcp-client.cpp $(INC)/tcpsocket.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -clean: - $(call RM,$(BUILDDIR)) - -cleaner: clean - $(call RM,$(TARGETDIR)) +tcp-server: tcp-server.cpp $(INC)/tcpserver.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -clean-deps: clean - (cd ../easysocket && make clean) +udp-client: udp-client.cpp $(INC)/udpsocket.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -cleaner-deps: cleaner - (cd ../easysocket && make cleaner) +udp-server: udp-server.cpp $(INC)/udpserver.hpp + $(CC) $(CFLAGS) $< -I$(INC) $(LIBS) -o $@ -.PHONY: build template clean cleaner clean-deps cleaner-deps +clean: + $(RM) tcp-client + $(RM) tcp-server + $(RM) udp-client + $(RM) udp-server diff --git a/examples/tcp-client.cpp b/examples/tcp-client.cpp index 1ea70f2..3e82b5e 100644 --- a/examples/tcp-client.cpp +++ b/examples/tcp-client.cpp @@ -1,4 +1,4 @@ -#include +#include "tcpsocket.hpp" #include using namespace std; @@ -6,29 +6,27 @@ using namespace std; int main() { // Initialize socket. - TCPSocket tcpSocket; - - // Set connection timeout seconds. - tcpSocket.setTimeout(5); + TCPSocket<> tcpSocket([](int errorCode, std::string errorMessage){ + cout << "Socket creation error:" << errorCode << " : " << errorMessage << endl; + }); // Start receiving from the host. - tcpSocket.onMessageReceived = [](string message) { - cout << "Message from the Server: " << message << endl; - }; - // If you want to use raw bytes instead of std::string: - /* tcpSocket.onRawMessageReceived = [](const char* message, int length) { cout << "Message from the Server: " << message << "(" << length << ")" << endl; }; - */ + + // If you want to use std::string instead of const char*: + //tcpSocket.onMessageReceived = [](string message) { + // cout << "Message from the Server: " << message << endl; + //}; // On socket closed: - tcpSocket.onSocketClosed = []{ - cout << "Connection closed." << endl; + tcpSocket.onSocketClosed = [](int errorCode){ + cout << "Connection closed: " << errorCode << endl; }; - // Connect to the host. - tcpSocket.Connect("54.23.12.43", 8888, [&] { + // Connect to the host (with a custom buffer size). + tcpSocket.Connect("localhost", 8888, [&] { cout << "Connected to the server successfully." << endl; // Send String: @@ -39,8 +37,7 @@ int main() cout << errorCode << " : " << errorMessage << endl; }); - // You should do an input loop so the program will not end immediately: - // Because socket listenings are non-blocking. + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") diff --git a/examples/tcp-server.cpp b/examples/tcp-server.cpp index 4071321..7c642b8 100644 --- a/examples/tcp-server.cpp +++ b/examples/tcp-server.cpp @@ -1,4 +1,4 @@ -#include +#include "tcpserver.hpp" #include using namespace std; @@ -6,10 +6,10 @@ using namespace std; int main() { // Initialize server socket.. - TCPServer tcpServer; + TCPServer<> tcpServer; // When a new client connected: - tcpServer.onNewConnection = [&](TCPSocket *newClient) { + tcpServer.onNewConnection = [&](TCPSocket<> *newClient) { cout << "New client: ["; cout << newClient->remoteAddress() << ":" << newClient->remotePort() << "]" << endl; @@ -26,8 +26,9 @@ int main() }; */ - newClient->onSocketClosed = [newClient]() { - cout << "Socket closed:" << newClient->remoteAddress() << ":" << newClient->remotePort() << endl; + newClient->onSocketClosed = [newClient](int errorCode) { + cout << "Socket closed:" << newClient->remoteAddress() << ":" << newClient->remotePort() << " -> " << errorCode << endl; + cout << flush; }; }; @@ -43,7 +44,7 @@ int main() cout << errorCode << " : " << errorMessage << endl; }); - // You should do an input loop so the program will not terminated immediately: + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") diff --git a/examples/udp-client.cpp b/examples/udp-client.cpp index 73f034d..d9e63aa 100644 --- a/examples/udp-client.cpp +++ b/examples/udp-client.cpp @@ -1,4 +1,4 @@ -#include +#include "udpsocket.hpp" #include using namespace std; @@ -6,11 +6,11 @@ using namespace std; int main() { // Our constants: - const string IP = "localhost"; - const uint16_t PORT = 8888; + constexpr const char* IP = "localhost"; + constexpr uint16_t PORT = 8888; // Initialize socket. - UDPSocket udpSocket(true); // "true" to use Connection on UDP. Default is "false". + UDPSocket<100> udpSocket(true); // "true" to use Connection on UDP. Default is "false". udpSocket.Connect(IP, PORT); // Send String: @@ -28,7 +28,7 @@ int main() }; */ - // You should do an input loop so the program will not terminated immediately: + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit") diff --git a/examples/udp-server.cpp b/examples/udp-server.cpp index b5366c7..990bb2d 100644 --- a/examples/udp-server.cpp +++ b/examples/udp-server.cpp @@ -1,4 +1,4 @@ -#include +#include "udpserver.hpp" #include using namespace std; @@ -6,22 +6,21 @@ using namespace std; int main() { // Initialize server socket.. - UDPServer udpServer; + UDPServer<> udpServer; // onMessageReceived will run when a message received with information of ip & port of sender: /*udpServer.onMessageReceived = [&](string message, string ipv4, uint16_t port) { //cout << ipv4 << ":" << port << " => " << message << endl; - // Just send without control: + // Echo to client: udpServer.SendTo("A!", ipv4, port); };*/ // If you want to use raw byte arrays: - udpServer.onRawMessageReceived = [&](const char* message, int length, string ipv4, uint16_t port) { - //cout << ipv4 << ":" << port << " => " << message << "(" << length << ")" << endl; + cout << ipv4 << ":" << port << " => " << message << "(" << length << ")" << endl; - // Just send without control: + // Echo to client: udpServer.SendTo(message, length, ipv4, port); }; @@ -32,7 +31,7 @@ int main() cout << errorCode << " : " << errorMessage << endl; }); - // You should do an input loop so the program will not terminated immediately: + // You should do an input loop, so the program won't terminate immediately string input; getline(cin, input); while (input != "exit")