使用:
(1)首先运行服务端,待服务端运行起来;
(2)最后运行客户端,这里使用目标机器IP地址是本机;
(3)输入下载文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含(代表需要传输文件的类型)。
例如:E:/Data(D)/Cat_and_Dog/dog.jpg
参考博主:https://blog.csdn.net/sinat_23118323/article/details/71024351

客户端:

#include <WinSock2.h> //windows socket的头文件
#include <Windows.h>
#include <iostream>
#include <thread>
#include <process.h>
#include<mutex>
#include<string>
#include<process.h>
#define MAXBYTES 300*1024
#define err(errMsg) printf("[error] %s failed,code %d\
line:%d\n",errMsg, WSAGetLastError(),__LINE__)
#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件using namespace std;
mutex m;
//获取当前日期
void OBTION_TIME() {SYSTEMTIME start; //windows.h中  GetLocalTime(&start);//time.h的tm结构体一样的效果  cout << start.wYear << "/" << start.wMonth << "/" << start.wDay << " " << start.wHour << ":" << start.wMinute << ":" << start.wSecond << endl;
}
//获取开始时间
double START_TIME() {DWORD start_time;start_time = GetTickCount64();return (double)start_time;
}
//获取结束时间
double END_TIME() {DWORD end_time;end_time = GetTickCount64();return double(end_time);
}
//获取文件大小
void getByteSize(long size) {long rest = 0;if (size < 1024) {cout << size << "B" << endl;return;}else {size /= 1024;}if (size < 1024) {cout << size << "KB" << endl;return;}else {rest = size % 1024;size /= 1024;}if (size < 1024) {size *= 100;cout << (size / 100) << "." << (rest * 100 / 1024 % 100) << "MB" << endl;return;}else {size = size * 100 / 1024;cout << (size / 100) << "." << (size % 100) << "GB" << endl;return;}
}
//定义结构体用来设置
typedef struct my_file
{SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;
//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)
DWORD WINAPI transmmit(const LPVOID arg)
{//上锁是为了方便看输出m.lock();F* temp = (F*)arg;/*获取文件的序号int file_id = temp->id;获取客户机的端口号ntohs(temp -> clientAddr.sin_port);*/cout << "测试开始,等待服务端发送消息..." << endl;char revdata[1024] = { 0 };char file_name[100] = { 0 };int ret = recv(temp->clientSocket, revdata, MAXBYTE, 0);char file_names[1024] = { 0 };if (ret > 0) {revdata[ret] = '\0';int i = 0;for (i = 0; i < strlen(revdata); i++) {if (revdata[i] == 'E' && revdata[i + 1] == 'S' && revdata[i + 2] == 'C') {break;}file_name[i] = revdata[i];}file_name[i] = '\0';}else {cout << "文件下载出错" << endl;}ret = recv(temp->clientSocket, file_names, MAXBYTE, 0);if (ret > 0) {file_names[ret] = '\0';for (int i = 0; i < strlen(file_names); i++) {if (file_names[i] == 'E' && file_names[i + 1] == 'S' && file_names[i + 2] == 'C') {break;}}cout << "开始下载文件" << endl;}//文件路径unsigned long long len_file = 0;FILE* fp = fopen(file_name, "rb");if (fp == NULL) {cout << "文件" << file_name << "出错或不存在" << endl;}else {cout << "发送文件时间: ";OBTION_TIME();char Buffer[MAXBYTES] = { 0 }; //文件缓冲区unsigned long long size = 0; //读取的文件长度while ((size = fread(Buffer, sizeof(char), MAXBYTES, fp)) > 0) {//返回非0值表示send错误if (send(temp->clientSocket, Buffer, size, NULL) < 0){cout << "下载出错,请检查网络配置。" << endl;}len_file += size;//每次读取完之后清空缓存区,以便下一块文件读入memset(&Buffer, 0, MAXBYTES);}const char* t = "end";send(temp->clientSocket, t, strlen(t), NULL);cout << temp->id << "线程已成功发送" << file_name << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;getByteSize(len_file);cout << "文件下载结束时间: ";OBTION_TIME();double currentTime = 0;currentTime = END_TIME() - START_TIME();cout << "文件下载耗时: " << currentTime << endl;fclose(fp);}/*发送简单的字符串到客户端const char* s = "Server file";send(temp->clientSocket, s, strlen(s)*sizeof(char)+1, NULL);cout << "线程" << temp->id << "通过客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口发送:" << s << endl;*/m.unlock();return 0;
}
int main()
{SOCKET clientSock;WSADATA wsadata;//WSA-windows socket ansyc windows的异步套接字 2.2版本的if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {err("WSAStartup");return 0;}//建立连接while (true) {//客户端socket//加载winsock库clientSock = socket(AF_INET, SOCK_STREAM, 0);if (clientSock == INVALID_SOCKET) {err("SOCKET");return 0;}//初始化socket信息sockaddr_in clientAddr;memset(&clientAddr, 0, sizeof(SOCKADDR));//clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);clientAddr.sin_family = AF_INET;clientAddr.sin_port = htons(2017);//将本地字节序转换为网络字节序,大端和小端存储clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");if (connect(clientSock, (SOCKADDR*)&clientAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {err("connect");return 0;}cout << "已建立连接。" << endl;/*char* s = new char[100];cout << "请输入你要发送的文字消息: ";cin >> s;send(clientSock, s, strlen(s)*sizeof(char) + 1, NULL);cout << "已发送:" << s << endl;*/char Buffer[MAXBYTES] = { 0 }; // 文件缓冲区char wb_files[100] = { 0 }; //写入的文件char wb_file[100] = { 0 };char wb_file_s[100] = { 0 };cout << "首先请客户端输入想要下载的文件路径: ";cin >> wb_files;int len = strlen(wb_files);wb_files[len] = 'E';wb_files[len + 1] = 'S';wb_files[len + 2] = 'C';wb_files[len + 3] = '\0';send(clientSock, wb_files, strlen(wb_files), 0);cout << endl;cout << "其次请服务端输入想要下载的文件保存路径: ";cin >> wb_file_s;len = strlen(wb_file_s);wb_file_s[len] = 'E';wb_file_s[len + 1] = 'S';wb_file_s[len + 2] = 'C';wb_file_s[len + 3] = '\0';send(clientSock, wb_file_s, strlen(wb_file_s), 0);int i = 0;for (i = 0; i < strlen(wb_file_s)-3; i++){wb_file[i] = wb_file_s[i];}wb_file[i] = '\0';cout << wb_file << endl;FILE* fp = fopen(wb_file, "wb");//如果录入文件不存在的话就创建一个新的文件if (fp == NULL) {fp = fopen(wb_file, "w");}unsigned long long len_file = 0;if (fp == NULL) {cout << "操作文件时出错" << endl;system("pause");}else {cout << "下载文件时间: ";OBTION_TIME();memset(&Buffer, 0, MAXBYTES);unsigned long long size = 0;//当成功接收文件(size > 0)时,判断写入的时候文件长度是否等于接收的长度while ((size = recv(clientSock, Buffer, MAXBYTES, 0)) > 0) {if (Buffer[size - 3] == 'e' && Buffer[size - 2] == 'n' && Buffer[size - 1] == 'd'){char buffer[MAXBYTES] = { 0 };for (int i = 0; i < strlen(Buffer) - 3; i++) {buffer[i] = Buffer[i];}len_file += size - 3;if (fwrite(buffer, sizeof(char), size, fp) < size) {cout << "下载出错,部分文件缺失。" << endl;}break;}else {if (fwrite(Buffer, sizeof(char), size, fp) < size) {cout << "下载出错,部分文件缺失。" << endl;}len_file += size;}//清空缓存区以便下一次接收memset(&Buffer, 0, MAXBYTES);}cout << "下载完成..." << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;getByteSize(len_file);cout << "文件结束下载时间: ";OBTION_TIME();double currentTime = 0;currentTime = END_TIME() - START_TIME();cout << "下载文件耗时: " << currentTime << endl;fclose(fp);}//“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;HANDLE hThread[2];for (int i = 0; i < 1; i++) {F* temp = new F;sockaddr_in clntAddr;memset(&clntAddr, 0, sizeof(SOCKADDR));temp->clientSocket = clientSock;temp->clientAddr = clntAddr;temp->id = i + 1;//使用 API 的 CreateThread, 它执行完入口函数后会自动退出, 无需 ExitThread;hThread[i] = CreateThread(NULL, 0, &transmmit, temp, 0, NULL);}//等待子线程完成WaitForMultipleObjects(1, hThread, TRUE, INFINITE);cout << "错误代码: " << WSAGetLastError() << endl;closesocket(clientSock);}/*closesocket(clientSock);WSACleanup();*/关闭网络库 if (WSACleanup() != 0) {err("WSACleanup");return 0;}cout << "客户端连接已关闭。" << endl;system("pause");return 0;
}

#include <WinSock2.h> //windows socket的头文件
#include <Windows.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <process.h>
#include <fstream>
#include <string>
#include<time.h>
#define MAXBYTES 300*1024
#define err(errMsg) printf("[error] %s failed,code %d\
line:%d\n",errMsg, WSAGetLastError(),__LINE__)#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件using namespace std;mutex m;
//获取当前日期
void OBTION_TIME() {SYSTEMTIME start; //windows.h中  GetLocalTime(&start);//time.h的tm结构体一样的效果  cout << start.wYear << "/" << start.wMonth << "/" << start.wDay << " " << start.wHour << ":" << start.wMinute << ":" << start.wSecond << endl;
}
//获取开始时间
double START_TIME() {DWORD start_time;start_time = GetTickCount64();return (double)start_time;
}
//获取结束时间
double END_TIME() {DWORD end_time;end_time = GetTickCount64();return double(end_time);
}
//获取文件大小
void getByteSize(unsigned long long size) {unsigned long long rest = 0;if (size < 1024) {cout << size << "B" << endl;return;}else {size /= 1024;}if (size < 1024) {cout << size << "KB" << endl;return;}else {rest = size % 1024;size /= 1024;}if (size < 1024) {size *= 100;cout << (size / 100) << "." << (rest * 100 / 1024 % 100) << "MB" << endl;return;}else {size = size * 100 / 1024;cout << (size / 100) << "." << (size % 100) << "GB" << endl;}
}
//定义结构体用来设置
typedef struct my_file {SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;
//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)
DWORD WINAPI transmmit(const LPVOID arg) {//上锁是为了方便看输出m.lock();F* temp = (F*)arg;/*获取文件的序号int file_id = temp->id;获取客户机的端口号ntohs(temp -> clientAddr.sin_port);*/cout << "测试开始,等待客户端发送消息..." << endl;//从客户端处接受数据/*char Buffer[MAXBYTE] = { 0 }; //缓冲区recv(temp->clientSocket, Buffer, MAXBYTE, 0); //recv方法 从客户端通过clientScocket接收cout << "线程" << temp->id << "从客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口收到:" << Buffer << endl;*/char revdata[1024] = { 0 };char file_name[100] = { 0 };//文件路径 int ret = recv(temp->clientSocket, revdata, MAXBYTE, 0);char file_names[1024] = { 0 };if (ret > 0) {revdata[ret] = '\0';int i = 0;for (i = 0; i < strlen(revdata); i++) {if (revdata[i] == 'E' && revdata[i + 1] == 'S' && revdata[i + 2] == 'C') {break;}file_name[i] = revdata[i];}file_name[i] = '\0';cout << "接收到下载文件消息" << endl;}else {cout << "文件下载出错" << endl;}ret = recv(temp->clientSocket, file_names, MAXBYTE, 0);if (ret > 0) {file_names[ret] = '\0';for (int i = 0; i < strlen(file_names); i++) {if (file_names[i] == 'E' && file_names[i + 1] == 'S' && file_names[i + 2] == 'C') {break;}}cout << "开始下载文件" << endl;}FILE* fp = fopen(file_name, "rb");unsigned long long len_file = 0;if (fp == NULL) {cout << "文件" << file_name << "出错或不存在" << endl;}else {unsigned long long g_fileSize = 0;cout << "下载文件时间: ";OBTION_TIME();struct _stat64 st;_stat64(file_name, &st);g_fileSize = st.st_size;string send_file_len;send_file_len = to_string(g_fileSize);send(temp->clientSocket, send_file_len.c_str(), send_file_len.length(), 0);char Buffer[MAXBYTES] = { 0 }; //文件缓冲区unsigned long long size = 0; //读取的文件长度while ((size = fread(Buffer, sizeof(char), MAXBYTES, fp)) > 0) {//返回非0值表示send错误if (send(temp->clientSocket, Buffer, size, NULL) < 0) {cout << "下载出错,请检查网络配置。" << endl;}len_file += size;cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSize) % 5 > 0) {cout << (len_file * 100 / g_fileSize) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}size = 0;//每次读取完之后清空缓存区,以便下一块文件读入memset(&Buffer, 0, MAXBYTES);}const char* t = "end";send(temp->clientSocket, t, strlen(t), NULL);cout << temp->id << "线程已成功发送" << file_name << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;getByteSize(len_file);cout << "文件下载结束时间: ";OBTION_TIME();double currentTime = 0;currentTime = END_TIME() - START_TIME();cout << "下载文件耗时: " << currentTime << endl;fclose(fp);}/*发送简单的字符串到客户端const char* s = "Server file";send(temp->clientSocket, s, strlen(s)*sizeof(char)+1, NULL);cout << "线程" << temp->id << "通过客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口发送:" << s << endl;*/m.unlock();return 0;
}
int main() {//加载网络库WSADATA wsaData;//第一个参数是winsocket load的版本号(2.2)if (WSAStartup(MAKEWORD(2, 3), &wsaData) != 0) {err("WSAStartup");return 0;}//创建服务器端的socket(协议族, sokcet类型)SOCKET servSocket = socket(AF_INET, SOCK_STREAM, 0);//如果改成SOCK_DGRAM则使用UDPif (servSocket == INVALID_SOCKET) {err("SOCKET");return 0;}sockaddr_in servAddr; //服务器的socket地址,包含sin_addr表示IP地址,sin_port保持端口号和sin_zero填充字节memset(&servAddr, 0, sizeof(SOCKADDR)); //初始化socket地址servAddr.sin_family = AF_INET; //设置使用的协议族servAddr.sin_port = htons(2017); //设置使用的端口servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //define s_addr = S_un.S_addr//将之前创建的servSocket和端口,IP地址绑定if (bind(servSocket, (SOCKADDR*)&servAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {err("bind");return 0;}HANDLE hThread[2]; //获取句柄listen(servSocket, 1); //监听服务器端口SOCKET clientSock;cout << "等待连接..." << endl;while (true) {//“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;HANDLE hThread[2]; //获取句柄SOCKET clientSock;//最多可以接受20个请求for (int i = 0; i < 1; i++) {F* temp = new F; //创建新的传输结构体sockaddr_in clntAddr;int nSize = sizeof(clntAddr);clientSock = accept(servSocket, (SOCKADDR*)&clntAddr, &nSize);if (clientSock == INVALID_SOCKET) {err("accept");}//temp数据成员赋值temp->clientSocket = clientSock;temp->id = i + 1;temp->clientAddr = clntAddr;//通过句柄创建子线程,使用 API 的 CreateThread, 它执行完入口函数后会自动退出, 无需 ExitThread;hThread[i] = CreateThread(NULL, 0, &transmmit, temp, 0, NULL);}//等待子线程完成WaitForMultipleObjects(1, hThread, TRUE, INFINITE);cout << "错误代码: " << WSAGetLastError() << endl;char Buffer[MAXBYTES] = { 0 }; // 文件缓冲区char wb_files[100] = { 0 }; //下载的文件char wb_file[100] = { 0 }; //写入的文件char wb_file_s[100] = { 0 };cout << "首先请服务端输入想要下载的文件路径: ";cin >> wb_files;int len = strlen(wb_files);wb_files[len] = 'E';wb_files[len+1] = 'S';wb_files[len+2] = 'C';wb_files[len+3] = '\0';send(clientSock, wb_files, strlen(wb_files), 0);cout << endl;cout << "其次请服务端输入想要保存的文件目录: ";cin >> wb_file_s;len = strlen(wb_file);wb_file[len] = 'E';wb_file[len + 1] = 'S';wb_file[len + 2] = 'C';wb_file[len + 3] = '\0';send(clientSock, wb_file_s, strlen(wb_file_s), 0);int i = 0;for (i = 0; i < strlen(wb_file_s) - 3; i++) {wb_file[i] = wb_file_s[i];}FILE* fp = fopen(wb_file, "wb");//如果录入文件不存在的话就创建一个新的文件if (fp == NULL) {fp = fopen(wb_file, "w");}unsigned long long len_file = 0;if (fp == NULL) {cout << "操作文件时出错" << endl;system("pause");}else {cout << "下载文件时间: ";OBTION_TIME();memset(&Buffer, 0, MAXBYTES);unsigned long long size = 0;//当成功接收文件(size > 0)时,判断写入的时候文件长度是否等于接收的长度while ((size = recv(clientSock, Buffer, MAXBYTES, 0)) > 0) {if (Buffer[size - 3] == 'e' && Buffer[size - 2] == 'n' && Buffer[size - 1] == 'd'){char buffer[MAXBYTES] = { 0 };for (int i = 0; i < strlen(Buffer) - 3; i++) {buffer[i] = Buffer[i];}len_file += size - 3;if (fwrite(buffer, sizeof(char), size, fp) < size) {cout << "下载出错,部分文件缺失。" << endl;}break;}else {if (fwrite(Buffer, sizeof(char), size, fp) < size) {cout << "下载出错,部分文件缺失。" << endl;}len_file += size;}//清空缓存区以便下一次接收memset(&Buffer, 0, MAXBYTES);}cout << "下载完成..." << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;getByteSize(len_file);cout << "文件下载结束时间: ";OBTION_TIME();double currentTime = 0;currentTime = END_TIME() - START_TIME();cout << "下载文件耗时: " << currentTime << endl;fclose(fp);}closesocket(clientSock);}//关闭socket,释放winsockclosesocket(servSocket);关闭网络库 if (WSACleanup()) {err("WSACleanup");return 0;}cout << "服务器连接已关闭。" << endl;system("pause");return 0;
}

使用C++基于Socket编程实现文件下载相关推荐

  1. 使用C++基于Socket编程实现文件下载(改进-封装成类)

    使用: (1)首先运行服务端,待服务端运行起来: (2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址: (3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含( ...

  2. socket recv 服务端阻塞 python_网络编程(基于socket编程)

    网络编程(基于socket编程) socket套接字:应用程序通常通过socket"套接字"向网络发送请求或应答网络请求,是主机间或同一计算机中的进程间相互通讯 socket是介于 ...

  3. .NET(C#)基于Socket编程实现平行主机之间网络通讯有图片传输的Demo演示

    本文讲下C#通过Socket编程实现平行主机之间网络通讯的详细讲解,非常不错的博文,一起来看下吧.      在程序设计中,涉及数据存储和数据交换的时候,不管是B/S还是C/S模式 ,都有这样一个概念 ...

  4. C# Winform基于socket编程的五子棋游戏(带聊天和发送文件功能)

    最近在做课设,题目是关于socket编程的一对一网络小游戏.期间遇到各种问题,也从中学到了很多.在此记录下课设中遇到的问题. 题目要求: 设计4 网络版小游戏 1 设计目的 1)熟悉开发工具(Visu ...

  5. 基于Socket编程下 实现Linux-Linux、Linux-Windows tcp通信

    文章目录 前言 一.Linux - Linux 服务器 server 客户端 client 通信实操 二.socket编程在windows和linux下的区别 三.Windows - Linux 四. ...

  6. 使用C++实现的一个五子棋系统(基于Socket编程)

    准备工作: (1)首先创建两个记事本,其目的是用来保存玩家和管理员信息的: 上面的数据都是在运行代码时添加的,使用文件保存测原因就是在模拟一个数据库,将这个文件保存的数据当成是数据库在保存数据,所有管 ...

  7. 【网络聊天室】——基于socket编程的TCP/UDP网络聊天服务器

    早期网络刚刚普及的时候,给人们印象最深的就是上网聊天,虽然作为一名上世纪的尾巴刚刚出生的我没有经历过,但仍从有所耳闻,那个时期是网络聊天室风靡的年代,全国知名聊天室大家都争破头的想要进去,基于如上和一 ...

  8. 基于Socket编程实现FTP客户端

    实验环境 Cygwin Python 2.7 FileZella Server 原理 利用ftp协议进行文件传输时,主要利用两个端口:命令端口(也叫作控制端口)和数据端口.控制端口主要用来传输命令,数 ...

  9. 基于socket编程的多人聊天室

    效果图:      server.c 1 /* 服务器端 server.c */ 2 #include <glib.h> 3 #include <stdio.h> 4 #inc ...

最新文章

  1. 面向对象分析与设计的意义是什么
  2. python爬虫:使用BeautifulSoup进行查找
  3. 解决硬盘文件目录损坏且无法读取
  4. linux分布式文件存储挂载使用_Linux - tmpfs内存文件系统使用
  5. 不能错过!简单易懂的哈希表总结
  6. 误删除了Oracle的dbf文件后的解决方法
  7. 三步教你手动破解网易云音乐加密
  8. db2exc_971_WIN_x86,db2数据库下载,不是官方下载,直接可下
  9. Python中列表的常用方法总结
  10. java程序执行时间_java记录代码运行时间
  11. heka 输出到mysql_让Heka支持lua的io操作和os操作
  12. NODE.JS DM数据库驱动简介及搭建
  13. 如何使用计算机网络打印机,电脑重新连接网络打印机的操作方法-电脑自学网...
  14. 微信支付服务商,消费者投诉处理系统
  15. 百度地图 - 添加区划覆盖物 - 循环打点
  16. 01-leveldb概述
  17. debian9.6安装和卸载新立得软件包管理器
  18. html制作类似qq聊天室,QQ聊天室主页设计
  19. 编译ffmpeg+dl等库
  20. 如何设置一台电脑双网卡双线上网

热门文章

  1. redis源码分析(beta版本)-redis实现的概述逻辑
  2. Flask之异常处理
  3. python中yield的认识与学习|生成器
  4. 3D视觉应用开发--机器人3D互动四大技术难点分析
  5. 链表问题14——在单链表种删除指定值的节点
  6. mapreduce工作流程
  7. 天际汽车牛胜福:受感知系统等影响 点对点L3将于五年后实现...
  8. java项目的逻辑结构
  9. MySQL常见的几个错误汇总
  10. angular-创建自定义的指令