任务
设计服务端与客户端程序,从服务端输入要传送的文件路径,将文件传送给客户端,客户端接收文件并保存到指定位置。
服务端
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include "WinSock2.h"
#include "iostream"
#include "fstream"
#include "string.h"
#pragma comment(lib,"ws2_32.lib") //链接WinSock导入库
#define PORT 65432
using namespace std;
struct fileMessage {
char fileName[256];
long int fileSize;
};
struct ArckMessage {
char ok[3];
unsigned long fileOffset;
};
int main(int argc, char **argv) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2); //调用2.2版本
if (WSAStartup(wVersionRequested, &wsaData) != 0) { //加载WinSock动态链接库
cout << "加载WinSock DLL失败!\n";
return 0;
}
SOCKET sock_server, newsock; //监听套接字,已连接套接字
struct sockaddr_in addr; //填写绑定地址
struct sockaddr_in client_addr; //接收客户端发来的信息
char msgbuffer[256];
char msg[] = "Connect succeed.\n"; //发给客户端的信息
//创建套接字
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
//填写要绑定的地址
int addr_len = sizeof(struct sockaddr_in);
memset((void*)&addr, 0, addr_len);
addr.sin_family = AF_INET;
addr.sin_port = htons(PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY); //允许本机的任何IP地址
//给监听套接字绑定地址
if (bind(sock_server, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
//将套接字设为监听状态
if (listen(sock_server, 5) != 0) { //最多有5个连接请求在等待队列中
cout << "listen函数调用失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
else {
cout << "listenning......\n";
}
//接收连接请求
if ((newsock = accept(sock_server, (struct sockaddr *)&client_addr, &addr_len)) == INVALID_SOCKET) {
cout << "accept函数调用失败!错误代码:" << WSAGetLastError() << endl;
closesocket(sock_server);
WSACleanup();
return 0;
}
cout << "connect from " << inet_ntoa(client_addr.sin_addr) << endl;
//定义文件传输所需变量
char filename[500];
cout << "输入要传输的文件路径:";
cin.getline(filename, 500);
char filebuffer[1000];
struct fileMessage fileMsg;
struct ArckMessage arkMsg;
//从文件路径提取文件名,保存到变量filemsg中
int size=strlen(filename);
while (filename[size] != '\\'&&size > 0) {
size--;
}
strcpy(fileMsg.fileName, filename + size);
//打开要传输的文件
ifstream inFile(filename, ios::in | ios::binary);
if (!inFile.is_open()) {
cout << "Cannot open " << filename << endl;
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
//获取文件长度
inFile.seekg(0, ios::end); //将文件的位置指针移到文件末尾
size = inFile.tellg(); //获取当前文件位置指针值,
inFile.seekg(0, ios::beg); //将文件的位置指针返回到文件头
//发送文件名
fileMsg.fileSize = htonl(size); //将文件长度存入filemsg
send(newsock, (char *)&fileMsg, sizeof(fileMsg), 0); //发送filemsg
if (recv(newsock, (char *)&arkMsg, sizeof(arkMsg), 0) <= 0) {
cout << "接收失败\n";
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
int pos = ntohl(arkMsg.fileOffset);
inFile.seekg(0, ios::beg); //将文件的位置指针移动到接收端请求位置
//发送文件内容
if (strcmp(arkMsg.ok, "ok") == 0) {
while (!inFile.eof()) {
inFile.read(filebuffer, sizeof(filebuffer));
size = inFile.gcount(); //获取实际读取的字节数
send(newsock, filebuffer, size, 0);
}
cout << "file transfer completed";
inFile.close();
}
else
cout << "无法接收文件!\n";
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
客户端
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include "WinSock2.h"
#include "iostream"
#include "fstream"
#include "string.h"
#include "direct.h"
#pragma comment(lib,"ws2_32.lib") //链接WinSock导入库
#define PORT 65432
using namespace std;
struct fileMessage {
char fileName[256];
long int fileSize;
};
struct ArckMessage {
char ok[3];
unsigned long fileOffset;
};
int main(int argc, char **argv) {
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2); //调用2.2版本
if (WSAStartup(wVersionRequested, &wsaData) != 0) { //加载WinSock动态链接库
cout << "加载WinSock DLL失败!\n";
return 0;
}
int sock_client;
struct sockaddr_in server_addr;
int addr_len = sizeof(struct sockaddr_in);
//创建套接字
if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
//连接服务器
memset((void *)&server_addr, 0, addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
if (connect(sock_client, (struct sockaddr *)&server_addr, addr_len) != 0) {
cout << "连接失败!错误代码:" << WSAGetLastError();
closesocket(sock_client);
WSACleanup();
return 0;
}
//定义文件传输所需变量
struct fileMessage fileMsg;
long int filelen;
char filename[500] = "D:\\download_test\\"; //指定接收到的文件的保存目录
struct ArckMessage arkMsg = { "ok",0 };
char fileBuffer[1000];
_mkdir(filename);
//接收文件名以及文件长度信息
if ((filelen = recv(sock_client, (char *)&fileMsg, sizeof(fileMsg), 0)) <= 0) {
cout << "未接收到文件名字以及长度!\n";
closesocket(sock_client);
WSACleanup();
return 0;
}
filelen = ntohl(fileMsg.fileSize);
strcat(filename, fileMsg.fileName);
//创建文件,准备接收文件内容
ofstream outFile(filename, ios::out | ios::binary);
if (!outFile.is_open()) {
cout << "Cannot open " << filename << endl;
closesocket(sock_client);
WSACleanup();
return 0;
}
//将文件写位置移动至文件末尾,获取其值并发送
outFile.seekp(0, ios::end);
arkMsg.fileOffset = ntohl(outFile.tellp());
send(sock_client, (char *)&arkMsg, sizeof(arkMsg), 0); //发送文件及文件位置
//接收文件数据并写入文件
int size = 0;
do {
size = recv(sock_client, fileBuffer, sizeof(fileBuffer), 0);
outFile.write(fileBuffer, size);
filelen -= size;
} while (size != 0 && filelen > 0);
cout << "Transfer completed!\n";
outFile.close();
closesocket(sock_client);
WSACleanup();
return 0;
}