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

客户端:

#pragma once
#ifndef _LOAD_SOCKET_H_
#define _LOAD_SOCKET_H_
#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;
class Socket {private:SOCKET clientSock;int id;char wb_file[MAXBYTE];char wb_files[MAXBYTE];char wb_file_s[MAXBYTE] ;string ip;public://获取当前日期void OBTION_TIME();//获取开始时间double START_TIME();//获取结束时间double END_TIME();//获取文件大小void getByteSize(long size);static DWORD WINAPI transmmit(const LPVOID arg);//输入文件void INPUT_FILE(string file1, string file2);int MAIN_SOCKET();//输入IPint INPUT_IP(string ip);//判断输入的IP地址是否可以连接int JUDEG_IP(string ip);//清除库void CLEAR();
};
//定义结构体用来设置
typedef struct my_file
{SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;
#endif // !_LOAD_SOCKET_H_

#include "load_socket.h"using namespace std;
mutex m;
//获取当前日期
void Socket::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 Socket::START_TIME() {DWORD start_time;start_time = GetTickCount64();return (double)start_time;
}
//获取结束时间
double Socket::END_TIME() {DWORD end_time;end_time = GetTickCount64();return double(end_time);
}
//获取文件大小
void Socket::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;}
}//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)
DWORD WINAPI Socket::transmmit(const LPVOID arg)
{//上锁是为了方便看输出m.lock();Socket* soc = (Socket*)arg;cout << "测试开始,等待服务端发送消息..." << endl;char revdata[1024] = { 0 };char file_name[100] = { 0 };int ret = recv(soc->clientSock, 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(soc->clientSock, 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 << "发送文件时间: ";soc->OBTION_TIME();double start_time = soc->START_TIME();char Buffer[MAXBYTES] = { 0 }; //文件缓冲区unsigned long long size = 0; //读取的文件长度while ((size = fread(Buffer, sizeof(char), MAXBYTES, fp)) > 0) {//返回非0值表示send错误if (send(soc->clientSock, Buffer, size, NULL) < 0){cout << "下载出错,请检查网络配置。" << endl;}len_file += size;//每次读取完之后清空缓存区,以便下一块文件读入memset(&Buffer, 0, MAXBYTES);}const char* t = "end";send(soc->clientSock, t, strlen(t), NULL);cout << soc->id << "线程已成功发送" << file_name << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;soc->getByteSize(len_file);cout << "文件下载结束时间: ";soc->OBTION_TIME();double end_time = soc->END_TIME();double currentTime = 0;currentTime = end_time-start_time;cout << "文件下载耗时: " << currentTime << endl;fclose(fp);}m.unlock();return 0;
}
void Socket::INPUT_FILE(string file1,string file2) {for (int i = 0; i < file1.length(); i++) {wb_files[i] = file1[i];}wb_files[file1.length()] = '\0';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);for (int i = 0; i < file2.length(); i++) {wb_file_s[i] = file2[i];}wb_file_s[file2.length()] = '\0';
}
int  Socket::INPUT_IP(string ip) {const char* ips = ip.c_str();WSADATA wsadata;//WSA-windows socket ansyc windows的异步套接字 2.2版本的if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {err("WSAStartup");return 0;}//建立连接//客户端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(ips);if (connect(clientSock, (SOCKADDR*)&clientAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {err("connect");return 0;}return 1;
}
int Socket::JUDEG_IP(string ip) {if (INPUT_IP(ip)) {return true;}else{return false;}
}
int Socket::MAIN_SOCKET(){char Buffer[MAXBYTES] = { 0 }; // 文件缓冲区int i = 0;for (i = 0; i < strlen(wb_file_s) ; i++) {wb_file[i] = wb_file_s[i];}wb_file[i] = '\0';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();double start_time = START_TIME();unsigned long long g_fileSize = 0;char rev_buffer[MAXBYTES] = { 0 };//接收文件的长度int rev_len = recv(clientSock, rev_buffer, MAXBYTE, 0);if (rev_len > 0) {rev_buffer[rev_len] = '\0';for (int i = 0; i < strlen(rev_buffer); i++) {g_fileSize = g_fileSize * 10 + ((unsigned long long)rev_buffer[i] - 48);}}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;size -= 3;if (fwrite(buffer, sizeof(char), size, fp) < size) {cout << "下载出错,部分文件缺失。" << endl;break;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSize) % 5 > 0) {cout << (len_file * 100 / g_fileSize) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}break;}else {if (fwrite(Buffer, sizeof(char), size, fp) < size) {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";//回删三个字符,使数字在原地变化}//清空缓存区以便下一次接收memset(&Buffer, 0, MAXBYTES);}cout << "下载完成..." << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;getByteSize(len_file);cout << "文件结束下载时间: ";OBTION_TIME();double end_time = END_TIME();double currentTime = 0;currentTime = (double)(end_time - start_time) / CLOCKS_PER_SEC;cout << "下载文件耗时: " << currentTime <<"s"<< endl;fclose(fp);}return 0;
}
void Socket::CLEAR() {关闭网络库 closesocket(clientSock);if (WSACleanup() != 0) {err("WSACleanup");return ;}cout << "客户端连接已关闭。" << endl;system("pause");}

