使用:
(1)首先运行服务端,待服务端运行起来;
(2)最后运行客户端,输入要传输文件到哪个目标机器的IP地址;
(3)输入传输文件的路径及文件(完成的路径),其中包含文件的类型,也就是后缀需要包含(代表需要传输文件的类型)。
例如:E:/Data(D)/Cat_and_Dog/dog.jpg
参考博主:https://blog.csdn.net/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);
};
//定义结构体用来设置
typedef struct my_file
{SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信sockaddr_in clientAddr; //用于保存客户端的socket地址int id; //文件块的序号
}F;
struct Potocol {int 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-表示文件传输结束uint64_t 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;
}
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 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;}}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,int length);//处理接收到的信息void solve_file();//根据分类来处理信息,鼠标,键盘,文件,图片等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;
struct Potocol {int 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-表示文件传输结束uint64_t length;char raw[0];
};
struct FileHeaderCli {LogicHeader lh;FileHeader file;
};
#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) {int byteReceivedOnce = 0;int 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, int 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() {int length = 0;int 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;}
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();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;
}

使用C++实现Socket编程图片打包传输(修改)相关推荐

  1. java socket 传多个文件下载,Socket编程多文件传输

    有子曰:"其为人也孝弟,而好犯上者,鲜矣:不好犯上,而好作乱者,未之有也.君子务本,本立而道生.孝弟也者,其为仁之本与!" 项目介绍:基于TCP协议实现多文件传输 将F盘test文 ...

  2. socket编程实现文件传输功能

    这节我们来完成 socket 文件传输程序,这是一个非常实用的例子.要实现的功能为:client 从 server 下载一个文件并保存到本地. 编写这个程序需要注意两个问题: 1) 文件大小不确定,有 ...

  3. 【Java】UDP Socket编程案例——文件传输聊天工具

    UDP(用户数据报协议)就像日常生活中的邮件投递,是不能保证可靠地寄到目的地.UDP是无连接的,对系统资源的要求较少,UDP可能丢包,也不保证数据顺序.但是对于网络游戏和在线视频等要求传输快,实时性高 ...

  4. socket编程二十二:socket编程实现文件传输功能

    这节我们来完成 socket 文件传输程序,这是一个非常实用的例子.要实现的功能为:client 从 server 下载一个文件并保存到本地. 编写这个程序需要注意两个问题: 1) 文件大小不确定,有 ...

  5. 例程:socket编程实现文件传输功能

    程序要实现的功能:client 从 server 下载一个文件并保存到本地. 编写这个程序需要注意两个问题: (1)文件大小不确定 有可能比缓冲区大很多,调用一次 write()/send() 函数不 ...

  6. socket 编程实现文件传输功能!强无敌,网络通讯的必备知识储备!

    socket 文件传输程序,这是一个非常实用的例子. 要实现的功能为:client 从 server 下载一个文件并保存到本地. 编写这个程序需要注意两个问题: ======== 1) 文件大小不确定 ...

  7. 【Java】TCP Socket编程案例——文件传输聊天工具

    TCP(传输控制协议)是面向连接的可靠数据传输协议.TCP连接一旦建立起来,一直占用,直到关闭连接.另外,TCP为了保证数据的正确性,会重发一切没有收到的数据,还会对数据内容进行验证,并保证数据传输的 ...

  8. Socket编程(C语言实现)——UDP协议(进程间通信AF_UNIX)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【循环监听】

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

  9. Socket编程(C语言实现)——TCP协议(网络间通信AF_INET)的流式(SOCK_STREAM)+报式(SOCK_DGRAM)传输【多线程+循环监听】

    Socket编程 目前较为流行的网络编程模型是客户机/服务器通信模式 客户进程向服务器进程发出要求某种服务的请求,服务器进程响应该请求.如图所示,通常,一个服务器进程会同时为多个客户端进程服务,图中服 ...

最新文章

  1. 三十二、图的创建深度优先遍历(DFS)广度优先遍历(BFS)
  2. git 删除远程分支
  3. iOS开发 QQ粘性动画效果
  4. 图解Windows下开发Objective-C程序之二 - Objective-C入门例子
  5. 计算机科学与技术 单片机,单片机-兰州交通大学计算机科学与技术实验教学中心...
  6. bzoj 1079: [SCOI2008]着色方案
  7. Something about mvss
  8. 迅雷2019校园招聘 内推码
  9. linux服务器上的cad病毒,LibreCAD_LibreCAD下载[2021官方最新版]LibreCAD安全下载_ 极速下载...
  10. 【图像搜索】基于pytorch官方预训练模型的简易相似图片搜索
  11. 计算机一级用写在简历里面吗,写简历要小心,简历填写最忌讳的是什么,你知道吗?...
  12. 软件测试工程师有哪些要求
  13. Vue知识点囊括清单
  14. 拉格朗日松弛(二)——实例及代码
  15. 关于谷歌浏览器请求action两次
  16. iOS 7、iOS 8屏幕适配
  17. ASP.NET微信群机器人管家系统,源码分享
  18. Ubuntu 16.04 安装好之后需要做的15件事
  19. java计算机毕业设计自动化办公系统源码+mysql数据库+系统+lw文档+部署
  20. 759页14万字智慧大楼弱电智能化规划设计方案

热门文章

  1. 美多商城之订单(我的订单)
  2. 两个数组的交集 II
  3. idea软件,如何不每次弹出“欢迎界面!”
  4. 技术04期:关于神经网络的概念及技术领域
  5. 深度学习中的噪声数据
  6. 机器学习模型调参指南(附代码)
  7. 第二篇:时间和全局状态(二)
  8. Android Studio编写运行测试纯java代码可带main()函数
  9. 想要去阿里面试?你必须得跨过 JVM 这道坎!
  10. C程序演示产生僵死进程的过程