您的位置:首页 > 编程语言 > C语言/C++

windows环境下C++多线程文件传输

2017-04-30 17:32 555 查看
把上午写的传输字符串代码改了一下,本来是想实现客户端和服务器一对一多线程分块传输的,结果发现好像变成了一个服务器对多个客户端,每个客户端分配一条线程来处理文件传输任务的模式...

直接上代码,使用的是简单的fstream操作。

Sever代码:

#include "stdafx.h"
#include <WinSock2.h> //windows socket的头文件
#include <Windows.h>
#include <iostream>
#include <thread>
#include <mutex>
#include <process.h>
#include <fstream>
#include <string>

#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件

using namespace std;

mutex m;

//定义结构体用来设置
typedef struct my_file
{
SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信
sockaddr_in clientAddr; //用于保存客户端的socket地址
int id; //文件块的序号
}F;

DWORD WINAPI transmmit(const LPVOID arg)
{
//实际上这里也可以不加锁,上锁是为了方便看输出
m.lock();

F *temp = (F*)arg;
//获取文件的序号
//int file_id = temp->id;
//获取客户机的端口号
//ntohs(temp -> clientAddr.sin_port);
cout << "测试开始,等待客户端发送消息..." << endl;
//从客户端处接受数据
/*
char Buffer[MAXBYTE] = { 0 }; //缓冲区
recv(temp->clientSocket, Buffer, MAXBYTE, 0); //recv方法 从客户端通过clientScocket接收
cout << "线程" << temp->id << "从客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口收到:" << Buffer << endl;
*/
char file_name[100] = { 0 }; //文件路径
cout << "输入传输文件路径: ";
cin >> file_name;
FILE *fp = fopen(file_name, "rb"); //将文件按二进制读取
if (fp == NULL)
{
cout << "文件" << file_name << "出错或不存在" << endl;
}
else
{
char Buffer[MAXBYTE] = { 0 }; //文件缓冲区
int size = 0; //读取的文件长度
//每次读取完之后清空缓存区,以便下一块文件读入
while ((size = fread(Buffer, sizeof(char), MAXBYTE, fp)) > 0)
{
//返回非0值表示send错误
if (send(temp->clientSocket, Buffer, size, NULL) < 0)
{
cout << "传输出错,请检查网络配置。" << endl;
}
memset(&Buffer, 0, MAXBYTE);
}
cout << temp->id << "线程已成功发送" << file_name << endl;
fclose(fp);
}

/*
//发送简单的字符串到客户端
const char* s = "Server file";
send(temp->clientSocket, s, strlen(s)*sizeof(char)+1, NULL);
cout << "线程" << temp->id << "通过客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口发送:" << s << endl;
*/

m.unlock();

return 0;
}

int main()
{
WSADATA wsaData;
//第一个参数是winsocket load的版本号(2.2)
WSAStartup(MAKEWORD(2, 3), &wsaData);
//创建服务器端的socket(协议族, sokcet类型)
SOCKET servSocket = socket(AF_INET, SOCK_STREAM, 0);//如果改成SOCK_DGRAM则使用UDP
sockaddr_in servAddr; //服务器的socket地址,包含sin_addr表示IP地址,sin_port保持端口号和sin_zero填充字节
memset(&servAddr, 0, sizeof(SOCKADDR)); //初始化socket地址
servAddr.sin_family = PF_INET; //设置使用的协议族
servAddr.sin_port = htons(2017); //设置使用的端口
servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //define s_addr = S_un.S_addr
::bind(servSocket, (SOCKADDR *)&servAddr, sizeof(SOCKADDR)); //将之前创建的servSocket和端口,IP地址绑定

HANDLE hThread[2]; //获取句柄
listen(servSocket, 1); //监听服务器端口
for (int i = 0; i < 1; i++)
{
F *temp = new F; //创建新的传输结构体
sockaddr_in clntAddr;
int nSize = sizeof(SOCKADDR);
SOCKET clientSock = accept(servSocket, (SOCKADDR*)&clntAddr, &nSize);
//temp数据成员赋值
temp->clientSocket = clientSock;
temp->id = i + 1;
temp->clientAddr = clntAddr;
//通过句柄创建子线程
hThread[i] = CreateThread(NULL, 0, &transmmit, temp, 0, NULL);
}
//等待子线程完成
WaitForMultipleObjects(1, hThread, TRUE, INFINITE);
cout << "错误代码: " << WSAGetLastError() << endl;

//关闭socket,释放winsock
closesocket(servSocket);
WSACleanup();

cout << "服务器连接已关闭。" << endl;
system("pause");

return 0;
}


Client端代码:
#include "stdafx.h"
#include <WinSock2.h> //windows socket的头文件
#include <Windows.h>
#include <iostream>
#include <thread>
#include <process.h>

#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件

using namespace std;

int main()
{
//加载winsock库
WSADATA wsadata;
WSAStartup(MAKEWORD(2, 3), &wsadata);

//客户端socket
SOCKET clientSock = socket(PF_INET, SOCK_STREAM, 0);
//初始化socket信息
sockaddr_in clientAddr;
memset(&clientAddr, 0, sizeof(SOCKADDR));
//clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
clientAddr.sin_family = PF_INET;
clientAddr.sin_port = htons(2017);
//建立连接
connect(clientSock, (SOCKADDR*)&clientAddr, sizeof(SOCKADDR));

cout << "已建立连接。" << endl;

/*
char* s = new char[100];
cout << "请输入你要发送的文字消息: ";
cin >> s;
send(clientSock, s, strlen(s)*sizeof(char) + 1, NULL);
cout << "已发送:" << s << endl;
*/

char Buffer[MAXBYTE] = { 0 }; // 文件缓冲区
char wb_file[100] = { 0 }; //写入的文件

cout << "请输入想要写入的文件: ";
cin >> wb_file;

FILE *fp = fopen(wb_file, "wb");
if (fp == NULL)
{
cout << "操作文件时出错" << endl;
system("pause");
}
else
{
memset(&Buffer, 0, MAXBYTE);
int size = 0;
//当成功接收文件(size > 0)时,判断写入的时候文件长度是否等于接收的长度
while ((size = recv(clientSock, Buffer, MAXBYTE, 0)) > 0)
{
if (fwrite(Buffer, sizeof(char), size, fp) < size)
{
cout << "写入出错,部分文件缺失。" << endl;
}
//清空缓存区以便下一次接收
memset(&Buffer, 0, MAXBYTE);
}
cout << "接收完成" << endl;
fclose(fp);
}

closesocket(clientSock);
WSACleanup();

cout << "客户端连接已关闭。" << endl;
system("pause");

return 0;
}


因为之前用了WaitForMultipleObjects,所以客户端即使已经接收完成,亦不会输出接收完成的信息,只有关闭服务器的时候才会输出...

接下来思考一下怎么实现大文件分块传输的问题吧_(:з)∠)_
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  C++ windows 多线程