900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > 使用C++实现Socket编程传输协议文件(包括大文件)

使用C++实现Socket编程传输协议文件(包括大文件)

时间:2020-03-12 09:44:39

相关推荐

使用C++实现Socket编程传输协议文件(包括大文件)

使用:

(1)首先运行服务端,待服务端运行起来;

(2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址;

(3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含(代表需要传输文件的类型)。

例如:E:/Data(D)/Cat_and_Dog/dog.jpg

参考博主:/sinat_23118323/article/details/71024351

1.客户端:

#pragma once#ifndef _TCPSOCKET_H_#define _TCPSOCKET_H_#include <WinSock2.h> //windows socket的头文件#include <Windows.h>#include <iostream>#include <thread>#include <process.h>#include<mutex>#include<string>#include<atlimage.h>#include<process.h>#include<algorithm>#define MAX 1024*10#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;string ip;char wb_file[MAXBYTE];unsigned long long g_fileSize;public://获取ClientSockSOCKET Getcientsock();//获取当前日期void OBTION_TIME();//获取开始时间double START_TIME();//获取结束时间double END_TIME();//获取文件大小void getByteSize(unsigned long long size);//返回以MB为单位的文件大小unsigned long long RETURN_MB(unsigned long long size);//判断输入IP是否存在bool TARGE_FILE(string ip);//输入文件void SEND_FILE(string file);//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)static DWORD WINAPI transmmit(const LPVOID arg);bool INPUT_IP(string ipt);//系统的实现以上函数int MAIN_SOCKET();//获取图片的高度int getHeight(string file);//获取图片的宽度int getWidth(string file);//清理和关闭网络库void CLEAR();//有裸数据的情况下void send_image(int width,int height,int depth,char *data, int length);//接收图片static DWORD WINAPI run(const LPVOID arg);//接收图片的线程void Thread();//一次性发送的文件bool send_once(char*Buffer,int length);//接收文件int Socket_Recv();string TYPE_file();void REVER_file(string file1, string file2);//测试传输打包文件void MAIN_SOCKET_File();//测试传输打包文件线程static DWORD WINAPI RUN(const LPVOID arg);//发送打包文件头void Send_FileHeader(char files[MAXBYTE], unsigned long long length);//发送打包文件尾void Send_FileEnd(char files[MAXBYTE], unsigned long long length);};//定义结构体用来设置typedef struct my_file{SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号}F;struct Potocol {unsigned long long length;};struct LogicHeader {int type;int logic_raw_size;int log_raw_offset;};struct image {int width;int height;int depth;char data[0];};struct imageCli {Potocol pl;LogicHeader lh;image images;};struct FileHeader {char name[64];//文件名称int dataType;//文件包的类别,0-表示打开文件 1-表示数 2-表示文件传输结束unsigned long long length;char raw[0];};struct FileHeaderSr {Potocol p;LogicHeader lh;FileHeader file;};#endif // !_TCPSOCKET_H_

#include "tcpSocket.h"#define MAXBYTES 300*1024//表示一秒钟会有多少个时钟计时单元#define CLOCKS_PER_SEC ((clock_t)1000) 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);}SOCKET Socket::Getcientsock() {return clientSock;}//获取文件大小void Socket::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;return;}}void Socket::SEND_FILE(string file) {int i = 0;char Temporary_file[MAXBYTE] = {0 };//保存发送文件的格式for (i = 0; i < file.length(); i++) {wb_file[i] = file[i];Temporary_file[i] = file[i];}wb_file[i] = '\0';Temporary_file[i] = '\0';send(clientSock, Temporary_file, strlen(Temporary_file), 0);struct _stat64 st;_stat64(wb_file, &st);g_fileSize = st.st_size;}//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)DWORD WINAPI Socket::transmmit(const LPVOID arg) {//上锁是为了方便看输出m.lock();//F* temp = (F*)arg;Socket* so = (Socket*)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* file_name; //文件路径char File_Alias[100] = {0 };file_name = so->wb_file;unsigned long long len_file = 0;FILE* fp = fopen(file_name, "rb");if (fp == NULL) {cout << "文件" << file_name << "出错或不存在" << endl;}else {/*获取文件大小注意这个地方不能使用unsigned long long,因为当文件传输很大的时候,ftell返回的是longfseek(fp, 0, SEEK_END);//将读取的文件指针放到文件末尾g_fileSize = ftell(fp);fseek(fp, 0, SEEK_SET);//指针移到文件开头*/string send_file_len;send_file_len = to_string(so->g_fileSize);send(so->clientSock, send_file_len.c_str(), send_file_len.length(), 0);cout << "发送文件时间: ";so->OBTION_TIME();double start_time = so->START_TIME();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, (unsigned long long)size, NULL) < 0){cout << "传输出错,请检查网络配置。" << endl;break;}len_file += size;cout.width(3);//i的输出为3位宽if ((len_file * 100 / so->g_fileSize) % 5 > 0) {cout << (len_file * 100 / so->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 << "发送文件大小: ";so->getByteSize(len_file);cout << "文件发送结束时间: ";so->OBTION_TIME();double end_time = so->END_TIME();double currentTime = 0;currentTime = (double)(end_time - start_time) / CLOCKS_PER_SEC;cout << "发送文件耗时: " << currentTime << "s" << 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;}//发送打包文件头void Socket::Send_FileHeader(char files[MAXBYTE],unsigned long long length) {char* buf = new char[sizeof(FileHeaderSr) + length + 10];FileHeaderSr& file = *(FileHeaderSr*)buf;file.file.dataType = 0;file.file.length = length;for (int i = 0; i < strlen(files); i++) {file.file.name[i] = files[i];}file.file.name[strlen(files)] = '\0';file.lh.type = 1;file.lh.logic_raw_size = length;file.lh.log_raw_offset = sizeof(file.lh) + sizeof(file.file);file.p.length = file.lh.logic_raw_size + file.lh.log_raw_offset;//memcpy(buf + file.lh.log_raw_offset + 4, files, length);send(clientSock, buf, file.p.length + sizeof(file.p) + 5, 0);delete[]buf;}//发送打包文件尾void Socket::Send_FileEnd(char files[MAXBYTE], unsigned long long length) {char* buf = new char[sizeof(FileHeaderSr) + length + 10];FileHeaderSr& file = *(FileHeaderSr*)buf;file.file.dataType = 2;file.file.length = length;for (int i = 0; i < strlen(files); i++) {file.file.name[i] = files[i];}file.file.name[strlen(files)] = '\0';file.lh.type = 1;file.lh.logic_raw_size = length;file.lh.log_raw_offset = sizeof(file.lh) + sizeof(file.file);file.p.length = file.lh.logic_raw_size + file.lh.log_raw_offset;//memcpy(buf + file.lh.log_raw_offset + 4, files, length);send(clientSock, buf, file.p.length + sizeof(file.p) + 5, 0);delete[]buf;}//测试传输打包文件//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)DWORD WINAPI Socket::RUN(const LPVOID arg) {m.lock();Socket* so = (Socket*)arg;cout << "测试开始,等待服务端发送消息..." << endl;char* file_name; //文件路径char File_Alias[100] = {0 };file_name = so->wb_file;cout <<"wb_file = "<< so->wb_file << endl;unsigned long long len_file = 0;//发送文件开始so->Send_FileHeader(so->wb_file, so->g_fileSize);FILE* fp = fopen(file_name, "rb");if (fp == NULL) {cout << "文件" << file_name << "出错或不存在" << endl;}else {string send_file_len;send_file_len = to_string(so->g_fileSize);send(so->clientSock, send_file_len.c_str(), send_file_len.length(), 0);cout << "发送文件时间: ";so->OBTION_TIME();double start_time = so->START_TIME();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, (unsigned long long)size, NULL) < 0) {cout << "传输出错,请检查网络配置。" << endl;break;}len_file += size;cout.width(3);//i的输出为3位宽if ((len_file * 100 / so->g_fileSize) % 5 > 0) {cout << (len_file * 100 / so->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;//表示发送文件结束so->Send_FileEnd(so->wb_file, so->g_fileSize);cout << "发送文件大小: ";so->getByteSize(len_file);cout << "文件发送结束时间: ";so->OBTION_TIME();double end_time = so->END_TIME();double currentTime = 0;currentTime = (double)(end_time - start_time) / CLOCKS_PER_SEC;cout << "发送文件耗时: " << currentTime << "s" << endl;fclose(fp);}m.unlock();return 0;}//测试传输打包文件void Socket::MAIN_SOCKET_File() {//建立连接//while (true) {cout << "已建立连接。" << endl;char Buffer[MAXBYTE] = {0 }; // 文件缓冲区char wb_file[100] = {0 }; //写入的文件//“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;HANDLE hThread[2];for (int i = 0; i < 1; i++) {sockaddr_in clntAddr;memset(&clntAddr, 0, sizeof(SOCKADDR));//使用 API 的 CreateThread, 它执行完入口函数后会自动退出, 无需 ExitThread;hThread[i] = CreateThread(NULL, 0, &RUN, this, 0, NULL);}//等待子线程完成WaitForMultipleObjects(1, hThread, TRUE, INFINITE);cout << "错误代码: " << WSAGetLastError() << endl;}bool Socket::INPUT_IP(string ipt) {//客户端socket//加载winsock库WSADATA wsadata;//WSA-windows socket ansyc windows的异步套接字 2.2版本的if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) {err("WSAStartup");return 0;}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);const char* ips = ipt.c_str();clientAddr.sin_family = AF_INET;clientAddr.sin_port = htons(3725);//将本地字节序转换为网络字节序,大端和小端存储clientAddr.sin_addr.s_addr = inet_addr(ips);if (connect(clientSock, (SOCKADDR*)&clientAddr, sizeof(SOCKADDR)) == SOCKET_ERROR) {err("connect");return false;}return true;}//获取图片的高度int Socket::getHeight(string file) {char buf[MAXBYTE] = {0 };for (int i = 0; i < file.length(); i++) {buf[i] = file[i];}buf[file.length()] = '\0';LPCTSTR srcFilepath = _T(buf);CImage srcImage;srcImage.Load(srcFilepath);try {int height = srcImage.GetHeight();return height;}catch (exception& e) {cout << e.what() << endl;}}//获取图片的宽度int Socket::getWidth(string file) {char buf[MAXBYTE] = {0 };for (int i = 0; i < file.length(); i++) {buf[i] = file[i];}buf[file.length()] = '\0';LPCTSTR srcFilepath = _T(buf);CImage srcImage;srcImage.Load(srcFilepath);try {int width = srcImage.GetWidth();return width;}catch (exception& e) {cout << e.what() << endl;}}//有裸数据的情况下void Socket::send_image(int width, int height, int depth, char* data, int length) {char* buf = new char[sizeof(imageCli) + length+10];imageCli& image = *(imageCli*)buf;image.images.width = width;image.images.height = height;image.images.depth = depth;/** 测试读取的文件是否正确FILE* fp = fopen("D:\\5.jpg", "wb");if (fp == NULL) {fp = fopen("D:\\5.jpg", "w");}fwrite(data, sizeof(char), length, fp);fclose(fp);*/image.lh.type = 1;image.lh.logic_raw_size = length;image.lh.log_raw_offset = sizeof(image.lh) + sizeof(image.images);image.pl.length = image.lh.logic_raw_size + image.lh.log_raw_offset;memcpy(buf + image.lh.log_raw_offset+4, data, length);send(clientSock, buf, image.pl.length + sizeof(image.pl)+5, 0);delete []buf;}//一次性发送的文件bool Socket::send_once(char* Buffer, int length) {int byteReceivedOnce = 0;int bytesReceivedAll = 0;while (bytesReceivedAll < length) {if ((byteReceivedOnce = send(clientSock, Buffer + bytesReceivedAll, length - bytesReceivedAll, NULL)) < 0) {return false;}bytesReceivedAll += byteReceivedOnce;}return true;}//接收和传输文件目录bool Socket::TARGE_FILE(string ip) {bool flag = INPUT_IP(ip);if (flag == true)return 1;else {return 0;}}DWORD WINAPI Socket::run(const LPVOID arg) {Socket* soc = (Socket*)arg;char* img=NULL;while (true) {int ret = recv(soc->clientSock, img, strlen(img), NULL);}}void Socket::Thread() {CreateThread(NULL, 0, &run, this, 0, NULL);}int Socket::MAIN_SOCKET() {//建立连接//while (true) {cout << "已建立连接。" << endl;char Buffer[MAXBYTE] = {0 }; // 文件缓冲区char wb_file[100] = {0 }; //写入的文件//“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;HANDLE hThread[2];for (int i = 0; i < 1; i++) {sockaddr_in clntAddr;memset(&clntAddr, 0, sizeof(SOCKADDR));//使用 API 的 CreateThread, 它执行完入口函数后会自动退出, 无需 ExitThread;hThread[i] = CreateThread(NULL, 0, &transmmit, this, 0, NULL);}//等待子线程完成WaitForMultipleObjects(1, hThread, TRUE, INFINITE);cout << "错误代码: " << WSAGetLastError() << endl;//}return 0;}int Socket::Socket_Recv() {char Buffer[MAXBYTES] = {0 }; // 文件缓冲区char wb_files[MAXBYTE] = {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();unsigned long long g_fileSizes = 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_fileSizes = g_fileSizes * 10 + ((unsigned long long)rev_buffer[i] - 48);}}double start_time = START_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;size -= 3;if (fwrite(buffer, sizeof(char), size, fp) < size) {cout << "写入出错,部分文件缺失。" << endl;break;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSizes) % 5 > 0) {cout << (len_file * 100 / g_fileSizes) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}break;}else {if (fwrite(Buffer, sizeof(char), size, fp) < size) {cout << "写入出错,部分文件缺失。" << endl;break;}len_file += size;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSizes) % 5 > 0) {cout << (len_file * 100 / g_fileSizes) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}//清空缓存区以便下一次接收memset(&Buffer, 0, MAXBYTE);}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;}string Socket::TYPE_file() {string end_file = "";char Temporary[1024] = {0 };char file[1024] = {0 };int index_last = 0;int ret = recv(clientSock, file, 100, 0);for (int i = strlen(file) - 1; i >= 0; i--) {if (file[i] == '\\') {index_last = i;break;}}index_last++;end_file += "\\";if (ret > 0) {file[ret] = '\0';for (int i = index_last; i < strlen(file); i++) {end_file += file[i];}}return end_file;}void Socket::REVER_file(string file, string filename) {int i = 0;memset(wb_file, 0, sizeof(wb_file));int len_file = file.length();int len_filename = filename.length();for (i = 0; i < len_file; i++) {wb_file[i] = file[i];}int j = 0;for (i = len_file; i < (len_file + len_filename) && j < len_filename; j++, i++) {wb_file[i] = filename[j];}wb_file[i] = '\0';}void Socket::CLEAR() {closesocket(clientSock);关闭网络库 if (WSACleanup() != 0) {err("WSACleanup");return;}cout << "客户端连接已关闭。" << endl;system("pause");}

#include"tcpSocket.h"#define MAXBYTES 1024int main() {Socket* soc = new Socket();while (true) {string ip;cout << "请输入目标机器的IP:";cin >> ip;bool flag = soc->TARGE_FILE(ip);if (flag == true)break;else {cout << "IP地址错误或者目标主机不存在" << endl;continue;}}string wb_file;char Tempoary[1024] = {0 };char Buffer[MAXBYTES] = {0 };cout << "首先请客户端输入传输文件路径: ";string file;cin >> file;soc->SEND_FILE(file);int ret = recv(soc->Getcientsock(), Tempoary, 10, 0);if (ret < 0) {soc->CLEAR();return 0;}soc->MAIN_SOCKET_File();/** 图像传输测试* string filename;char buf[MAXBYTE] = { 0 };int g_fileSize = 0;cout << "请输入文件路径: ";cin >> filename;for (int i = 0; i < filename.length(); i++) {buf[i] = filename[i];}buf[filename.length()] = '\0';struct _stat64 st;_stat64(buf, &st);g_fileSize = st.st_size;char* Buffer = new char[g_fileSize + 1];int width = soc->getWidth(buf);int height = soc->getHeight(buf);FILE* fp = fopen(buf, "rb+");if (fp == NULL) {cout << "文件打开错误" << endl;return 0;}int size = 0;if ((size=fread(Buffer, sizeof(char), g_fileSize, fp) )> 0) {soc->send_image(width, height, 2, Buffer, g_fileSize);}else {cout << "传输出现问题" << endl;}delete[]Buffer;*//*link nod = soc->initstruct();memset(Buffer, 0, sizeof(Buffer));memcpy(Buffer, &nod, sizeof(link));soc->send_once(Buffer, sizeof(link) + 1);*//*while (true) {string wb_file;char Tempoary[1024] = { 0 };char Buffer[MAXBYTES] = { 0 };cout << "首先请客户端输入传输文件路径: ";string file;cin >> file;soc->SEND_FILE(file);int ret = recv(soc->Getcientsock(), Tempoary, 10, 0);if (ret < 0)continue;soc->MAIN_SOCKET();cout << "其次请客户端输入想要写入的文件(不用输入文件名): ";cin >> wb_file;string st = "ESC";string end_file = soc->TYPE_file();send(soc->Getcientsock(), st.c_str(), st.length(), 0);soc->REVER_file(wb_file, end_file);soc->Socket_Recv();}*/soc->CLEAR();delete soc;return 0;}

2.服务端:

#pragma once#ifndef _TCPSERVER_H_#define _TCPSERVER_H_#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 MAX 10*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 clientSock;SOCKET servSocket;int id;char wb_file[MAXBYTE];//写入文件路径char wb_files[MAXBYTE];//发送文件路径char filename[MAXBYTE];unsigned long long g_fileSize;public://获取clientSockSOCKET GetclientSock();//获取servSocketSOCKET GetservSocket();//获取当前日期void OBTION_TIME();//获取开始时间double START_TIME();//获取结束时间double END_TIME();//获取文件大小void getByteSize(unsigned long long size);//返回以MB为单位的文件大小unsigned long long RETURN_MB(unsigned long long size);//绑定和监听void TARGE_FILE();//返回文件的类型string TYPE_file();//LPVOID是一个没有类型的指针,也就是说你可以将任意类型的指针赋值给LPVOID类型的变量(一般作为参数传递)static DWORD WINAPI transmmit(const LPVOID arg);//系统的实现以上函数int MAIN_Server();//接收文件void REVER_file(string file, string fileanme);//清理网络库和关闭void CLEAR();//发送图片static DWORD WINAPI run(const LPVOID arg);//发送图片的线程void Thread();//一次性的接收发送的文件等bool recv_once(char *buffer, unsigned long long length);//处理接收到的信息void solve_file();//根据分类来处理信息,鼠标,键盘,文件,图片等void do_handle(char *Buffer, unsigned long long length);//发送文件int Server_Send();//发送文件1void SEND_FILE(string file);//测试接收打包文件void MAIN_Server_File();int do_handle_file(char* Buffer, unsigned long long length);};//定义结构体用来设置typedef struct my_file {SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号}F;struct Potocol {unsigned long long length;//代表整个数据包的长度};struct LogicHeader {int type;//代表业务类型int logic_raw_size;//裸数据的长度int log_raw_offset;//裸数据的偏移};struct image {//图像业务int width;int height;int depth;char data[0];};struct imageSer {LogicHeader lh;image images;};struct FileHeader {char name[64];//文件名称int dataType;//文件包的类别,0-表示打开文件 1-表示数 2-表示文件传输结束unsigned long long length;char raw[0];};struct FileHeaderCli {LogicHeader lh;FileHeader file;};#endif // !_TCPSERVER_H_

#include "tcpServer.h"#define MAXBYTES 300*1024mutex 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;return;}}string Server::TYPE_file() {string end_file = "";char Temporary[1024] = {0 };char file[1024] = {0 };int index_last = 0;int ret = recv(GetclientSock(), file, 100, 0);for (int i = strlen(file) - 1; i >= 0; i--) {if (file[i] == '\\') {index_last = i;break;}}index_last++;end_file += "\\";if (ret > 0) {file[ret] = '\0';for (int i = index_last; i < strlen(file); i++) {end_file += file[i];}}return end_file;}void Server::TARGE_FILE() {//加载网络库WSADATA wsaData;//第一个参数是winsocket load的版本号(2.2)if (WSAStartup(MAKEWORD(2, 3), &wsaData) != 0) {err("WSAStartup");return;}//创建服务器端的socket(协议族, sokcet类型)servSocket = socket(AF_INET, SOCK_STREAM, 0);//如果改成SOCK_DGRAM则使用UDPif (servSocket == INVALID_SOCKET) {err("SOCKET");return;}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(3725); //设置使用的端口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;}HANDLE hThread[2];hThread[0]=CreateThread(NULL, 0, &run, this, 0, NULL);WaitForMultipleObjects(1, hThread, TRUE, INFINITE);/*listen(servSocket, 1); //监听服务器端口sockaddr_in clntAddr;int nSize = sizeof(clntAddr);cout << "等待连接..." << endl;clientSock = accept(servSocket, (SOCKADDR*)&clntAddr, &nSize);if (clientSock == INVALID_SOCKET) {err("accept");}cout << "连接成功" << endl;*/}DWORD WINAPI Server::run(const LPVOID arg) {Server* ser = (Server*)arg;listen(ser->servSocket, 1); //监听服务器端口sockaddr_in clntAddr;int nSize = sizeof(clntAddr);cout << "等待连接..." << endl;ser->clientSock = accept(ser->servSocket, (SOCKADDR*)&clntAddr, &nSize);if (ser->clientSock == INVALID_SOCKET) {err("accept");}cout << "连接成功" << endl;return 0;}void Server::REVER_file(string file, string filename) {int i = 0;int len_file = file.length();int len_filename = filename.length();for (i = 0; i < len_file; i++) {wb_file[i] = file[i];}int j = 0;for (i = len_file; i < (len_file + len_filename) && j < len_filename; j++, i++) {wb_file[i] = filename[j];}wb_file[i] = '\0';}SOCKET Server::GetclientSock() {return clientSock;}SOCKET Server::GetservSocket() {return servSocket;}/**/bool Server::recv_once(char *buffer,unsigned long long length) {unsigned long long byteReceivedOnce = 0;unsigned long long bytesReceivedAll = 0;while (bytesReceivedAll <length) {if ((byteReceivedOnce = recv(clientSock, buffer + bytesReceivedAll, length - bytesReceivedAll, NULL)) < 0) {return false;}bytesReceivedAll += byteReceivedOnce;}return true;}void Server::do_handle(char *Buffer, unsigned long long length) {LogicHeader& lh = *(LogicHeader*)Buffer;//测试传输图片是否完整/*FILE* fp = fopen("D:\\3.jpg", "wb");if (fp == NULL) {fp = fopen("D:\\3.jpg", "w");}*/switch (lh.type) {case 1:imageSer & image = *(imageSer*)Buffer;char* raw_data = Buffer + image.lh.log_raw_offset;int Logic_lengths = image.lh.logic_raw_size;raw_data[Logic_lengths] = '\0';/*fwrite(raw_data, sizeof(char), Logic_lengths, fp);fclose(fp);*/cout << "发送数据包大小 = " << length << endl;cout << "数据类型 = " << lh.type << endl;cout << "裸数据长度= " << Logic_lengths << endl;cout << "裸数据的偏移 = " << lh.log_raw_offset << endl;cout << "图像宽度 = " << image.images.width << endl;cout << "图像高度 = " << image.images.height << endl;cout << "图片深度 = " << image.images.depth << endl;break;}}void Server::solve_file() {unsigned long long length = 0;unsigned long long ret = recv(clientSock, (char*)&length, sizeof(length),NULL);cout << "ret = " <<ret<< endl;cout << "length = " << length << endl;if (ret == sizeof(length)) {try {char* buf = new char[length+100];memset(buf, 0, sizeof(buf));if (recv_once(buf, length)) {do_handle(buf, length);}delete []buf;}catch (exception& e) {cout << e.what() << endl;}}}void Server::Thread() {CreateThread(NULL, 0, &run, this, 0, NULL);}void Server::SEND_FILE(string file) {int i = 0;char Temporary_file[MAXBYTE] = {0 };//保存发送文件的格式memset(wb_file, 0, sizeof(wb_file));for (i = 0; i < file.length(); i++) {wb_file[i] = file[i];Temporary_file[i] = file[i];}wb_file[i] = '\0';Temporary_file[i] = '\0';send(clientSock, Temporary_file, strlen(Temporary_file), 0);struct _stat64 st;_stat64(wb_file, &st);g_fileSize = st.st_size;}int Server::MAIN_Server() {char Buffer[MAXBYTES] = {0 }; // 文件缓冲区char wb_files[MAXBYTE] = {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();unsigned long long g_fileSizes = 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_fileSizes = g_fileSizes * 10 + ((unsigned long long)rev_buffer[i] - 48);}}double start_time = START_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;size -= 3;if (fwrite(buffer, sizeof(char), size, fp) < size) {cout << "写入出错,部分文件缺失。" << endl;break;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSizes) % 5 > 0) {cout << (len_file * 100 / g_fileSizes) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}break;}else {if (fwrite(Buffer, sizeof(char), size, fp) < size) {cout << "写入出错,部分文件缺失。" << endl;break;}len_file += size;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSizes) % 5 > 0) {cout << (len_file * 100 / g_fileSizes) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}//清空缓存区以便下一次接收memset(&Buffer, 0, MAXBYTE);}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;}int Server::do_handle_file(char* Buffer, unsigned long long length) {//LogicHeader& lh = *(LogicHeader*)Buffer;FileHeaderCli & file = *(FileHeaderCli*)Buffer;//char* raw_data = Buffer + file.lh.log_raw_offset;int Logic_lengths_offest = file.lh.log_raw_offset;//raw_data[Logic_lengths] = '\0';/*fwrite(raw_data, sizeof(char), Logic_lengths, fp);fclose(fp);*/cout << "功能类型 = " << file.lh.type << endl;cout << "文件名 = " << file.file.name << endl;cout << "发送数据包大小 = " << length << endl;cout << "数据类型 = " << file.file.dataType << endl;cout << "裸数据偏移= " << Logic_lengths_offest << endl;cout << "裸数据长度 = " << file.lh.logic_raw_size << endl;return file.file.dataType;}//测试接收打包文件void Server::MAIN_Server_File() {char Buffer[MAXBYTES] = {0 }; // 文件缓冲区char wb_files[MAXBYTE] = {0 };FILE* fp = fopen(wb_file, "wb");//接收打包发送来的文件unsigned long long length = 0;unsigned long long ret = recv(clientSock, (char*)&length, sizeof(length), NULL);cout << "ret = " << ret << endl;cout << "length = " << length << endl;int flag =0;if (ret == sizeof(length)) {try {char* buf = new char[length + 100];memset(buf, 0, sizeof(buf));if (recv_once(buf, length)) {flag=do_handle_file(buf, length);}delete[]buf;}catch (exception& e) {cout << e.what() << endl;}}if (flag == 0) {//如果录入文件不存在的话就创建一个新的文件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();unsigned long long g_fileSizes = 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_fileSizes = g_fileSizes * 10 + ((unsigned long long)rev_buffer[i] - 48);}}double start_time = START_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;size -= 3;if (fwrite(buffer, sizeof(char), size, fp) < size) {cout << "写入出错,部分文件缺失。" << endl;break;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSizes) % 5 > 0) {cout << (len_file * 100 / g_fileSizes) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}break;}else {if (fwrite(Buffer, sizeof(char), size, fp) < size) {cout << "写入出错,部分文件缺失。" << endl;break;}len_file += size;}cout.width(3);//i的输出为3位宽if ((len_file * 100 / g_fileSizes) % 5 > 0) {cout << (len_file * 100 / g_fileSizes) << "%";cout << "\b\b\b\b";//回删三个字符,使数字在原地变化}//清空缓存区以便下一次接收memset(&Buffer, 0, MAXBYTE);}//接收打包发送来的文件unsigned long long length = 0;unsigned long long ret = recv(clientSock, (char*)&length, sizeof(length), NULL);cout << "ret = " << ret << endl;cout << "length = " << length << endl;int flags = 0;if (ret == sizeof(length)) {try {char* buf = new char[length + 100];memset(buf, 0, sizeof(buf));if (recv_once(buf, length)) {flags = do_handle_file(buf, length);}delete[]buf;}catch (exception& e) {cout << e.what() << endl;}}if (flags == 2) {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);}}}}DWORD WINAPI Server::transmmit(const LPVOID arg) {//上锁是为了方便看输出m.lock();//F* temp = (F*)arg;Server* so = (Server*)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* file_name; //文件路径char File_Alias[100] = {0 };file_name = so->wb_file;unsigned long long len_file = 0;FILE* fp = fopen(file_name, "rb");if (fp == NULL) {cout << "文件" << file_name << "出错或不存在" << endl;}else {/*获取文件大小注意这个地方不能使用unsigned long long,因为当文件传输很大的时候,ftell返回的是longfseek(fp, 0, SEEK_END);//将读取的文件指针放到文件末尾g_fileSize = ftell(fp);fseek(fp, 0, SEEK_SET);//指针移到文件开头*/string send_file_len;send_file_len = to_string(so->g_fileSize);send(so->clientSock, send_file_len.c_str(), send_file_len.length(), 0);cout << "发送文件时间: ";so->OBTION_TIME();double start_time = so->START_TIME();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, (unsigned long long)size, NULL) < 0){cout << "传输出错,请检查网络配置。" << endl;break;}len_file += size;cout.width(3);//i的输出为3位宽if ((len_file * 100 / so->g_fileSize) % 5 > 0) {cout << (len_file * 100 / so->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 << "发送文件大小: ";so->getByteSize(len_file);cout << "文件发送结束时间: ";so->OBTION_TIME();double end_time = so->END_TIME();double currentTime = 0;currentTime = (double)(end_time - start_time) / CLOCKS_PER_SEC;cout << "发送文件耗时: " << currentTime << "s" << 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 Server::Server_Send() {//建立连接//while (true) {cout << "已建立连接。" << endl;char Buffer[MAXBYTES] = {0 }; // 文件缓冲区char wb_file[100] = {0 }; //写入的文件//“句柄” 类似指针, 但通过指针可读写对象, 通过句柄只是使用对象;HANDLE hThread[2];for (int i = 0; i < 1; i++) {sockaddr_in clntAddr;memset(&clntAddr, 0, sizeof(SOCKADDR));//使用 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() {//关闭socket,释放winsockif (this != nullptr) {closesocket(clientSock);closesocket(servSocket);}关闭网络库 if (WSACleanup()!=0) {err("WSACleanup");return;}cout << "服务器连接已关闭。" << endl;system("pause");}

#include "tcpServer.h"#define MAXBYTES 1024int main() {Server* ser = new Server();ser->TARGE_FILE();char buffer[MAXBYTES] = {0 };string wb_file;char Tempoary[MAXBYTES] = {0 };cout << "其次请服务端输入想要写入的文件(不用输入文件名): ";cin >> wb_file;string st = "ESC";string end_file = ser->TYPE_file();send(ser->GetclientSock(), st.c_str(), st.length(), 0);ser->REVER_file(wb_file, end_file);ser->MAIN_Server_File();/** 图像传输测试ser->solve_file();*//*while (true) {char buffer[MAXBYTES] = { 0 };string wb_file;char Tempoary[MAXBYTES] = { 0 };cout << "其次请服务端输入想要写入的文件(不用输入文件名): ";cin >> wb_file;string st = "ESC";string end_file = ser->TYPE_file();send(ser->GetclientSock(), st.c_str(), st.length(), 0);ser->REVER_file(wb_file, end_file);ser->MAIN_Server();cout << "首先请服务端输入传输文件路径: ";string file;cin >> file;ser->SEND_FILE(file);int ret = recv(ser->GetclientSock(), Tempoary, 10, 0);if (ret < 0)continue;ser->Server_Send();}*/ser->CLEAR();delete ser;return 0;}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。