载入中...
搜索中...
未找到
UdpLink.cpp
浏览该文件的文档.
1#include "network/UdpLink.h"
2#include "network/Network.h"
3#include "network/UdpSocket.h"
4#include "data/ByteData.h"
5
6#include <algorithm>
7#include <chrono>
8#include <cstring>
9
10namespace eve::network {
11
12namespace {
13
14constexpr uint8_t kMagic0 = 'E';
15constexpr uint8_t kMagic1 = 'V';
16constexpr uint8_t kVersion = 1;
17constexpr size_t kHeaderLen = 18;
18constexpr size_t kMaxOutOfOrder = 2048;
19constexpr size_t kMaxFragments = 64;
20constexpr size_t kMaxFragCount = 2048;
21constexpr int64_t kFragExpireMs = 5000;
22constexpr int64_t kPingIntervalMs = 500;
23constexpr uint8_t kFragFlag = 1;
24
25enum PktType : uint8_t {
26 T_RELIABLE = 0,
27 T_UNRELIABLE = 1,
28 T_ORDERED = 2,
29 T_ACK = 3,
30 T_PING = 4,
31 T_PONG = 5,
32};
33
34int64_t nowMs() {
35 return std::chrono::duration_cast<std::chrono::milliseconds>(
36 std::chrono::steady_clock::now().time_since_epoch())
37 .count();
38}
39
40void putU8(std::vector<char>& v, uint8_t x) {
41 v.push_back(static_cast<char>(x));
42}
43
44void putU16(std::vector<char>& v, uint16_t x) {
45 v.push_back(static_cast<char>(x & 0xff));
46 v.push_back(static_cast<char>((x >> 8) & 0xff));
47}
48
49void putU32(std::vector<char>& v, uint32_t x) {
50 for (int i = 0; i < 4; ++i) {
51 v.push_back(static_cast<char>((x >> (8 * i)) & 0xff));
52 }
53}
54
55struct PktView {
56 const char* p = nullptr;
57 size_t n = 0;
58 size_t pos = 0;
59 bool ok = true;
60
61 bool u8(uint8_t& out) {
62 if (!ok || n - pos < 1) {
63 ok = false;
64 return false;
65 }
66 out = static_cast<uint8_t>(p[pos++]);
67 return true;
68 }
69
70 bool u16(uint16_t& out) {
71 if (!ok || n - pos < 2) {
72 ok = false;
73 return false;
74 }
75 out = static_cast<uint16_t>(uint8_t(p[pos])) |
76 (static_cast<uint16_t>(uint8_t(p[pos + 1])) << 8);
77 pos += 2;
78 return true;
79 }
80
81 bool u32(uint32_t& out) {
82 if (!ok || n - pos < 4) {
83 ok = false;
84 return false;
85 }
86 out = static_cast<uint32_t>(uint8_t(p[pos])) |
87 (static_cast<uint32_t>(uint8_t(p[pos + 1])) << 8) |
88 (static_cast<uint32_t>(uint8_t(p[pos + 2])) << 16) |
89 (static_cast<uint32_t>(uint8_t(p[pos + 3])) << 24);
90 pos += 4;
91 return true;
92 }
93
94 const char* rest(size_t& len) const {
95 len = n - pos;
96 return p + pos;
97 }
98};
99
100bool splitAddress(const std::string& addr, std::string& host, uint16_t& port) {
101 if (addr.empty()) return false;
102 if (addr.front() == '[') {
103 auto close = addr.find(']');
104 if (close == std::string::npos || close + 2 >= addr.size() || addr[close + 1] != ':')
105 return false;
106 host = addr.substr(1, close - 1);
107 port = static_cast<uint16_t>(std::atoi(addr.c_str() + close + 2));
108 return port != 0;
109 }
110 auto colon = addr.rfind(':');
111 if (colon == std::string::npos || colon == 0) return false;
112 host = addr.substr(0, colon);
113 port = static_cast<uint16_t>(std::atoi(addr.c_str() + colon + 1));
114 return port != 0;
115}
116
117// true if b is strictly after a in the u32 circular order (within a 2^31 window)
118inline bool after(uint32_t a, uint32_t b) {
119 return a != b && (b - a) < 0x80000000u;
120}
121
122} // namespace
123
124UdpLink::UdpLink(Network* net, UdpSocket* sock) : net_(net), sock_(sock) {}
125
127 sendQueue_.clear();
128 fragments_.clear();
129 outOfOrder_.clear();
130 unrelOrdBuf_.clear();
131}
132
133bool UdpLink::setRemote(std::string host, uint16_t port) {
134 if (host.empty() || port == 0) return false;
135 remoteHost_ = std::move(host);
136 remotePort_ = port;
137 remote_ = remoteHost_ + ":" + std::to_string(remotePort_);
138 remoteSet_ = true;
139 return true;
140}
141
142bool UdpLink::setRemoteString(const std::string& addr) {
143 std::string host;
144 uint16_t port = 0;
145 if (!splitAddress(addr, host, port)) return false;
146 return setRemote(std::move(host), port);
147}
148
149void UdpLink::setLossRate(float rate) {
150 lossRate_ = std::max(0.f, std::min(1.f, rate));
151}
152
153void UdpLink::sendDatagram(std::vector<char> pkt) {
154 if (!sock_ || !remoteSet_) return;
155 lastSendMs_ = nowMs();
156 if (lossRate_ > 0.f &&
157 (rng_() % 10000) < static_cast<uint32_t>(lossRate_ * 10000.f)) {
158 return; // simulated loss
159 }
160 eve::data::ByteData d(pkt.data(), pkt.size());
161 sock_->sendTo(&d, remoteHost_, remotePort_);
162}
163
164void UdpLink::send(MsgType type, uint8_t channel, const void* data, size_t n) {
165 if (!remoteSet_ || !sock_) return;
166 if (data == nullptr && n > 0) return;
167 if (n > kMaxMessage) return;
168 const char* p = static_cast<const char*>(data);
169
170 uint32_t seq = 0;
171 bool track = false;
173 seq = nextSeq_++;
174 track = (type == MsgType::Reliable);
175 }
176
177 const uint8_t wireType = type == MsgType::Reliable
178 ? T_RELIABLE
179 : (type == MsgType::UnreliableOrdered ? T_ORDERED
180 : T_UNRELIABLE);
181
182 const auto build = [&](uint8_t flags, const uint8_t* frag, size_t fragLen) {
183 std::vector<char> pkt;
184 putU8(pkt, kMagic0);
185 putU8(pkt, kMagic1);
186 putU8(pkt, kVersion);
187 putU8(pkt, wireType);
188 putU8(pkt, channel);
189 putU8(pkt, flags);
190 putU32(pkt, seq);
191 putU32(pkt, ackSend_);
192 putU32(pkt, ackBitsSend_);
193 pkt.insert(pkt.end(), reinterpret_cast<const char*>(frag),
194 reinterpret_cast<const char*>(frag) + fragLen);
195 return pkt;
196 };
197
198 if (n > kPayloadMTU) {
199 const uint32_t msgId = nextFragId_++;
200 const uint16_t fragCount =
201 static_cast<uint16_t>((n + kPayloadMTU - 1) / kPayloadMTU);
202 for (uint16_t i = 0; i < fragCount; ++i) {
203 const size_t off = static_cast<size_t>(i) * kPayloadMTU;
204 const size_t len = std::min(kPayloadMTU, n - off);
205 std::vector<char> frag;
206 putU32(frag, msgId);
207 putU16(frag, fragCount);
208 putU16(frag, i);
209 frag.insert(frag.end(), p + off, p + off + len);
210 auto pkt = build(kFragFlag,
211 reinterpret_cast<const uint8_t*>(frag.data()), frag.size());
212 if (track) {
213 SendEntry& e = sendQueue_[seq];
214 if (e.pkts.empty()) {
215 e.deadlineMs = nowMs() + retryBaseMs_;
216 e.attempts = 0;
217 }
218 e.pkts.push_back(pkt);
219 }
220 sendDatagram(std::move(pkt));
221 }
222 return;
223 }
224
225 auto pkt = build(0, reinterpret_cast<const uint8_t*>(p), n);
226 if (track) {
227 SendEntry& e = sendQueue_[seq];
228 e.pkts.clear();
229 e.pkts.push_back(pkt);
230 e.deadlineMs = nowMs() + retryBaseMs_;
231 e.attempts = 0;
232 }
233 sendDatagram(std::move(pkt));
234}
235
236bool UdpLink::sendString(MsgType type, uint8_t channel, const std::string& s) {
237 if (s.empty()) return false;
238 send(type, channel, s.data(), s.size());
239 return true;
240}
241
242void UdpLink::sendAckNow() {
243 std::vector<char> pkt;
244 putU8(pkt, kMagic0);
245 putU8(pkt, kMagic1);
246 putU8(pkt, kVersion);
247 putU8(pkt, T_ACK);
248 putU8(pkt, 0);
249 putU8(pkt, 0);
250 putU32(pkt, 0);
251 putU32(pkt, ackSend_);
252 putU32(pkt, ackBitsSend_);
253 sendDatagram(std::move(pkt));
254}
255
256void UdpLink::noteReceived() {
257 lastRecvMs_ = nowMs();
258 if (!alive_ && remoteSet_) {
259 alive_ = true;
260 disconnectNotified_ = false;
261 }
262}
263
264void UdpLink::pruneAcked(uint32_t ack, uint32_t bits) {
265 if (sendQueue_.empty()) return;
266 auto it = sendQueue_.begin();
267 while (it != sendQueue_.end() && !after(ack, it->first)) {
268 it = sendQueue_.erase(it);
269 }
270 for (uint32_t i = 0; i < 32; ++i) {
271 if (bits & (1u << i)) sendQueue_.erase(ack + 1 + i);
272 }
273}
274
275void UdpLink::deliver(MsgType type, uint8_t channel, std::vector<char> payload) {
276 if (onMessage_) {
277 onMessage_(type, channel, payload.data(), payload.size());
278 }
279}
280
281void UdpLink::handleData(uint8_t type, uint8_t channel, uint32_t seq,
282 const std::vector<char>& payload) {
283 if (type == T_UNRELIABLE) {
284 deliver(MsgType::Unreliable, channel, payload);
285 return;
286 }
287 if (type == T_ORDERED) {
288 if (seq == expectedUnrelOrd_) {
289 deliver(MsgType::UnreliableOrdered, channel, payload);
290 ++expectedUnrelOrd_;
291 while (true) {
292 auto it = unrelOrdBuf_.find(expectedUnrelOrd_);
293 if (it == unrelOrdBuf_.end()) break;
294 deliver(MsgType::UnreliableOrdered, channel, std::move(it->second));
295 unrelOrdBuf_.erase(it);
296 ++expectedUnrelOrd_;
297 }
298 } else if (seq > expectedUnrelOrd_ && unrelOrdBuf_.size() < kMaxOutOfOrder) {
299 unrelOrdBuf_[seq] = payload;
300 }
301 return;
302 }
303
304 // reliable
305 if (seq == expectedReliable_) {
306 deliver(MsgType::Reliable, channel, payload);
307 ++expectedReliable_;
308 while (true) {
309 auto it = outOfOrder_.find(expectedReliable_);
310 if (it == outOfOrder_.end()) break;
311 deliver(MsgType::Reliable, channel, std::move(it->second));
312 outOfOrder_.erase(it);
313 ++expectedReliable_;
314 }
315 } else if (seq > expectedReliable_ && outOfOrder_.size() < kMaxOutOfOrder) {
316 outOfOrder_[seq] = payload;
317 }
318
319 ackSend_ = expectedReliable_ - 1;
320 ackBitsSend_ = 0;
321 uint32_t scanned = 0;
322 for (const auto& kv : outOfOrder_) {
323 if (scanned >= 32) break;
324 if (after(ackSend_, kv.first)) {
325 const uint32_t idx = kv.first - ackSend_ - 1;
326 if (idx < 32) ackBitsSend_ |= (1u << idx);
327 }
328 ++scanned;
329 }
330 sendAckNow();
331}
332
333void UdpLink::onDatagram(const std::vector<char>& bytes, const std::string& from) {
334 (void)from;
335 if (bytes.size() < kHeaderLen) return;
336 const char* p = bytes.data();
337 if (static_cast<uint8_t>(p[0]) != kMagic0 || static_cast<uint8_t>(p[1]) != kMagic1 ||
338 static_cast<uint8_t>(p[2]) != kVersion) {
339 return;
340 }
341 const uint8_t type = static_cast<uint8_t>(p[3]);
342 const uint8_t channel = static_cast<uint8_t>(p[4]);
343 const uint8_t flags = static_cast<uint8_t>(p[5]);
344
345 PktView v{p, bytes.size(), 6, true};
346 uint32_t seq = 0, ack = 0, ackBits = 0;
347 if (!v.u32(seq) || !v.u32(ack) || !v.u32(ackBits)) return;
348 noteReceived();
349 pruneAcked(ack, ackBits);
350
351 if (type == T_ACK || type == T_PONG) return;
352 if (type == T_PING) {
353 std::vector<char> pong;
354 putU8(pong, kMagic0);
355 putU8(pong, kMagic1);
356 putU8(pong, kVersion);
357 putU8(pong, T_PONG);
358 putU8(pong, 0);
359 putU8(pong, 0);
360 putU32(pong, 0);
361 putU32(pong, ackSend_);
362 putU32(pong, ackBitsSend_);
363 sendDatagram(std::move(pong));
364 return;
365 }
366
367 size_t restLen = 0;
368 const char* rest = v.rest(restLen);
369 std::vector<char> payload;
370 if (flags & kFragFlag) {
371 PktView fv{rest, restLen, 0, true};
372 uint32_t msgId = 0;
373 uint16_t fragCount = 0, fragIndex = 0;
374 if (!fv.u32(msgId) || !fv.u16(fragCount) || !fv.u16(fragIndex)) return;
375 size_t fragLen = 0;
376 const char* frag = fv.rest(fragLen);
377 if (fragCount == 1) {
378 payload.assign(frag, frag + fragLen);
379 } else {
380 if (fragCount > kMaxFragCount || fragIndex >= fragCount) return;
381 auto it = fragments_.find(msgId);
382 if (it == fragments_.end()) {
383 if (fragments_.size() >= kMaxFragments) return;
384 FragBuf fb;
385 fb.total = fragCount;
386 fb.data.resize(static_cast<size_t>(fragCount) * kPayloadMTU);
387 fb.seen.resize(fragCount, 0);
388 fb.lastMs = nowMs();
389 fragments_[msgId] = std::move(fb);
390 it = fragments_.find(msgId);
391 }
392 FragBuf& fb = it->second;
393 if (fb.total != fragCount) return;
394 if (fb.seen[fragIndex] != 0) return; // duplicate fragment
395 fb.seen[fragIndex] = 1;
396 std::memcpy(fb.data.data() + static_cast<size_t>(fragIndex) * kPayloadMTU,
397 frag, fragLen);
398 if (fragIndex == fragCount - 1) fb.lastLen = fragLen;
399 fb.received++;
400 fb.lastMs = nowMs();
401 if (fb.received == fb.total) {
402 fb.data.resize((static_cast<size_t>(fb.total) - 1) * kPayloadMTU +
403 fb.lastLen);
404 payload = std::move(fb.data);
405 fragments_.erase(it);
406 } else {
407 return; // still assembling
408 }
409 }
410 } else {
411 payload.assign(rest, rest + restLen);
412 }
413
414 handleData(type, channel, seq, payload);
415}
416
417void UdpLink::pump(int64_t now) {
418 for (auto it = sendQueue_.begin(); it != sendQueue_.end();) {
419 SendEntry& e = it->second;
420 if (e.deadlineMs <= now) {
421 if (e.attempts >= maxAttempts_) {
422 it = sendQueue_.erase(it);
423 if (!disconnectNotified_) {
424 disconnectNotified_ = true;
425 alive_ = false;
426 if (onDisconnect_) onDisconnect_("timeout");
427 }
428 continue;
429 }
430 for (const auto& pkt : e.pkts) sendDatagram(pkt);
431 e.attempts++;
432 e.deadlineMs = now + retryBaseMs_ * (1 << std::min(e.attempts, 6));
433 }
434 ++it;
435 }
436
437 for (auto it = fragments_.begin(); it != fragments_.end();) {
438 if (now - it->second.lastMs > kFragExpireMs) {
439 it = fragments_.erase(it);
440 } else {
441 ++it;
442 }
443 }
444
445 if (remoteSet_ && now - lastSendMs_ >= kPingIntervalMs) {
446 std::vector<char> ping;
447 putU8(ping, kMagic0);
448 putU8(ping, kMagic1);
449 putU8(ping, kVersion);
450 putU8(ping, T_PING);
451 putU8(ping, 0);
452 putU8(ping, 0);
453 putU32(ping, 0);
454 putU32(ping, ackSend_);
455 putU32(ping, ackBitsSend_);
456 sendDatagram(std::move(ping));
457 }
458
459 if (lastRecvMs_ > 0 && now - lastRecvMs_ > timeoutMs_ && !disconnectNotified_) {
460 disconnectNotified_ = true;
461 alive_ = false;
462 if (onDisconnect_) onDisconnect_("timeout");
463 }
464}
465
466} // namespace eve::network
std::string type
vk::ShaderModule frag
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
uint32_t a
uint32_t b
int idx
glm::vec4 p[6]
Light2D::Data * data
int d
int v
uint32_t s
Definition Weather.cpp:28
In-memory byte buffer implementing eve::Data (ref-counted).
Definition ByteData.h:11
Network module: TCP/UDP/HTTP factories, background worker, and completion event plumbing....
Definition Network.h:30
UDP socket backed by Poco::Net; supports connect/bind and datagram send.
Definition UdpSocket.h:24
bool sendTo(eve::data::ByteData *data, std::string host, uint16_t port)
Sends a datagram to an explicit host:port.
Definition UdpSocket.cpp:70