From a2116fd143ce791a2db8db93df0f2b496f531a84 Mon Sep 17 00:00:00 2001 From: ackimixs Date: Thu, 21 Mar 2024 21:27:39 +0100 Subject: [PATCH] initial commit --- .gitignore | 4 ++ CMakeLists.txt | 39 +++++++++++++++++++ TCPSocket.pc.in | 12 ++++++ example/CMakeLists.txt | 11 ++++++ example/client.test.cpp | 22 +++++++++++ include/TCPSocket/TCPClient.hpp | 33 +++++++++++++++++ include/TCPSocket/TCPUtils.hpp | 37 ++++++++++++++++++ src/TCPClient.cpp | 66 +++++++++++++++++++++++++++++++++ 8 files changed, 224 insertions(+) create mode 100644 .gitignore create mode 100644 CMakeLists.txt create mode 100644 TCPSocket.pc.in create mode 100644 example/CMakeLists.txt create mode 100644 example/client.test.cpp create mode 100644 include/TCPSocket/TCPClient.hpp create mode 100644 include/TCPSocket/TCPUtils.hpp create mode 100644 src/TCPClient.cpp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f7428b --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/cmake-build-debug/ +/build/ +/example/cmake-build-debug/ +/example/build/ \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..096fda9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required(VERSION 3.25) +project(TCPSocket VERSION 0.1.2 DESCRIPTION "TCP Socket" LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 17) + +# Specify C++ Standard +set(CMAKE_CXX_STANDARD 17) + +# Add the source files +set(SOURCES + src/TCPClient.cpp +) + +# Add the header files +set(HEADERS + include/TCPSocket/TCPClient.hpp + include/TCPSocket/TCPUtils.hpp +) + +add_library(TCPSocket SHARED ${SOURCES} ${HEADERS}) + +set_target_properties(TCPSocket PROPERTIES + VERSION ${PROJECT_VERSION} + SOVERSION ${PROJECT_VERSION_MAJOR} + PUBLIC_HEADER "${HEADERS}" +) + +target_include_directories(TCPSocket PRIVATE include) +target_include_directories(TCPSocket PRIVATE src) + +include(GNUInstallDirs) + +install(TARGETS TCPSocket + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/TCPSocket) + +configure_file(TCPSocket.pc.in TCPSocket.pc @ONLY) + +install(FILES ${CMAKE_BINARY_DIR}/TCPSocket.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig) \ No newline at end of file diff --git a/TCPSocket.pc.in b/TCPSocket.pc.in new file mode 100644 index 0000000..91fdfeb --- /dev/null +++ b/TCPSocket.pc.in @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${exec_prefix}/@CMAKE_INSTALL_LIBDIR@/TCPSocket +includedir=${prefix}/@CMAKE_INSTALL_INCLUDEDIR@ + +Name: @PROJECT_NAME@ +Description: @PROJECT_DESCRIPTION@ +Version: @PROJECT_VERSION@ + +Requires: +Libs: -L${libdir} -lmylib +Cflags: -I${includedir} \ No newline at end of file diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt new file mode 100644 index 0000000..2700e0c --- /dev/null +++ b/example/CMakeLists.txt @@ -0,0 +1,11 @@ +cmake_minimum_required(VERSION 3.25) +project(example) + +set(CMAKE_CXX_STANDARD 17) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(TCPSocket REQUIRED TCPSocket) + +add_executable(client client.test.cpp) + +target_link_libraries(client TCPSocket) diff --git a/example/client.test.cpp b/example/client.test.cpp new file mode 100644 index 0000000..8bfd8b6 --- /dev/null +++ b/example/client.test.cpp @@ -0,0 +1,22 @@ +#include + +int main() { + TCPClient client("127.0.0.1", 8082); // Replace "127.0.0.1" with the IP address of your server and 8080 with the port number + + client.start(); + + while (true) { + std::string message; + std::cout << "Enter message ('quit' to exit): "; + std::getline(std::cin, message); + + if (message == "quit") { + client.stop(); + break; + } + + client.sendMessage(message.c_str()); + } + + return 0; +} diff --git a/include/TCPSocket/TCPClient.hpp b/include/TCPSocket/TCPClient.hpp new file mode 100644 index 0000000..178fa9d --- /dev/null +++ b/include/TCPSocket/TCPClient.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +class TCPClient { + int clientSocket; + sockaddr_in serverAddress; + bool running; + //void (*callback)(const std::string& message); + +public: + TCPClient(const char* serverIP = "127.0.0.1", int port = 8080/*, void (*callback)(const std::string& message) = [](const std::string& message) { std::cout << message << std::endl; }*/); + + void sendMessage(const char* message); + + void receiveMessages(); + + void start(); + + void stop(); + + virtual ~TCPClient(); + + virtual void handleMessage(const std::string& message); + + //void setCallback(void (*callback)(const std::string& message)); +}; \ No newline at end of file diff --git a/include/TCPSocket/TCPUtils.hpp b/include/TCPSocket/TCPUtils.hpp new file mode 100644 index 0000000..af27ee0 --- /dev/null +++ b/include/TCPSocket/TCPUtils.hpp @@ -0,0 +1,37 @@ +#pragma once + +#include + +inline bool startWith(const std::string& str, const std::string& start) +{ + return str.rfind(start, 0) == 0; +} + +inline bool endsWith(const std::string& str, const std::string& end) +{ + if (str.length() >= end.length()) + { + return (0 == str.compare(str.length() - end.length(), end.length(), end)); + } + return false; +} + +inline bool contains(const std::string& str, const std::string& sub) +{ + return str.find(sub) != std::string::npos; +} + +inline std::vector split(const std::string& str, const std::string& delimiter) +{ + std::vector tokens; + size_t prev = 0, pos = 0; + do + { + pos = str.find(delimiter, prev); + if (pos == std::string::npos) pos = str.length(); + std::string token = str.substr(prev, pos - prev); + if (!token.empty()) tokens.push_back(token); + prev = pos + delimiter.length(); + } while (pos < str.length() && prev < str.length()); + return tokens; +} \ No newline at end of file diff --git a/src/TCPClient.cpp b/src/TCPClient.cpp new file mode 100644 index 0000000..558ff3d --- /dev/null +++ b/src/TCPClient.cpp @@ -0,0 +1,66 @@ +#include "TCPSocket/TCPClient.hpp" + +TCPClient::TCPClient(const char* serverIP, int port/*, void (*callback)(const std::string& message)*/) : running(true)/*, callback(callback)*/ { + clientSocket = socket(AF_INET, SOCK_STREAM, 0); + if (clientSocket == -1) { + std::cerr << "Socket creation failed" << std::endl; + exit(EXIT_FAILURE); + } + + serverAddress.sin_family = AF_INET; + serverAddress.sin_port = htons(port); + + if (inet_pton(AF_INET, serverIP, &serverAddress.sin_addr) <= 0) { + std::cerr << "Invalid address or address not supported" << std::endl; + exit(EXIT_FAILURE); + } + + if (connect(clientSocket, (struct sockaddr*)&serverAddress, sizeof(serverAddress)) == -1) { + std::cerr << "Connection failed" << std::endl; + exit(EXIT_FAILURE); + } +} + +void TCPClient::sendMessage(const char* message) { + send(clientSocket, message, strlen(message), 0); +} + +void TCPClient::receiveMessages() { + char buffer[1024] = {0}; + while (running) { + ssize_t valread = recv(clientSocket, buffer, sizeof(buffer), 0); + if (valread > 0) { + handleMessage(buffer); + memset(buffer, 0, sizeof(buffer)); // Clear buffer + } else if (valread == 0) { + std::cerr << "Connection closed by server" << std::endl; + break; + } else { + std::cerr << "Error in receiving message" << std::endl; + break; + } + } + running = false; +} + +void TCPClient::handleMessage(const std::string& message) { + std::cout << message << std::endl; +} + +TCPClient::~TCPClient() { + stop(); +} + +void TCPClient::start() { + std::thread receiveThread(&TCPClient::receiveMessages, this); + receiveThread.detach(); +} + +void TCPClient::stop() { + running = false; + close(clientSocket); +} + +/*void TCPClient::setCallback(void (*callback)(const std::string& message)) { + this->callback = callback; +}*/ \ No newline at end of file