C++使用TCP SOCKET发送超大文件(超过2G)

您所在的位置:网站首页 udp传输大文件的原因是什么意思 C++使用TCP SOCKET发送超大文件(超过2G)

C++使用TCP SOCKET发送超大文件(超过2G)

2024-07-07 17:15:44| 来源: 网络整理| 查看: 265

C++使用TCP SOCKET发送超大文件(超过2G)

前几天有一个网友提出问题,如何使用socket传输超大文件。 之前虽然知道理论上该怎么处理,但并未在实际工作中使用过,毕竟现成的工具实在是太多了,没有自己开发的必要。但是想着既然给他回复了一些文字,何不写个demo让他看,不是更加直观吗?说干就干。

首先是服务端的开发。 首先要让客户端知道我们要发送的文件是多大,这就要在服务建立连接的时候,先将文件大小通过socket发送给客户端。其次需要让客户端知道文件名是什么,这样客户端在保存的时候可以动态保存,而不是写死一个文件名。最后就是文件内容的发送了,当然选择读取文件二进制,客户端使用二进制方式再保存最为稳妥。

服务端代码如下,windows下开发,包含了WinSock2.h头文件。

#include #include #include #pragma comment(lib,"WS2_32.lib") #pragma warning(disable:4996) using namespace std; //缓存大小设置不能超过2M #define BUFF_SIZE (1024 * 1024) #define FILE_NAME_LENGTH 1024 int s; /* socket for accepting connections */ int ns; /* socket connected to client */ int exitFunc() { closesocket(s); closesocket(ns); } off64_t getFileSize(char *filePath) { FILE *f; f = fopen(filePath, "rb"); if (NULL == f) { printf("getFileSize fopen error\n"); return -1; } if (0 != fseeko64(f, 0, SEEK_END)) { printf("getFileSize fseek error\n"); return -1; } off64_t fileSize = ftello64(f); if (fileSize bool bFound = false; char *buff = new char[1024]; memset(buff, 0, 1024); while (!bFound) { int lastIndex = 0; for (int i = 0; i lastIndex = i; } } for (int i = lastIndex + 1; i _onexit(exitFunc); unsigned short port; /* port server binds to */ char buff[BUFF_SIZE]; /* buffer for sending & receiving data */ struct sockaddr_in client; /* client address information */ struct sockaddr_in server; /* server address information */ int namelen; /* length of client name */ char *filePath = new char[FILE_NAME_LENGTH]; //检查是否传入端口参数 if (argc filePath = argv[2]; printf("filePath from arg:%s\n", filePath); } else { //char *filePath = "D:\\Download\\qt-opensource-windows-x86-5.12.5.exe"; //char *filePath = "D:\\Download\\ideaIC-2019.3.3.exe"; filePath = "D:\\Download\\settings.xml"; } off64_t fileSize = getFileSize(filePath); printf("fileSize:%lld\n", fileSize); char *fileName = getFileName(filePath); printf("fileName:%s\n", fileName); WSADATA wsadata; WSAStartup(0x202, &wsadata); //创建socket服务 if ((s = socket(AF_INET, SOCK_STREAM, 0)) printf("bind error\n"); exit(3); } //监听服务,只允许一个客户端连接 if (listen(s, 1) != 0) { printf("listen error\n"); exit(4); } //等待连接 namelen = sizeof(client); while (true) { //循环 一直等待客户端的连接 if ((ns = accept(s, (struct sockaddr *)&client, &namelen)) == -1) { printf("accept error\n"); exit(5); } //有客户端连接过来之后 将指定文件发送给客户端 FILE *f; f = fopen(filePath, "rb"); if (f == NULL) { printf("file:%s doesn't exist\n", filePath); exit(6); } off64_t sendSize = 0; //先将文件大小的数据发送给客户端 lltoa(fileSize, buff, 10); if (send(ns, buff, sizeof(buff), 0) printf("send fileName to client error\n"); exit(7); } while (sendSize printf("fread error\n"); fclose(f); break; } int iSend = send(ns, buff, iread, 0); if (iSend closesocket(s); return 0; } /* * Client Main. */ int main(int argc, char** argv) { _onexit(exitFunc); WSADATA wsadata; WSAStartup(0x202, &wsadata); printf("start...\n"); unsigned short port; //服务端口 char buf[BUFF_SIZE]; //缓存 struct hostent *hostnm; //服务地址信息 struct sockaddr_in server; //服务sockaddr信息 //传入两个参数,顺序是服务器地址和端口 if (argc != 3) { fprintf(stderr, "Usage: %s hostname port\n", argv[0]); exit(1); } //第一个参数是服务器地址 hostnm = gethostbyname(argv[1]); if (hostnm == (struct hostent *) 0) { fprintf(stderr, "Gethostbyname failed\n"); exit(2); } //第二个参数是端口号 port = (unsigned short) atoi(argv[2]); //put the server information into the server structure. //The port must be put into network byte order. server.sin_family = AF_INET; server.sin_port = htons(port); server.sin_addr.s_addr = *((unsigned long *)hostnm->h_addr); //创建socket if ((s = socket(AF_INET, SOCK_STREAM, 0)) printf("Connect error\n"); exit(4); } //先接收文件大小 int iRecv = 0; memset(buf, 0, BUFF_SIZE); iRecv = recv(s, buf, BUFF_SIZE, 0); if (iRecv printf("recv fileName error\n"); exit(5); } char fileName[FILE_NAME_LENGTH]; memset(fileName, 0, FILE_NAME_LENGTH); memcpy(fileName, buf, strlen(buf)); printf("recv fileName:%s\n", fileName); //接收文件 将文件保存到指定位置 char *filePath = new char[FILE_NAME_LENGTH]; memset(filePath, 0, FILE_NAME_LENGTH); char *basePath = "D:\\client\\"; memcpy(filePath, basePath, strlen(basePath)); strcat(filePath, fileName); printf("filePath:%s\n", filePath); FILE *f = NULL; f = fopen(filePath, "wb"); if (f == NULL) { printf("file:%s doesn't exist and failed to create\n", filePath); exit(5); } off64_t fileRecv = 0; time_t start; start = time(NULL); while (fileRecv printf("Recv error\n"); exit(6); } if (iRecv == 0) { break; } fileRecv += iRecv; time_t end = time(NULL); time_t cost = end - start; //动态计算出传输完需要用时多久 time_t totalTime = 0; //计算出剩余时间 time_t leftTime = 0; if (cost != 0) { totalTime = totalFileSize / (fileRecv / cost); leftTime = (totalFileSize - fileRecv) / (fileRecv / cost); } printf("totalFileSize:%lld recv file size:%lld, totalTime:%d 's, leftTime:%d 's\n", totalFileSize, fileRecv, totalTime, leftTime); fwrite(buf, sizeof(char), iRecv, f); } fclose(f); printf("Client Ended Successfully\n"); exit(0); }

运行服务端时通过参数传入端口号,也可在代码中写死端口号。

运行客户端时通过参数传入服务地址、服务端口号,也可在代码中写死。

在这个过程中遇到一个有趣事情就是,比较小的文件传输没问题,但是大小超过2G的文件刚开始使用fseek和ftell获取文件大小时获取到的文件大小为-1,后来查询文档才知道要使用其他接口,fseeko64和ftello64。

由此来看,很多时候虽然理论上知道怎么做,但实际做起来,并没有想象中的那么顺利。这在现实生活中又何尝不是呢。 ———————————————— 版权声明:本文为CSDN博主「codears」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/codears/article/details/111475389



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