udp实现可靠稳定传输的C++代码
时间: 2023-12-12 16:03:44 浏览: 114
用UDP实现的可靠传输源码
5星 · 资源好评率100%
UDP是一种无连接的协议,不保证数据的可靠传输。但是我们可以通过编写一些机制来实现UDP的可靠传输。下面是一个简单的UDP可靠传输的C++代码实现:
```
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <ctime>
using namespace std;
const int MAXSIZE = 1024;
const int TIMEOUT = 3;
struct Packet {
int seq; //序列号
int ack; //确认号
int len; //数据长度
char data[MAXSIZE]; //数据
};
class UDPReliableSocket {
private:
int sockfd; //套接字
struct sockaddr_in serverAddr; //服务器地址
struct sockaddr_in clientAddr; //客户端地址
int serverPort; //服务器端口
int clientPort; //客户端端口
int seq; //序列号
int ack; //确认号
char buf[MAXSIZE]; //缓冲区
public:
UDPReliableSocket(int clientPort, int serverPort, const char* serverIP) {
this->clientPort = clientPort;
this->serverPort = serverPort;
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
perror("socket error");
exit(-1);
}
bzero(&clientAddr, sizeof(clientAddr));
clientAddr.sin_family = AF_INET;
clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddr.sin_port = htons(clientPort);
if (bind(sockfd, (struct sockaddr*)&clientAddr, sizeof(clientAddr)) < 0) {
perror("bind error");
exit(-1);
}
bzero(&serverAddr, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(serverPort);
if (inet_aton(serverIP, &serverAddr.sin_addr) == 0) {
perror("inet_aton error");
exit(-1);
}
seq = 0;
ack = 0;
srand(time(NULL));
}
~UDPReliableSocket() {
close(sockfd);
}
void sendPacket(Packet& packet) {
packet.seq = seq; //设置序列号
packet.ack = ack; //设置确认号
int len = sizeof(serverAddr);
int n = sendto(sockfd, &packet, sizeof(packet), 0, (struct sockaddr*)&serverAddr, len);
if (n < 0) {
perror("sendto error");
exit(-1);
}
cout << "send packet " << seq << endl;
seq++;
}
void recvPacket(Packet& packet) {
int n, fromlen = sizeof(serverAddr);
while (true) {
fd_set readfds;
FD_ZERO(&readfds);
FD_SET(sockfd, &readfds);
struct timeval timeout;
timeout.tv_sec = TIMEOUT;
timeout.tv_usec = 0;
int ret = select(sockfd + 1, &readfds, NULL, NULL, &timeout);
if (ret < 0) {
perror("select error");
exit(-1);
}
else if (ret == 0) {
cout << "timeout!" << endl;
sendPacket(packet);
}
else {
n = recvfrom(sockfd, &packet, sizeof(packet), 0, (struct sockaddr*)&serverAddr, (socklen_t*)&fromlen);
if (n < 0) {
perror("recvfrom error");
exit(-1);
}
if (rand() % 10 < 7) {
if (packet.ack == ack) {
ack++;
cout << "recv ack " << ack << endl;
break;
}
else {
cout << "recv ack " << packet.ack << " not equal to " << ack << endl;
}
}
else {
cout << "packet loss!" << endl;
}
}
}
}
};
int main() {
UDPReliableSocket socket(8888, 9999, "127.0.0.1");
Packet packet;
while (true) {
cout << "input message: ";
fgets(packet.data, MAXSIZE, stdin);
packet.len = strlen(packet.data) - 1;
if (packet.len == 0) {
break;
}
socket.sendPacket(packet);
socket.recvPacket(packet);
}
return 0;
}
```
代码中采用了GBN(Go-Back-N)协议,当客户端发送一个数据包时,服务端会返回一个确认包,如果客户端在规定的时间内未收到确认包,则认为数据包丢失,会重新发送数据包。如果服务端收到了正确的数据包,则会返回正确的确认包。在代码中,为了模拟网络环境不好的情况,我们引入了一定的随机性,有一定几率会出现数据包丢失的情况。
阅读全文