TcpClient/Reactor 框架

This commit is contained in:
2026-09-08 12:38:28 +08:00
parent ac4045a979
commit aae773a7fa
11 changed files with 801 additions and 1 deletions
+138
View File
@@ -0,0 +1,138 @@
#include <c_TcpClient.h>
#include <c_AddrInfo.h>
/* ------------------------------------------------------------------------------------------------------------------ */
/* */
c_err_t c_TcpClient_Connect(c_TcpClient_t* self, int family, const char* server, const char* port, void* args, c_Allocator_t* allocator) {
if (!self || (!server && !port)) return C_ERR_PARAM;
self->allocator = allocator ? *allocator : c_DefaultAllocator;
self->sock = C_INVALID_SOCKET;
self->is_linked = C_FALSE;
/* 1. Resolve network address dynamically using your custom c_AddrInfo_t wrapper */
c_AddrInfo_t addr_resolver;
c_err_t err = c_AddrInfo_Init(&addr_resolver, family, SOCK_STREAM, 0, server, port);
if (err != C_ERR_OK) {
c_Socket_Destroy();
return C_ERR_FAIL;
}
c_AddrInfo_t curr_node = addr_resolver;
c_bool_t connected = C_FALSE;
/* 2. Traverse the resolved address link chain until a connection succeeds */
while (curr_node.addrinfo_p != NULL) {
/* Open the system socket using descriptors from addrinfo */
self->sock = socket(
c_AddrInfo_GetFamily(&curr_node),
c_AddrInfo_GetSockType(&curr_node),
c_AddrInfo_GetProtocol(&curr_node)
);
if (c_Socket_IsValid(self->sock)) {
/* Execute synchronous network connect transaction handshake */
int rc = connect(self->sock, curr_node.addrinfo_p->ai_addr, (int)curr_node.addrinfo_p->ai_addrlen);
if (rc != C_SOCKET_ERROR) {
connected = C_TRUE;
break; /* Route successfully established, break chain safely */
}
/* Connection failed on this node: close socket using custom macro helper */
c_Socket_Close(self->sock);
}
/* Shift forward to parse alternative network address frames */
c_AddrInfo_GetNext(&curr_node, &curr_node);
}
c_AddrInfo_Destroy(&addr_resolver);
if (!connected) {
if (self->fnOnError) {
self->fnOnError(self, C_TCPCLIENT_ERR_ON_CONNECT, args);
}
return C_ERR_FAIL; /* Host unreachable or timed out */
}
self->is_linked = C_TRUE;
if (self->fnOnConnect) {
if (!self->fnOnConnect(self, args)) {
self->is_linked = C_FALSE;
}
}
return C_SUCCESS;
}
c_err_t c_TcpClient_Send(c_TcpClient_t* self, const void* buffer, c_size_t bytes_to_send, c_size_t* out_bytes_sent) {
if (!self || !self->is_linked || !c_Socket_IsValid(self->sock) || !buffer) return C_ERR_PARAM;
if (bytes_to_send == 0) {
if (out_bytes_sent) *out_bytes_sent = 0;
return C_SUCCESS;
}
c_size_t total_sent = 0;
const char* ptr = (const char*)buffer;
/* Loop until the complete raw buffer payload block is flushed out to the wire */
while (total_sent < bytes_to_send) {
c_size_t remaining = bytes_to_send - total_sent;
#if defined(_WIN32) || defined(_WIN64)
int n = send(self->sock, ptr + total_sent, (int)remaining, 0);
#else
#ifdef MSG_NOSIGNAL
ssize_t n = send(self->sock, ptr + total_sent, (size_t)remaining, MSG_NOSIGNAL); /* Guard against SIGPIPE */
#else
ssize_t n = send(self->sock, ptr + total_sent, (size_t)remaining, 0);
#endif
#endif
if (n == C_SOCKET_ERROR) {
if (out_bytes_sent) *out_bytes_sent = total_sent;
return C_ERR_FAIL; /* Network pipeline transmission error */
}
total_sent += (c_size_t)n;
}
if (out_bytes_sent) *out_bytes_sent = total_sent;
return C_SUCCESS;
}
c_err_t c_TcpClient_Recv(c_TcpClient_t* self, void* buffer, c_size_t max_bytes_to_read, c_size_t* out_bytes_read) {
if (!self || !self->is_linked || !c_Socket_IsValid(self->sock) || !buffer || max_bytes_to_read == 0) return C_ERR_PARAM;
#if defined(_WIN32) || defined(_WIN64)
int n = recv(self->sock, (char*)buffer, (int)max_bytes_to_read, 0);
#else
ssize_t n = recv(self->sock, buffer, (size_t)max_bytes_to_read, 0);
#endif
if (n == 0) {
if (out_bytes_read) *out_bytes_read = 0;
return C_ERR_EOF; /* Connection clean cut closed by peer node */
}
if (n == C_SOCKET_ERROR) {
if (out_bytes_read) *out_bytes_read = 0;
return C_ERR_FAIL; /* Network pipeline failure */
}
if (out_bytes_read) *out_bytes_read = (c_size_t)n;
return C_SUCCESS;
}
void c_TcpClient_Destroy(c_TcpClient_t* self) {
if (!self) return;
self->is_linked = C_FALSE;
if (c_Socket_IsValid(self->sock)) {
c_Socket_Close(self->sock);
}
if (self->reactor) c_TcpClientReactor_Destroy(self->reactor);
}
c_err_t c_TcpClient_PollEvents(c_TcpClient_t* self, long timeout_ms, void* args) {
if (!self || !self->reactor || self->is_linked==C_FALSE) return C_ERR_PARAM;
return c_TcpClientReactor_Poll(self->reactor, timeout_ms, self, args);
}