MyLib
This commit is contained in:
156
Socket/TCP.cpp
Normal file
156
Socket/TCP.cpp
Normal file
@ -0,0 +1,156 @@
|
||||
#include "TCP.h"
|
||||
|
||||
void TCPSocket::create_socket() {
|
||||
sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (sockfd_ == INVALID_SOCKET_VALUE) {
|
||||
throw std::runtime_error("Socket creation failed");
|
||||
}
|
||||
}
|
||||
|
||||
void TCPSocket::close_socket() {
|
||||
if (sockfd_ != INVALID_SOCKET_VALUE) {
|
||||
#ifdef _WIN32
|
||||
closesocket(sockfd_);
|
||||
#else
|
||||
close(sockfd_);
|
||||
#endif
|
||||
sockfd_ = INVALID_SOCKET_VALUE;
|
||||
}
|
||||
connected_.store(false);
|
||||
}
|
||||
|
||||
TCPSocket::~TCPSocket() {
|
||||
close_socket();
|
||||
}
|
||||
|
||||
bool TCPSocket::is_connected() const { return connected_.load(); }
|
||||
|
||||
void TCPClient::connect(const std::string &ip, uint16_t port) {
|
||||
create_socket();
|
||||
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
inet_pton(AF_INET, ip.c_str(), &addr.sin_addr);
|
||||
|
||||
if (::connect(sockfd_, (sockaddr *) &addr, sizeof(addr)) != 0) {
|
||||
close_socket();
|
||||
throw std::runtime_error("Connection failed");
|
||||
}
|
||||
connected_.store(true);
|
||||
}
|
||||
|
||||
size_t TCPClient::send(const void *data, size_t size) {
|
||||
#ifdef _WIN32
|
||||
auto sent = ::send(sockfd_, (const char *) data, (int) size, 0);
|
||||
#else
|
||||
auto sent = ::send(sockfd_, data, size, 0);
|
||||
#endif
|
||||
|
||||
if (sent == SOCKET_ERROR) {
|
||||
connected_.store(false);
|
||||
throw std::runtime_error("Send failed");
|
||||
}
|
||||
return static_cast<size_t>(sent);
|
||||
}
|
||||
|
||||
size_t TCPClient::send(const std::string &data) {
|
||||
#ifdef _WIN32
|
||||
auto sent = ::send(sockfd_, data.c_str(), static_cast<int>(data.size()), 0);
|
||||
#else
|
||||
auto sent = ::send(sockfd_, data.c_str(), data.size(), 0);
|
||||
#endif
|
||||
|
||||
if (sent == SOCKET_ERROR) {
|
||||
connected_.store(false);
|
||||
throw std::runtime_error("Send failed");
|
||||
}
|
||||
return static_cast<size_t>(sent);
|
||||
}
|
||||
|
||||
size_t TCPClient::receive(void *buffer, size_t buffer_size) {
|
||||
#ifdef _WIN32
|
||||
auto received = ::recv(sockfd_, (char *) buffer, (int) buffer_size, 0);
|
||||
#else
|
||||
auto received = ::recv(sockfd_, buffer, buffer_size, 0);
|
||||
#endif
|
||||
|
||||
if (received == 0) {
|
||||
connected_.store(false);
|
||||
return 0;
|
||||
}
|
||||
if (received == SOCKET_ERROR) {
|
||||
connected_.store(false);
|
||||
throw std::runtime_error("Receive failed");
|
||||
}
|
||||
return static_cast<size_t>(received);
|
||||
}
|
||||
|
||||
void TCPServer::listen(uint16_t port, int backlog) {
|
||||
create_socket();
|
||||
|
||||
sockaddr_in addr{};
|
||||
addr.sin_family = AF_INET;
|
||||
addr.sin_port = htons(port);
|
||||
addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
if (bind(sockfd_, (sockaddr *) &addr, sizeof(addr)) != 0) {
|
||||
close_socket();
|
||||
throw std::runtime_error("Bind failed");
|
||||
}
|
||||
|
||||
if (::listen(sockfd_, backlog) != 0) {
|
||||
close_socket();
|
||||
throw std::runtime_error("Listen failed");
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<TCPClient> TCPServer::accept() {
|
||||
sockaddr_in client_addr{};
|
||||
socklen_t addr_len = sizeof(client_addr);
|
||||
|
||||
auto client_sock = ::accept(sockfd_, (sockaddr *) &client_addr, &addr_len);
|
||||
if (client_sock == INVALID_SOCKET_VALUE) {
|
||||
throw std::runtime_error("Accept failed");
|
||||
}
|
||||
|
||||
auto client = std::make_shared<TCPClient>();
|
||||
client->sockfd_ = client_sock;
|
||||
client->connected_.store(true);
|
||||
return client;
|
||||
}
|
||||
|
||||
void AsyncTCPClient::start_async() {
|
||||
running_.store(true);
|
||||
recv_thread_ = std::thread([this]() {
|
||||
std::vector<uint8_t> buffer(4096);
|
||||
while (running_.load()) {
|
||||
try {
|
||||
auto size = receive(buffer.data(), buffer.size());
|
||||
if (size > 0) {
|
||||
std::lock_guard<std::mutex> lock(queue_mutex_);
|
||||
recv_queue_.emplace(buffer.begin(), buffer.begin() + static_cast<long long>(size));
|
||||
}
|
||||
}
|
||||
catch (...) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool AsyncTCPClient::try_pop(std::vector<uint8_t> &data) {
|
||||
std::lock_guard<std::mutex> lock(queue_mutex_);
|
||||
if (recv_queue_.empty()) return false;
|
||||
data = std::move(recv_queue_.front());
|
||||
recv_queue_.pop();
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncTCPClient::~AsyncTCPClient() {
|
||||
running_.store(false);
|
||||
if (recv_thread_.joinable()) {
|
||||
recv_thread_.join();
|
||||
}
|
||||
close_socket();
|
||||
}
|
Reference in New Issue
Block a user