diff --git a/CMakeLists.txt b/CMakeLists.txt index 4df006f..b7b8f5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,5 +10,5 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static -g -O2") add_subdirectory(${PROJECT_SOURCE_DIR}/include/ouc_server) -add_executable(test "${PROJECT_SOURCE_DIR}/examples/epoll_tcp_loop.cpp") +add_executable(test "${PROJECT_SOURCE_DIR}/examples/test_tcp_socket.cpp") target_link_libraries(test PRIVATE ouc_server_lib) \ No newline at end of file diff --git a/examples/test_tcp_socket.cpp b/examples/test_tcp_socket.cpp new file mode 100644 index 0000000..36c17f2 --- /dev/null +++ b/examples/test_tcp_socket.cpp @@ -0,0 +1,55 @@ +#include + +#include +#include +#include +#include +#include +#include + +int main() +{ + using namespace ouc_server::ouc_socket; + + auto server = TCPSocket::create(); + if (!server.bind("127.0.0.1", 8080)) + { + perror("socket"); + return 1; + } + + if (!server.listen()) + { + perror("listen"); + return 1; + } + puts("Server listening on port 8080..."); + + auto client = server.accept(); + while (client.get_fd() < 0) + { + client = server.accept(); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + } + puts("Client conntected"); + + while (true) + { + char buf[1024]; + ssize_t n = client.recv(buf, sizeof(buf)); + + if (n <= 0) + continue; + if (!memcmp("exit", buf, 4)) + break; + + std::string data(buf, n); + std::cout << "Receive data: " << data; + + // client.send("Receive!: "); + // client.send(buf); + } + + client.close(); + server.close(); +} \ No newline at end of file diff --git a/include/ouc_server/socket/tcp_socket.cpp b/include/ouc_server/socket/tcp_socket.cpp new file mode 100644 index 0000000..b3ae853 --- /dev/null +++ b/include/ouc_server/socket/tcp_socket.cpp @@ -0,0 +1,75 @@ +#include + +#include +#include +#include +#include + +namespace ouc_server +{ + namespace ouc_socket + { + TCPSocket::TCPSocket(int fd) + : listen_fd(fd) + { + } + + TCPSocket::TCPSocket(TCPSocket &&other) + : listen_fd(other.listen_fd) + { + other.listen_fd = -1; + } + + TCPSocket &TCPSocket::operator=(TCPSocket &&other) + { + if (this == &other) + return *this; + + if (listen_fd >= 0) + close(); + listen_fd = other.listen_fd; + other.listen_fd = -1; + + return *this; + } + + TCPSocket TCPSocket::create() + { + int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); + if (fd < 0) + perror("socket"); + + int opt = 1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); + return TCPSocket(fd); + } + + bool TCPSocket::bind(const std::string &ip, uint16_t port) + { + sockaddr_in addr{}; + addr.sin_family = AF_INET; + addr.sin_port = htons(port); + if (inet_pton(AF_INET, ip.c_str(), &addr.sin_addr) != 1) + return false; + return ::bind(listen_fd, (sockaddr *)&addr, sizeof(addr)) == 0; + } + + bool TCPSocket::listen(int backlog) { return ::listen(listen_fd, backlog) == 0; } + + TCPSocket TCPSocket::accept() + { + int client_fd = ::accept4(listen_fd, nullptr, nullptr, SOCK_NONBLOCK); + if (client_fd < 0) + return TCPSocket(); + return TCPSocket(client_fd); + } + + bool TCPSocket::close() { return ::close(listen_fd) == 0; } + + ssize_t TCPSocket::send(const char *buf, size_t len) { return ::send(listen_fd, buf, len, 0); } + + ssize_t TCPSocket::send(const char *buf) { return this->send(buf, sizeof(buf)); } + + ssize_t TCPSocket::recv(void *buf, size_t len) { return ::recv(listen_fd, buf, len, 0); } + } +} \ No newline at end of file diff --git a/include/ouc_server/socket/tcp_socket.hpp b/include/ouc_server/socket/tcp_socket.hpp new file mode 100644 index 0000000..a34357a --- /dev/null +++ b/include/ouc_server/socket/tcp_socket.hpp @@ -0,0 +1,43 @@ +#ifndef INCLUDE_OUC_SERVER_TCP_SOCKET +#define INCLUDE_OUC_SERVER_TCP_SOCKET + +#include +#include + +namespace ouc_server +{ + namespace ouc_socket + { + class TCPSocket + { + private: + int listen_fd; + + public: + explicit TCPSocket(int = -1); + + TCPSocket(const TCPSocket &) = delete; + TCPSocket &operator=(const TCPSocket &) = delete; + + TCPSocket(TCPSocket &&); + TCPSocket &operator=(TCPSocket &&); + + static TCPSocket create(); + + public: + int get_fd() const { return listen_fd; } + + bool bind(const std::string &, uint16_t); + bool listen(int = 128); + TCPSocket accept(); + bool close(); + + public: + ssize_t send(const char *, size_t); + ssize_t send(const char *); + ssize_t recv(void *, size_t); + }; + } +} + +#endif // INCLUDE_OUC_SERVER_TCP_SOCKET \ No newline at end of file