任務
設計服務端與客戶端程序,從服務端輸入要傳送的文件路徑,將文件傳送給客戶端,客戶端接收文件並保存到指定位置。
服務端
#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;
}