#include"load_socket.h"
int main() {Socket* so = new Socket();string ip;while (true) {cout << "请输入IP地址: ";cin >> ip;bool flag = so->JUDEG_IP(ip);if (flag == true) {break;}else{cout << "输入的IP地址不存在或者错误" << endl;}}cout << "已建立连接。" << endl;string file1, file2;while (true) {cout << "首先请客户端输入想要下载的文件路径: ";cin >> file1;cout << endl;cout << "其次请服务端输入想要下载的文件保存路径: ";cin >> file2;so->INPUT_FILE(file1, file2);so->MAIN_SOCKET();}so->CLEAR();
}

服务端:

#pragma once
#ifndef _LOAD_SOCKET_H_
#define _LOAD_SOCKET_H_
#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;
class Server {private:SOCKET servSocket;SOCKET clientSock;int id;public://获取当前日期void OBTION_TIME();//获取开始时间double START_TIME();//获取结束时间double END_TIME();//获取文件大小void getByteSize(unsigned long long size);static DWORD WINAPI transmmit(const LPVOID arg);//清除库void CLEAR();int MAIN_SERVER();
};
//定义结构体用来设置
typedef struct my_file
{SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;
#endif // !_LOAD_SOCKET_H_

#include "load_server.h"mutex m;
//获取当前日期
void Server::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 Server::START_TIME() {DWORD start_time;start_time = GetTickCount64();return (double)start_time;
}
//获取结束时间
double Server::END_TIME() {DWORD end_time;end_time = GetTickCount64();return double(end_time);
}
//获取文件大小
void Server::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;}
}//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)
DWORD WINAPI Server::transmmit(const LPVOID arg) {//上锁是为了方便看输出m.lock();Server* so = (Server*)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(so->clientSock, 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;}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 << "下载文件时间: ";so->OBTION_TIME();double start_time = so->START_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(so->clientSock, 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(so->clientSock, Buffer, size, NULL) < 0) {cout << "下载出错,请检查网络配置。" << endl;break;}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(so->clientSock, t, strlen(t), NULL);cout << so->id << "线程已成功发送" << file_name << endl;cout << "下载文件大小: ";len_file = (unsigned long long)len_file;so->getByteSize(len_file);cout << "文件下载结束时间: ";double end_time = so->END_TIME();so->OBTION_TIME();double currentTime = 0;currentTime =(double)(end_time-start_time)/ CLOCKS_PER_SEC;cout << "下载文件耗时: " << currentTime <<"s"<< endl;fclose(fp);}m.unlock();return 0;
}
int Server::MAIN_SERVER() {//加载网络库WSADATA wsaData;//第一个参数是winsocket load的版本号(2.2)if (WSAStartup(MAKEWORD(2, 3), &wsaData) != 0) {err("WSAStartup");return 0;}//创建服务器端的socket(协议族, sokcet类型)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 = INADDR_ANY; //define s_addr = S_un.S_addr//将之前创建的servSocket和端口,IP地址绑定if (bind(servSocket, (SOCKADDR*)&servAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {err("bind");return 0;}listen(servSocket, 1); //监听服务器端口cout << "等待连接..." << endl;sockaddr_in clntAddr;int nSize = sizeof(clntAddr);clientSock = accept(servSocket, (SOCKADDR*)&clntAddr, &nSize);while(true){//“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;HANDLE hThread[2]; //获取句柄memset(hThread, 0, sizeof(hThread));//最多可以接受20个请求for (int i = 0; i < 1; i++) {if (clientSock == INVALID_SOCKET) {err("accept");break;}//通过句柄创建子线程,使用 API 的 CreateThread, 它执行完入口函数后会自动退出, 无需 ExitThread;hThread[i] = CreateThread(NULL, 0, &transmmit, this, 0, NULL);}//等待子线程完成WaitForMultipleObjects(1, hThread, TRUE, INFINITE);cout << "错误代码: " << WSAGetLastError() << endl;}return 0;
}
void Server::CLEAR(){关闭网络库 closesocket(servSocket);closesocket(clientSock);if (WSACleanup() != 0) {err("WSACleanup");return;}cout << "客户端连接已关闭。" << endl;system("pause");}

