-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathtcp_client.cpp
More file actions
90 lines (78 loc) · 2.85 KB
/
tcp_client.cpp
File metadata and controls
90 lines (78 loc) · 2.85 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#include <format>
#include <print>
#include <string>
#include "socket.h"
struct ClientConf {
static const uint32_t RecvBufSize = 4096;
static const uint32_t ConnRetrySec = 3;
static const uint32_t ConnTimeoutSec = 30;
static const uint32_t SendTimeoutSec = 0;
static const uint32_t RecvTimeoutSec = 0;
struct UserData {};
};
using TcpClient = SocketTcpClient<ClientConf>;
struct MsgHeader {
uint32_t body_len;
};
class MyClient : public TcpClient {
private:
bool is_first = true;
public:
MyClient(/* args */) {}
~MyClient() = default;
void onTcpConnectFailed() { std::println("connect error:{}", this->getLastError()); }
void onTcpConnected(TcpClient::Conn& conn) {
std::println("connected! first={}", is_first);
if (is_first) {
MsgHeader header;
std::string msg{"hello"};
header.body_len = msg.size();
this->write(&header, sizeof(MsgHeader));
this->write(msg.data(), header.body_len);
this->write(&header, sizeof(MsgHeader));
this->write(msg.data(), header.body_len);
}
is_first = false;
}
void onTcpDisconnect(TcpClient::Conn& conn) { std::println("disconnected!"); }
void onSendTimeout(TcpClient::Conn& conn) { std::println("send timeout"); }
void onRecvTimeout(TcpClient::Conn& conn) {
std::println("recv timeout");
conn.close("onRecvTimeout");
}
uint32_t onTcpData(TcpClient::Conn& conn, const uint8_t* data, uint32_t size) {
while (size >= sizeof(MsgHeader)) {
// 1. 解析 Header
const auto* header = reinterpret_cast<const MsgHeader*>(data);
uint32_t body_len = header->body_len;
uint32_t total_len = sizeof(MsgHeader) + body_len;
// 2. 检查缓冲区是否有完整的 Body
if (size < total_len) {
// 数据不足一个完整包,跳出循环,返回剩余字节数
// pollnet 会保留这些字节并在下次数据到达时拼接到 data 开头
break;
}
// 3. 处理 Body (使用 string_view 避免拷贝)
std::string_view body{
reinterpret_cast<const char*>(data) + sizeof(MsgHeader),
body_len};
std::println("Recv Body [len: {}]: {}", body_len, body);
// 4. 移动指针,准备处理下一个包
data += total_len;
size -= total_len;
}
// 返回值告知 pollnet 缓冲区还剩多少字节没处理(即半包部分)
return size;
}
};
int main(int argc, char const* argv[]) {
MyClient client;
if (!client.init("", "127.0.0.1", 1234)) {
std::println("init error:{}", client.getLastError());
exit(1);
}
while (true) {
client.poll(client);
}
return 0;
}