skywind3000 / kcp

:zap: KCP - A Fast and Reliable ARQ Protocol
MIT License
15.2k stars 2.49k forks source link

ikcp_recv总是返回-2,ikcp_peeksize函数里的kcp->nrcv_que与seg->frg这两个变量是什么意思 #414

Closed HeYang6 closed 2 months ago

HeYang6 commented 2 months ago

我做的是一个简单的文件上传下载功能,几KB的文件没有问题,超过1M的文件就出现问题了 因为if (kcp->nrcv_que < seg->frg + 1) return -1;这行代码导致调用的ikcp_recv总是返回-2,帮忙看下是怎么回事,顺便告诉我下kcp->nrcv_que与seg->frg变量的含义,谢谢

image image image image

发送端代码

include

include

include "..\test.h"

include

include

include

include

include

include

pragma comment(lib, "ws2_32.lib")

sockaddr_in addr; int udp_send(const char buf, int len, ikcpcb kcp, void user) { SOCKET sockfd = (SOCKET )user; sendto(sockfd, buf, len, 0, (struct sockaddr )&addr, sizeof(addr)); return 0; } std::streampos getFileSize(const std::string &filePath) { std::ifstream file(filePath, std::ios::binary | std::ios::ate); // 以二进制模式打开并定位到文件末尾 if (!file.is_open()) { std::cerr << "Could not open the file!" << std::endl; return -1; } std::streampos fileSize = file.tellg(); // 获取文件大小 file.close(); return fileSize; } void replaceUsingRegex(std::string &str, const std::string &pattern, const std::string &replacement) { std::regex re(pattern); str = std::regex_replace(str, re, replacement); } int main() { WSADATA ws; WSAStartup(MAKEWORD(2, 2), &ws); std::string hostUrl; std::cout << "请输入服务器IP" << std::endl; std::cin >> hostUrl; addr.sin_family = AF_INET; addr.sin_port = htons(666); // 服务器端口 addr.sin_addr.s_addr = inet_addr(hostUrl.data()); // 服务器地址 int sockfd = socket(AF_INET, SOCK_DGRAM, 0); ikcpcb kcp = ikcp_create(123, (void)&sockfd); kcp->output = udp_send; ikcp_nodelay(kcp, 2, 10, 2, 1); std::string path; char data[10240]; int len = sizeof(addr); while (1) { std::cout << "请输入要上传的文件地址" << std::endl; std::cin >> path; std::cout << "正在上传中......" << std::endl; replaceUsingRegex(path,"[/]","\"); //上传文件名称与文件大小 std::string name = "[begin]"+path.substr(path.find_last_of('\')+1)+"&"+std::to_string(getFileSize(path)) +"[end]"; ikcp_send(kcp, name.data(),name.length()+1); ikcp_update(kcp, iclock()); //上传文件内容 std::ifstream inputFile(path, std::ios::binary); while (!inputFile.eof()) { // 检查是否到达文件末尾 inputFile.read(data, 10240); // 读取指定长度的字节到缓冲区 int size = inputFile.gcount(); if (size > 0) { ikcp_send(kcp, data, size); } ikcp_update(kcp, iclock()); } auto interval=iclock(); while (iclock()- interval<22222) { isleep(1); ikcp_update(kcp, iclock()); } std::cout << "上传完毕" << std::endl; } return 0; }

接收端代码

include

include

include "..\test.h"

include

include

include

include

include

pragma comment(lib, "ws2_32.lib")

int sockfd; // UDP 发送函数 int udp_send(const char buf, int len, ikcpcb kcp, void user) { sockaddr_in addr = (sockaddr_in)user; sendto(sockfd, buf, len, 0, (struct sockaddr )addr, sizeof(addr)); return 0; } int main() { WSADATA ws; WSAStartup(MAKEWORD(2, 2), &ws); sockaddr_in server_addr, client_addr; // 创建 socket sockfd = socket(AF_INET, SOCK_DGRAM, 0); // 配置服务器地址 server_addr.sin_family = AF_INET; server_addr.sin_port = htons(666); server_addr.sin_addr.s_addr = inet_addr("127.0.0.1"); int timeout = 44444; int noTimeout = 0; // 绑定 socket bind(sockfd, (const struct sockaddr )&server_addr, sizeof(server_addr)); ikcpcb kcp = ikcp_create(123, (void)&client_addr); kcp->output = udp_send; ikcp_nodelay(kcp, 2, 10, 2, 1); int clientLen = sizeof(client_addr); char buffer[10240]; char data[10240]; std::string fileName; unsigned int fileSize; std::ofstream outputFile; std::string fileStr; char fileStrOldLen=-1; bool flag=true;//是否处于接收文件基本信息阶段 while (1) { label1: int length = recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr )&client_addr, &clientLen); if (length < 0) { std::cout << "网络连接断开" << std::endl; fileStrOldLen = -1; outputFile.close(); flag = true; fileStr.clear(); continue; } ikcp_input(kcp, buffer, length); ikcp_update(kcp, iclock()); int ret = ikcp_recv(kcp, data, sizeof(data)); if (ret > 0) { if (flag) { setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char)&timeout, sizeof(timeout)); fileStr += data; auto beginIndex = fileStr.find("[begin]"); auto endIndex = fileStr.find("[end]"); if (beginIndex == -1 && endIndex == -1)//一次读不完的情况 { fileStrOldLen = fileStr.length(); goto label1; } if (fileStrOldLen == -1)//一次读完的情况 { if(endIndex+5== fileStr.length()) fileStrOldLen = fileStr.length();//一次读完并且没有读取到文件内容字节数据的情况 else fileStrOldLen = endIndex + 5;//一次读完并且有读取到文件内容字节数据的情况 } auto splitIndex = fileStr.find_first_of('&'); fileName = fileStr.substr(7, splitIndex - 7); fileSize = std::stoul(fileStr.substr(splitIndex + 1, endIndex - 1 - splitIndex)); char subtractLen = endIndex + 5 - fileStrOldLen; if (subtractLen > 0)//还存在文件内容字节数据需要写入的情况 { char allLen = ret - subtractLen; beginIndex = ret - allLen; outputFile.open(fileName, std::ios::binary); outputFile.write(&data[beginIndex], allLen); fileSize -= allLen; } fileStrOldLen = -1; fileStr.clear(); flag = false; std::cout << fileName + "正在上传......" << std::endl; } else { if (!outputFile.is_open()) outputFile.open(fileName, std::ios::binary); outputFile.write(data, ret); if ((fileSize -= ret) > 0)//接收文件内容 { goto label1; } else//接收完毕 { outputFile.close(); std::cout << fileName + "上传完毕" << std::endl; flag = true; setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&noTimeout, sizeof(noTimeout)); } } } } return 0; }

skywind3000 commented 2 months ago

麻烦重新好好帖下代码

HeYang6 commented 2 months ago

麻烦重新好好帖下代码

image

image image image

HeYang6 commented 2 months ago

我已经找到原因了