From 7ea99d366918e5d54b4a678397325a602b450f2d Mon Sep 17 00:00:00 2001 From: Simon Ninon Date: Mon, 13 Nov 2017 00:24:55 -0800 Subject: [PATCH 1/4] ipv6 support --- includes/tacopie/network/tcp_socket.hpp | 6 + sources/network/common/tcp_socket.cpp | 53 +++++++-- sources/network/unix/unix_tcp_socket.cpp | 108 ++++++++++++----- .../network/windows/windows_tcp_socket.cpp | 112 +++++++++++++----- 4 files changed, 216 insertions(+), 63 deletions(-) diff --git a/includes/tacopie/network/tcp_socket.hpp b/includes/tacopie/network/tcp_socket.hpp index cd2a02f..5f970d7 100644 --- a/includes/tacopie/network/tcp_socket.hpp +++ b/includes/tacopie/network/tcp_socket.hpp @@ -179,6 +179,12 @@ class tcp_socket { //! fd_t get_fd(void) const; +public: + //! + //! \return whether the host is IPV6 + //! + bool is_ipv6(void) const; + private: //! //! create a new socket if no socket has been initialized yet diff --git a/sources/network/common/tcp_socket.cpp b/sources/network/common/tcp_socket.cpp index 2324d8f..a7be8c0 100644 --- a/sources/network/common/tcp_socket.cpp +++ b/sources/network/common/tcp_socket.cpp @@ -44,11 +44,11 @@ #endif /* SOCKET_ERROR */ #if _WIN32 -#define __TACOPIE_LENGTH(size) static_cast(size) // for Windows, convert buffer size to `int` -#pragma warning ( disable: 4996 ) // for Windows, `inet_ntoa` is deprecated as it does not support IPv6 +#define __TACOPIE_LENGTH(size) static_cast(size) // for Windows, convert buffer size to `int` +#pragma warning(disable : 4996) // for Windows, `inet_ntoa` is deprecated as it does not support IPv6 #else -#define __TACOPIE_LENGTH(size) size // for Unix, keep buffer size as `size_t` -#endif /* _WIN32 */ +#define __TACOPIE_LENGTH(size) size // for Unix, keep buffer size as `size_t` +#endif /* _WIN32 */ namespace tacopie { @@ -139,14 +139,42 @@ tcp_socket::accept(void) { create_socket_if_necessary(); check_or_set_type(type::SERVER); - struct sockaddr_in client_info; - socklen_t client_info_struct_size = sizeof(client_info); + struct sockaddr_storage ss; + socklen_t addrlen = sizeof(ss); - fd_t client_fd = ::accept(m_fd, (struct sockaddr*) &client_info, &client_info_struct_size); + fd_t client_fd = ::accept(m_fd, reinterpret_cast(&ss), &addrlen); if (client_fd == __TACOPIE_INVALID_FD) { __TACOPIE_THROW(error, "accept() failure"); } - return {client_fd, inet_ntoa(client_info.sin_addr), client_info.sin_port, type::CLIENT}; + //! now determine host and port based on socket type + std::string saddr; + std::uint32_t port; + + //! ipv6 + if (ss.ss_family == AF_INET6) { + struct sockaddr_in6* addr6 = reinterpret_cast(&ss); + char buf[INET6_ADDRSTRLEN] = {}; + const char* addr = ::inet_ntop(ss.ss_family, &addr6->sin6_addr, buf, INET6_ADDRSTRLEN); + + if (addr) { + saddr = std::string("[") + addr + "]"; + } + + port = ntohs(addr6->sin6_port); + } + //! ipv4 + else { + struct sockaddr_in* addr4 = reinterpret_cast(&ss); + char buf[INET_ADDRSTRLEN] = {}; + const char* addr = ::inet_ntop(ss.ss_family, &addr4->sin_addr, buf, INET_ADDRSTRLEN); + + if (addr) { + saddr = addr; + } + + port = ntohs(addr4->sin_port); + } + return {client_fd, saddr, port, type::CLIENT}; } //! @@ -203,6 +231,15 @@ tcp_socket::get_fd(void) const { return m_fd; } +//! +//! ipv6 checking +//! + +bool +tcp_socket::is_ipv6(void) const { + return m_host.find(':') != std::string::npos; +} + //! //! comparison operator //! diff --git a/sources/network/unix/unix_tcp_socket.cpp b/sources/network/unix/unix_tcp_socket.cpp index 5b642df..630977c 100644 --- a/sources/network/unix/unix_tcp_socket.cpp +++ b/sources/network/unix/unix_tcp_socket.cpp @@ -47,15 +47,34 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t create_socket_if_necessary(); check_or_set_type(type::CLIENT); - struct sockaddr_un server_addr_un; - struct sockaddr_in server_addr_in; + struct sockaddr_storage ss; + socklen_t addr_len; + + //! 0-init addr info struct + std::memset(&ss, 0, sizeof(ss)); //! Handle case of unix sockets if port is 0 bool is_unix_socket = m_port == 0; if (is_unix_socket) { - std::memset(&server_addr_un, 0, sizeof(server_addr_un)); - server_addr_un.sun_family = AF_UNIX; - strncpy(server_addr_un.sun_path, host.c_str(), sizeof(server_addr_un.sun_path) - 1); + //! init sockaddr_un struct + struct sockaddr_un* addr = reinterpret_cast(&ss); + //! host + strncpy(addr->sun_path, host.c_str(), sizeof(addr->sun_path) - 1); + //! Remaining fields + ss.ss_family = AF_UNIX; + addr_len = sizeof(*addr); + } + else if (is_ipv6()) { + //! init sockaddr_in6 struct + struct sockaddr_in6* addr = reinterpret_cast(&ss); + //! convert addr + if (::inet_pton(AF_INET6, host.data(), &addr->sin6_addr) < 0) { + __TACOPIE_THROW(error, "inet_pton() failure"); + } + //! remaining fields + ss.ss_family = AF_INET6; + addr->sin6_port = htons(port); + addr_len = sizeof(*addr); } else { struct addrinfo* result = nullptr; @@ -65,19 +84,21 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t hints.ai_socktype = SOCK_STREAM; hints.ai_family = AF_INET; + //! resolve DNS if (getaddrinfo(host.c_str(), nullptr, &hints, &result) != 0) { __TACOPIE_THROW(error, "getaddrinfo() failure"); } - std::memset(&server_addr_in, 0, sizeof(server_addr_in)); - server_addr_in.sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; - server_addr_in.sin_port = htons(port); - server_addr_in.sin_family = AF_INET; + //! init sockaddr_in struct + struct sockaddr_in* addr = reinterpret_cast(&ss); + //! host + addr->sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; + //! Remaining fields + addr->sin_port = htons(port); + ss.ss_family = AF_INET; + addr_len = sizeof(*addr); freeaddrinfo(result); } - socklen_t addr_len = is_unix_socket ? sizeof(server_addr_un) : sizeof(server_addr_in); - const struct sockaddr* server_addr = is_unix_socket ? (const struct sockaddr*) &server_addr_un : (const struct sockaddr*) &server_addr_in; - if (timeout_msecs > 0) { //! for timeout connection handling: //! 1. set socket to non blocking @@ -98,7 +119,7 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t } } - int ret = ::connect(m_fd, server_addr, addr_len); + int ret = ::connect(m_fd, reinterpret_cast(&ss), addr_len); if (ret < 0 && errno != EINPROGRESS) { close(); __TACOPIE_THROW(error, "connect() failure"); @@ -150,35 +171,56 @@ tcp_socket::bind(const std::string& host, std::uint32_t port) { create_socket_if_necessary(); check_or_set_type(type::SERVER); - struct sockaddr_un server_addr_un; - struct sockaddr_in server_addr_in; + struct sockaddr_storage ss; + socklen_t addr_len; + + //! 0-init addr info struct + std::memset(&ss, 0, sizeof(ss)); //! Handle case of unix sockets if port is 0 bool is_unix_socket = m_port == 0; if (is_unix_socket) { - std::memset(&server_addr_un, 0, sizeof(server_addr_un)); - server_addr_un.sun_family = AF_UNIX; - strncpy(server_addr_un.sun_path, host.c_str(), sizeof(server_addr_un.sun_path) - 1); + //! init sockaddr_un struct + struct sockaddr_un* addr = reinterpret_cast(&ss); + //! host + strncpy(addr->sun_path, host.c_str(), sizeof(addr->sun_path) - 1); + //! remaining fields + ss.ss_family = AF_UNIX; + addr_len = sizeof(*addr); + } + else if (is_ipv6()) { + //! init sockaddr_in6 struct + struct sockaddr_in6* addr = reinterpret_cast(&ss); + //! convert addr + if (::inet_pton(AF_INET6, host.data(), &addr->sin6_addr) < 0) { + __TACOPIE_THROW(error, "inet_pton() failure"); + } + //! remaining fields + addr->sin6_port = htons(port); + ss.ss_family = AF_INET6; + addr_len = sizeof(*addr); } else { struct addrinfo* result = nullptr; + //! dns resolution if (getaddrinfo(host.c_str(), nullptr, nullptr, &result) != 0) { __TACOPIE_THROW(error, "getaddrinfo() failure"); } - std::memset(&server_addr_in, 0, sizeof(server_addr_in)); - server_addr_in.sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; - server_addr_in.sin_port = htons(port); - server_addr_in.sin_family = AF_INET; + //! init sockaddr_in struct + struct sockaddr_in* addr = reinterpret_cast(&ss); + //! addr + addr->sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; + //! remaining fields + addr->sin_port = htons(port); + ss.ss_family = AF_INET; + addr_len = sizeof(*addr); freeaddrinfo(result); } - socklen_t addr_len = is_unix_socket ? sizeof(server_addr_un) : sizeof(server_addr_in); - const struct sockaddr* server_addr = is_unix_socket ? (const struct sockaddr*) &server_addr_un : (const struct sockaddr*) &server_addr_in; - - if (::bind(m_fd, server_addr, addr_len) == -1) { __TACOPIE_THROW(error, "bind() failure"); } + if (::bind(m_fd, reinterpret_cast(&ss), addr_len) == -1) { __TACOPIE_THROW(error, "bind() failure"); } } //! @@ -205,7 +247,19 @@ tcp_socket::create_socket_if_necessary(void) { //! new TCP socket //! handle case of unix sockets by checking whether the port is 0 or not - m_fd = socket(m_port == 0 ? AF_UNIX : AF_INET, SOCK_STREAM, 0); + //! also handle ipv6 addr + short family; + if (m_port == 0) { + family = AF_UNIX; + } + else if (is_ipv6()) { + family = AF_INET6; + } + else { + family = AF_INET; + } + + m_fd = socket(family, SOCK_STREAM, 0); m_type = type::UNKNOWN; if (m_fd == __TACOPIE_INVALID_FD) { __TACOPIE_THROW(error, "tcp_socket::create_socket_if_necessary: socket() failure"); } diff --git a/sources/network/windows/windows_tcp_socket.cpp b/sources/network/windows/windows_tcp_socket.cpp index ae26ef1..242a727 100644 --- a/sources/network/windows/windows_tcp_socket.cpp +++ b/sources/network/windows/windows_tcp_socket.cpp @@ -41,22 +41,46 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t create_socket_if_necessary(); check_or_set_type(type::CLIENT); - struct addrinfo* result = nullptr; - struct addrinfo hints; - - memset(&hints, 0, sizeof(hints)); - hints.ai_socktype = SOCK_STREAM; - hints.ai_family = AF_INET; - - if (getaddrinfo(host.c_str(), nullptr, &hints, &result) != 0) { __TACOPIE_THROW(error, "getaddrinfo() failure"); } - - struct sockaddr_in server_addr; - std::memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; - server_addr.sin_port = htons(port); - server_addr.sin_family = AF_INET; - - freeaddrinfo(result); + struct sockaddr_storage ss; + socklen_t addr_len; + + //! 0-init addr info struct + std::memset(&ss, 0, sizeof(ss)); + + if (is_ipv6()) { + //! init sockaddr_in6 struct + struct sockaddr_in6* addr = reinterpret_cast(&ss); + //! convert addr + if (::inet_pton(AF_INET6, host.data(), &addr->sin6_addr) < 0) { + __TACOPIE_THROW(error, "inet_pton() failure"); + } + //! remaining fields + ss.ss_family = AF_INET6; + addr->sin6_port = htons(port); + addr_len = sizeof(*addr); + } + else { + struct addrinfo* result = nullptr; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + hints.ai_socktype = SOCK_STREAM; + hints.ai_family = AF_INET; + + //! resolve DNS + if (getaddrinfo(host.c_str(), nullptr, &hints, &result) != 0) { __TACOPIE_THROW(error, "getaddrinfo() failure"); } + + //! init sockaddr_in struct + struct sockaddr_in* addr = reinterpret_cast(&ss); + //! host + addr->sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; + //! Remaining fields + addr->sin_port = htons(port); + ss.ss_family = AF_INET; + addr_len = sizeof(*addr); + + freeaddrinfo(result); + } if (timeout_msecs > 0) { //! for timeout connection handling: @@ -80,7 +104,7 @@ tcp_socket::connect(const std::string& host, std::uint32_t port, std::uint32_t t } } - int ret = ::connect(m_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr)); + int ret = ::connect(m_fd, reinterpret_cast(&ss), addr_len); if (ret == -1 && WSAGetLastError() != WSAEWOULDBLOCK) { close(); __TACOPIE_THROW(error, "connect() failure"); @@ -133,21 +157,45 @@ tcp_socket::bind(const std::string& host, std::uint32_t port) { create_socket_if_necessary(); check_or_set_type(type::SERVER); - struct addrinfo* result = nullptr; + struct sockaddr_storage ss; + socklen_t addr_len; + + //! 0-init addr info struct + std::memset(&ss, 0, sizeof(ss)); - if (getaddrinfo(host.c_str(), nullptr, nullptr, &result) != 0) { - __TACOPIE_THROW(error, "getaddrinfo() failure"); + if (is_ipv6()) { + //! init sockaddr_in6 struct + struct sockaddr_in6* addr = reinterpret_cast(&ss); + //! convert addr + if (::inet_pton(AF_INET6, host.data(), &addr->sin6_addr) < 0) { + __TACOPIE_THROW(error, "inet_pton() failure"); + } + //! remaining fields + addr->sin6_port = htons(port); + ss.ss_family = AF_INET6; + addr_len = sizeof(*addr); } + else { + struct addrinfo* result = nullptr; + + //! dns resolution + if (getaddrinfo(host.c_str(), nullptr, nullptr, &result) != 0) { + __TACOPIE_THROW(error, "getaddrinfo() failure"); + } - struct sockaddr_in server_addr; - std::memset(&server_addr, 0, sizeof(server_addr)); - server_addr.sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; - server_addr.sin_port = htons(port); - server_addr.sin_family = AF_INET; + //! init sockaddr_in struct + struct sockaddr_in* addr = reinterpret_cast(&ss); + //! addr + addr->sin_addr = ((struct sockaddr_in*) (result->ai_addr))->sin_addr; + //! remaining fields + addr->sin_port = htons(port); + ss.ss_family = AF_INET; + addr_len = sizeof(*addr); - freeaddrinfo(result); + freeaddrinfo(result); + } - if (::bind(m_fd, (const struct sockaddr*) &server_addr, sizeof(server_addr)) == SOCKET_ERROR) { __TACOPIE_THROW(error, "bind() failure"); } + if (::bind(m_fd, reinterpret_cast(&ss), addr_len) == -1) { __TACOPIE_THROW(error, "bind() failure"); } } //! @@ -173,7 +221,15 @@ tcp_socket::create_socket_if_necessary(void) { if (m_fd != __TACOPIE_INVALID_FD) { return; } //! new TCP socket - m_fd = socket(AF_INET, SOCK_STREAM, 0); + //! handle ipv6 addr + short family; + if (is_ipv6()) { + family = AF_INET6; + } + else { + family = AF_INET; + } + m_fd = socket(family, SOCK_STREAM, 0); m_type = type::UNKNOWN; if (m_fd == __TACOPIE_INVALID_FD) { __TACOPIE_THROW(error, "tcp_socket::create_socket_if_necessary: socket() failure"); } From 987ad8562421e7f96ab9769c197af244807fd770 Mon Sep 17 00:00:00 2001 From: Simon Ninon Date: Mon, 13 Nov 2017 22:47:50 -0800 Subject: [PATCH 2/4] keep SOCKET_ERROR on windows --- sources/network/windows/windows_tcp_socket.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sources/network/windows/windows_tcp_socket.cpp b/sources/network/windows/windows_tcp_socket.cpp index 242a727..f8c31b5 100644 --- a/sources/network/windows/windows_tcp_socket.cpp +++ b/sources/network/windows/windows_tcp_socket.cpp @@ -195,7 +195,7 @@ tcp_socket::bind(const std::string& host, std::uint32_t port) { freeaddrinfo(result); } - if (::bind(m_fd, reinterpret_cast(&ss), addr_len) == -1) { __TACOPIE_THROW(error, "bind() failure"); } + if (::bind(m_fd, reinterpret_cast(&ss), addr_len) == SOCKET_ERROR) { __TACOPIE_THROW(error, "bind() failure"); } } //! From 3ac9db3d6ecd7d23e8b0da35bfd1640d9ab8b1d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=83=E8=B0=B7?= Date: Mon, 2 Jul 2018 16:35:49 +0800 Subject: [PATCH 3/4] Perfect examples --- examples/tcp_client.cpp | 77 ++++++++++++++++++++++----------------- examples/tcp_server.cpp | 80 +++++++++++++++++++++++------------------ 2 files changed, 90 insertions(+), 67 deletions(-) diff --git a/examples/tcp_client.cpp b/examples/tcp_client.cpp index d7d2d5d..68a4ac5 100644 --- a/examples/tcp_client.cpp +++ b/examples/tcp_client.cpp @@ -29,54 +29,67 @@ #ifdef _WIN32 #include + +//! Windows netword DLL init +struct _INIT_WSA_ { + + _INIT_WSA_() { + WORD version = MAKEWORD(2, 2); + WSADATA data; + + if (WSAStartup(version, &data) != 0) { + std::cerr << "WSAStartup() failure" << std::endl; + } + }; + + ~_INIT_WSA_() { + WSACleanup(); + }; + +} __INIT_WSA__; + + #endif /* _WIN32 */ + std::condition_variable cv; void signint_handler(int) { - cv.notify_all(); + cv.notify_all(); } void on_new_message(tacopie::tcp_client& client, const tacopie::tcp_client::read_result& res) { - if (res.success) { - std::cout << "Client recv data" << std::endl; - client.async_write({res.buffer, nullptr}); - client.async_read({1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1)}); - } - else { - std::cout << "Client disconnected" << std::endl; - client.disconnect(); - } + if (res.success) { + std::string str; + str.insert(str.begin(), res.buffer.begin(), res.buffer.end()); + std::cout << "Client recv data:" << str << std::endl; + //client.async_write({ res.buffer, nullptr }); + client.async_read({ 1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1) }); + } + else { + std::cout << "Client disconnected" << std::endl; + client.disconnect(); + } } int main(void) { -#ifdef _WIN32 - //! Windows netword DLL init - WORD version = MAKEWORD(2, 2); - WSADATA data; - - if (WSAStartup(version, &data) != 0) { - std::cerr << "WSAStartup() failure" << std::endl; - return -1; - } -#endif /* _WIN32 */ + tacopie::tcp_client client; + client.connect("localhost", 3001); + client.async_read({ 1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1) }); - tacopie::tcp_client client; - client.connect("127.0.0.1", 3001); - client.async_read({1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1)}); + std::string str = "hello world!"; + std::vector buff; + buff.insert(buff.begin(), str.begin(), str.end()); - signal(SIGINT, &signint_handler); + client.async_write({ buff, nullptr }); + signal(SIGINT, &signint_handler); - std::mutex mtx; - std::unique_lock lock(mtx); - cv.wait(lock); - -#ifdef _WIN32 - WSACleanup(); -#endif /* _WIN32 */ + std::mutex mtx; + std::unique_lock lock(mtx); + cv.wait(lock); - return 0; + return 0; } diff --git a/examples/tcp_server.cpp b/examples/tcp_server.cpp index 90be800..232d6d1 100644 --- a/examples/tcp_server.cpp +++ b/examples/tcp_server.cpp @@ -29,57 +29,67 @@ #ifdef _WIN32 #include + +//! Windows netword DLL init +struct _INIT_WSA_ { + + _INIT_WSA_() { + WORD version = MAKEWORD(2, 2); + WSADATA data; + + if (WSAStartup(version, &data) != 0) { + std::cerr << "WSAStartup() failure" << std::endl; + } + }; + + ~_INIT_WSA_() { + WSACleanup(); + }; + +} __INIT_WSA__; + #endif /* _WIN32 */ std::condition_variable cv; void signint_handler(int) { - cv.notify_all(); + cv.notify_all(); } void on_new_message(const std::shared_ptr& client, const tacopie::tcp_client::read_result& res) { - if (res.success) { - std::cout << "Client recv data" << std::endl; - client->async_write({res.buffer, nullptr}); - client->async_read({1024, std::bind(&on_new_message, client, std::placeholders::_1)}); - } - else { - std::cout << "Client disconnected" << std::endl; - client->disconnect(); - } + if (res.success) { + std::string str; + str.insert(str.begin(), res.buffer.begin(), res.buffer.end()); + + std::cout << "Client recv data" << "[" << client->get_host() << ":" << client->get_port() << "]:" + << str << std::endl; + client->async_write({ res.buffer, nullptr }); + client->async_read({ 1024, std::bind(&on_new_message, client, std::placeholders::_1) }); + } + else { + std::cout << "Client disconnected" << "[" << client->get_host() << ":" << client->get_port() << "]" << std::endl; + client->disconnect(); + } } int main(void) { -#ifdef _WIN32 - //! Windows netword DLL init - WORD version = MAKEWORD(2, 2); - WSADATA data; - - if (WSAStartup(version, &data) != 0) { - std::cerr << "WSAStartup() failure" << std::endl; - return -1; - } -#endif /* _WIN32 */ - tacopie::tcp_server s; - s.start("127.0.0.1", 3001, [](const std::shared_ptr& client) -> bool { - std::cout << "New client" << std::endl; - client->async_read({1024, std::bind(&on_new_message, client, std::placeholders::_1)}); - return true; - }); + tacopie::tcp_server s; + s.start("localhost", 3001, [](const std::shared_ptr& client) -> bool { + std::cout << + "New client:" << "[" <get_host() << ":" << client->get_port() << "]" << std::endl; + client->async_read({ 1024, std::bind(&on_new_message, client, std::placeholders::_1) }); + return true; + }); - signal(SIGINT, &signint_handler); + signal(SIGINT, &signint_handler); - std::mutex mtx; - std::unique_lock lock(mtx); - cv.wait(lock); - -#ifdef _WIN32 - WSACleanup(); -#endif /* _WIN32 */ + std::mutex mtx; + std::unique_lock lock(mtx); + cv.wait(lock); - return 0; + return 0; } From 5707f20879ee14806dfc4299052e83cf6897fe7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=85=83=E8=B0=B7?= Date: Mon, 2 Jul 2018 17:31:57 +0800 Subject: [PATCH 4/4] connect error --- examples/tcp_client.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/examples/tcp_client.cpp b/examples/tcp_client.cpp index 68a4ac5..971edae 100644 --- a/examples/tcp_client.cpp +++ b/examples/tcp_client.cpp @@ -77,7 +77,16 @@ on_new_message(tacopie::tcp_client& client, const tacopie::tcp_client::read_resu int main(void) { tacopie::tcp_client client; - client.connect("localhost", 3001); + try + { + client.connect("localhost", 3001); + } + catch (const std::exception& e) + { + std::cout << "connect error:" << e.what() << std::endl; + return 0; + } + client.async_read({ 1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1) }); std::string str = "hello world!";