使用C++的Socket实现从客户端到服务端,服务端到客户端传输文件

news/2024/7/2 23:20:04

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

文档说明:如果接收端(服务端或者客户端)写入文件的地方已经存在了要发送的文件名,那么接收端将不在创建新的文件名,而是覆盖当前文件名,所以在接收端是看不到进度情况,也就是显示百分比的地方,因为就是要写入的文件夹已经存在了要发送的文件名,所以创建新的文件名这段时间就已经省去了,所以接收端会马上受到来自发送端的信息,而来不及处理接收的信息长度,所以显示不出百分比。

客户端:

#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<process.h>
#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;
#pragma pack(push,1)
typedef struct node {int age;char id[25];char name[25];char key[25];
};
#pragma pack(pop)
#pragma pack(push,1)
typedef struct link {node tk;int td;unsigned long long length;
};
#pragma
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();//清理和关闭网络库void CLEAR();//对结构体中的初始化link initstruct();//接收图片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);
};
//定义结构体用来设置
typedef struct my_file
{SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;#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;
}
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;
}
//对结构中的变量初始化
link Socket::initstruct() {link nod;/*memset(nod.id, 0, sizeof(nod.id));memset(nod.name, 0, sizeof(nod.name));memset(nod.key, 0, sizeof(nod.key));*///memcpy(nod.id, "123456", sizeof(nod.id[0])*7);strcpy(nod.tk.id, "123456");//memcpy(nod.name, "tom", sizeof(nod.name[0])*4);strcpy(nod.tk.name, "tom");//memcpy(nod.key, "123456", sizeof(nod.key[0])*7);strcpy(nod.tk.key, "123456");nod.tk.age = 18;nod.td = 2;return nod;
}
//接收和传输文件目录
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;while (true) {int ret = recv(soc->clientSock, img, strlen(img), NULL);}
}
void Socket::Thread() {CreateThread(NULL, 0, &run, this, 0, NULL);
}
//一次性发送的文件
bool Socket::send_once(char* Buffer, int length) {int len = 0;int sum_len = 0;while (sum_len < sizeof(link)) {if ((len = send(clientSock, Buffer + sum_len, sizeof(link) - sum_len, NULL)) < 0) {return false;}sum_len += len;}return true;
}
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 1024
int 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;}}/*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;
}

服务端:

#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[], int length);//处理接收到的信息void solve_file(char buffer[], int length);//根据分类来处理信息,鼠标,键盘,文件,图片等void do_handle(char Buffer[], int length);//发送文件int Server_Send();//发送文件1void SEND_FILE(string file);
};
//定义结构体用来设置
typedef struct my_file {SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;
#pragma pack(push,1)
struct node {int age;char id[25];char name[25];char key[25];
};
#pragma pack(pop)
#pragma pack(push,1)
typedef struct link {node tk;int td;unsigned long long length;
};
#pragma
#endif // !_TCPSERVER_H_

#include "tcpServer.h"
#define MAXBYTES 300*1024
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;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[], int length) {link nod;memset(buffer, 0, sizeof(buffer));int len = 0;int sum_len = 0;while (sum_len < sizeof(link)) {if ((len = recv(clientSock, buffer + sum_len, sizeof(link) - sum_len, NULL)) < 0) {return false;}nod = *(link*)buffer;cout << "strlen(nod.id) = " << strlen(nod.tk.id) << endl;cout << "strlen(nod.name) = " << strlen(nod.tk.name) << endl;cout << "strlen(nod.key) = " << strlen(nod.tk.key) << endl;cout << "link.id = " << nod.tk.id << endl;cout << "link.name = " << nod.tk.name << endl;cout << "link.key = " << nod.tk.key << endl;cout << "link.age = " << nod.tk.age << endl;cout << "link.td = " << nod.td << endl;cout << "接收的文件长度: " <<nod.length << "B" << endl;sum_len += len;}return true;
}
void Server::do_handle(char Buffer[], int length) {link nod = *(link*)Buffer;switch (nod.td){case 0:cout << "图片" << endl;break;case 1:cout << "键盘" << endl;break;case 2:cout << "鼠标" << endl;break;case 3:cout << "文件" << endl;break;default:break;}
}
void Server::solve_file(char Buffer[], int length) {try {if (recv_once(Buffer, sizeof(link) + 1) ){do_handle(Buffer,length);}}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;}
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 1024
int main() {Server* ser = new Server();ser->TARGE_FILE();//unsigned long long length = 0;//ser->solve_file(buffer, sizeof(link) + 1);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;
}

http://lihuaxi.xjx100.cn/news/285829.html

相关文章

最小割 ---- 2021 ccpc 威海 H city-safety(最大利润 = 最大收益 - 最小花费(最小割))

题目链接 题目大意&#xff1a; 一棵树&#xff0c;加强第 iii 个点有 wiw_iwi​ 的花费&#xff0c;而如果距离某 个点 ≤p≤ p≤p 的所有点都加强了&#xff0c;则会有 vpv_pvp​ 的收益&#xff0c;求最大净收益。 解题思路&#xff1a; 树形dp做法想不明白为啥是对的&…

Playboy封面女郎、互联网第一夫人,程序员们的“钢铁审美”

整理 | 琥珀 出品 | AI科技大本营&#xff08;ID:rgznai100&#xff09; 46 年前&#xff0c;《花花公子》&#xff08;Playboy&#xff09;的一期杂志封面女郎 Lenna&#xff0c;成为数万“钢铁直男”的梦中女神。然而&#xff0c;这位女性更为人所知的是她在计算机图像处理领…

java自动装箱性能

2019独角兽企业重金招聘Python工程师标准>>> Java 的基本数据类型&#xff08;int、double、 char&#xff09;都不是对象。但由于很多Java代码需要处理的是对象&#xff08;Object&#xff09;&#xff0c;Java给所有基本类型提供了包装类&#xff08;Integer、Dou…

[NC16591]关押罪犯 并查集

题解&#xff1a;很明显的并查集&#xff0c;但因为它们带有权值&#xff0c;所以我们先要把他排序&#xff0c;我们要尽可能让危害大的罪犯在两个监狱里&#xff08;这里有一点贪心的味道&#xff09;。 1.首先我们把它门按照之间的影响值从大到小排序。 2.假设a与b是敌人&…

简单分析MySQL 一则慢日志监控误报问题

这篇文章主要介绍了MySQL 一则慢日志监控误报的问题分析与解决&#xff0c;帮助大家更好的理解和使用MySQL&#xff0c;感兴趣的朋友可以了解下 之前因为各种原因&#xff0c;有些报警没有引起重视&#xff0c;最近放假马上排除了一些潜在的人为原因&#xff0c;发现数据库的慢…

一直在努力的你是否也是这样的(经典语录总结)

1.下次再遇见喜欢的人&#xff0c;一定要提醒自己&#xff0c;只做朋友&#xff0c;只谈笑风生&#xff0c;不可以动情&#xff0c;不远不近的欣赏&#xff0c;淡淡的喜欢&#xff0c;不至于最后乱了初心&#xff0c;败了芳华。 ——杨绛 2.走好选择的路&#xff0c;别选择好走…

前缀和 + ST表 ---- CF 1556 E. Equilibrium(两个序列 + - 操作使得每位相等) 详解

题目连接 题目大意&#xff1a; 就是给你两个长度为nnn的a,ba,ba,b数组&#xff0c;给你q∈[1,1e5]q\in[1,1e5]q∈[1,1e5]次询问&#xff0c;每次询问一个区间[l,r][l,r][l,r] 你对这个区间里面的数可以进行一下操作 取出偶数个位置 l≤pos1<pos2<....<posz≤r∣[z%…

手写 30 个主流机器学习算法,代码超 3 万行,全都开源了!

点击上方“视学算法”&#xff0c;选择“星标”公众号第一时间获取价值内容本文经机器之心&#xff08;ID&#xff1a;almosthuman2014&#xff09;授权转载&#xff0c;禁二次转载参与&#xff1a;思源、一鸣、张倩用 NumPy 手写所有主流 ML 模型&#xff0c;普林斯顿博士后 D…