#include "load_server.h"
int main() {Server* so = new Server();so->MAIN_SERVER();so->CLEAR();return 0;
}

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

  1. 使用C++基于Socket编程实现文件下载

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

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

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

  3. Java Socket编程----通信是这样炼成的

    转载自 Java Socket编程----通信是这样炼成的 Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而在网络编程中,使用最多的就是Socke ...

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

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

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

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

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

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

  7. 基于Socket的文件传输(使用CSocket类)

    本软件使用MFC采用面向对象的方法实现了基于Socket的文件传输.这是原来研究生课程的结课作业,实现了Socket的发送和接收,以及读取ini配置文件等操作.使用了CSocket类 以下是当时结课作 ...

  8. 把socket相关函数封装成类

    book241.cpp和book242.cpp程序已经有点长了,有些啰嗦了,如果还想扩展功能,或用于多进程.多线程,程序结构将非常复杂. 不管是socket通信程序的客户端还是服务端,准备工作的代码又 ...

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

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

最新文章

  1. $(function(){})、$(document).ready(function(){})....../ ready和onload的区别
  2. 限时福利:腾讯高级专家手把手教你打造 OCR 神器!
  3. C# 配置文件读取与修改
  4. 【数据平台】centos下部署anaconda2和pyhs2组件
  5. c语言内存拷贝 memcpy()函数
  6. redhat6.4执行二进制程序报错:/lib/ld-linux.so.2: bad ELF interpreter: No such file or directory...
  7. Starling 2D框架简介
  8. android系统签名app自动更新,【Android 进阶】Apk 使用系统签名
  9. 爬虫入门学习:爬取股票论坛信息
  10. 能够使用StringBuilder类的常用方法操纵字符串 1215
  11. LeetCode004-寻找两个正序数组的中位数(Median of two sorted arrays)-Rust语言实现
  12. bzoj 4316: 小C的独立集(仙人掌树形DP)
  13. 链表讲解和基本操作练习附代码
  14. RabbitMQ文档翻译——Hello World!(下)
  15. xp系统怎么添加ntp服务器,1 Windows xp NTP服务器的配置
  16. 服务器按f11才能进系统,电脑每次开机都需要按f11进入选择开启项才能开启系统,...
  17. jzy3D安装到弃坑
  18. 使用web设计器制作图表报表
  19. linux中svn卸载,linux svn 安装 配置 及 卸载
  20. CSS精灵图(sprite)

热门文章

  1. Zookeeper源码分析:Leader角色初始化
  2. 汇编语言中带点/小数点的是什么
  3. SVO: 视觉SLAM中特征点法与直接法结合
  4. 漂亮,LSTM模型结构的可视化
  5. 超硬核的 Python 数据可视化教程!
  6. 第1章统计学习方法概论之1.1统计学习
  7. Python3经典100例(③)
  8. 【安全牛学习笔记】字典、在线密码破解-hydra
  9. 扒一扒.net、.net framework、mono和Unity
  10. 深入分析Java的序列化与反序列化