写一份c++可靠的udp的源代码
时间: 2023-07-31 21:12:28 浏览: 74
以下是一个基于C++的可靠UDP源代码,它包含了数据包的序列化、反序列化、发送、接收和确认等功能:
```c++
#include <iostream>
#include <cstring>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <chrono>
#include <thread>
struct Packet {
uint32_t seq; // 序列号
char data[1024]; // 数据
};
class ReliableUDP {
public:
ReliableUDP() {
// 创建套接字
m_sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (m_sockfd < 0) {
std::cerr << "Error: Failed to create socket." << std::endl;
exit(-1);
}
// 设置目标服务器地址
memset(&m_server_addr, 0, sizeof(m_server_addr));
m_server_addr.sin_family = AF_INET;
m_server_addr.sin_port = htons(6666);
inet_pton(AF_INET, "127.0.0.1", &m_server_addr.sin_addr);
}
~ReliableUDP() {
// 关闭套接字
close(m_sockfd);
}
// 发送数据包
void send(const char* data, size_t len) {
uint32_t seq = m_seq++; // 获取序列号
Packet packet = { seq };
memcpy(packet.data, data, len);
// 序列化数据包
uint8_t buffer[sizeof(Packet)];
memcpy(buffer, &packet, sizeof(Packet));
// 发送数据包
ssize_t n = sendto(m_sockfd, buffer, sizeof(Packet), 0, (const sockaddr*)&m_server_addr, sizeof(m_server_addr));
if (n != sizeof(Packet)) {
std::cerr << "Error: Failed to send packet." << std::endl;
exit(-1);
}
// 等待ACK,直到超时
std::chrono::time_point<std::chrono::steady_clock> start_time = std::chrono::steady_clock::now();
while (true) {
// 接收ACK
Packet ack_packet;
ssize_t n = recvfrom(m_sockfd, &ack_packet, sizeof(Packet), 0, NULL, NULL);
if (n == sizeof(Packet) && ack_packet.seq == seq) {
break; // 收到正确的ACK,退出循环
}
// 检查是否超时
std::chrono::time_point<std::chrono::steady_clock> now_time = std::chrono::steady_clock::now();
std::chrono::duration<double> elapsed_seconds = now_time - start_time;
if (elapsed_seconds.count() > m_timeout) {
std::cerr << "Error: Timeout." << std::endl;
exit(-1);
}
// 等待一段时间再次接收ACK
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
// 接收数据包
void recv(char* data, size_t& len) {
while (true) {
// 接收数据包
Packet packet;
ssize_t n = recvfrom(m_sockfd, &packet, sizeof(Packet), 0, NULL, NULL);
if (n <= 0) {
continue; // 接收失败,继续等待
}
// 发送ACK
Packet ack_packet = { packet.seq };
sendto(m_sockfd, &ack_packet, sizeof(Packet), 0, (const sockaddr*)&m_server_addr, sizeof(m_server_addr));
// 反序列化数据包
memcpy(data, packet.data, sizeof(packet.data));
len = n - sizeof(uint32_t);
break;
}
}
private:
int m_sockfd; // 套接字文件描述符
sockaddr_in m_server_addr; // 目标服务器地址
uint32_t m_seq = 0; // 当前序列号
double m_timeout = 1.0; // 超时时间
};
```
使用方法:
```c++
int main() {
ReliableUDP udp;
// 发送数据包
char data[] = "Hello, world!";
udp.send(data, strlen(data));
// 接收数据包
char recv_data[1024];
size_t len = 0;
udp.recv(recv_data, len);
recv_data[len] = '\0';
std::cout << "Received: " << recv_data << std::endl;
return 0;
}
```
注意:此代码仅用于学习和参考,实际生产环境中需要考虑更多的异常处理、安全性等问题。
阅读全文