实验要求:使服务器与多个客户端进行通信,同时接收多个客户端上传的文件。
服务端代码:
#include"iostream"
#include"afxmt.h"
#include"process.h"
#include"winsock2.h"
#include"fstream"
#include"WS2tcpip.h"
#include"direct.h"
#define PORT 65432
#pragma comment(lib,"ws2_32.lib")
using namespace std;
struct fileMessage
{
char fileName[256];
long int fileSize;
};
/*主程序和线程函数共用的全局变量定义*/
char fname[128] = { 0 }; //发送给客户端的无路径信息的文件名
ifstream inFile; //定义文件的输入流
CMutex Section; //创建互斥对象
void rdFile(void* par); //发送文件的线程函数声明
/*主函数*/
int main()
{
SOCKET sock_server; //定义监听套接字
struct sockaddr_in addr;
struct sockaddr_in client_addr; //存放本地地址和客户地址的变量
SOCKET newsock; //储存accept()返回的套接字描述符
/*初始化winsock DLL*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout << "加载winSock动态链接库失败!\n";
return 0;
}
/*创建监听套接字*/
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "创建套接字失败!\n";
WSACleanup();
return 0;
}
/*绑定IP地址与端口*/
memset((void*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(65432);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_server, (struct sockaddr*)&addr, sizeof(addr)) != 0)
{
cout << "绑定失败!\n";
closesocket(sock_server);
WSACleanup();
return 0;
}
if (listen(sock_server, 5) != 0)
{
cout << "listen函数调用失败!\n";
closesocket(sock_server);
WSACleanup();
return 0;
}
else
{
cout << "listenning.....\n";
}
/*接收客户连接请求*/
int addr_len = sizeof(struct sockaddr_in);
while (true)
{
newsock = accept(sock_server, (LPSOCKADDR)&client_addr, &addr_len);
if (newsock != INVALID_SOCKET)
{
cout << "一个客户连接成功!" << endl;
_beginthread(rdFile, 0, (LPVOID)newsock);
}
else
{
break;
}
}
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
void rdFile(void* par)
{
/*定义文件传输所需变量*/
struct fileMessage fileMsg;
SOCKET sock = (SOCKET)par;
long int filelen;
char filename[500] = "C:\\Users\\86152\\source\\repos\\textfile"; //指定文件的保存目录
char ok[3] = "OK";
char fileBuffer[1000]; //接收文件数据的缓冲区
_mkdir(filename); //_mkdir()用于创建文件夹,其声明包含在direct.h中
/*接收文件名及文件长度信息*/
if ((filelen = recv(sock, (char*)&fileMsg, sizeof(fileMsg), 0)) <= 0)
{
cout << "未接收到文件名及文件长度!\n";
closesocket(sock);
WSACleanup();
return;
}
filelen = ntohl(fileMsg.fileSize);
strcat_s(filename, fileMsg.fileName);
ofstream outFile(filename, ios::out | ios::binary); //创建文件对象
if (!outFile.is_open())
{
cout << "Cannot open" << filename << endl;
closesocket(sock);
WSACleanup();
return; //文件打开失败则退出
}
send(sock, ok, sizeof(ok), 0); //发送接收文件数据的确认信息
int size = 0;
do
{
size = recv(sock, fileBuffer, sizeof(fileBuffer), 0);
if (size <= 0)break;
outFile.write(fileBuffer, size);
filelen -= size;
} while (filelen > 0);
if (filelen == 0)
{
cout << "Transfer finished!\n";
}
else
{
cout << "Transfer Failed!\n";
}
outFile.close();
closesocket(sock);
}
客户端代码:
#include<iostream>
#include"fstream"
#include"winsock2.h"
#include"WS2tcpip.h"
#include"direct.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
struct fileMessage //定义存储文件信息的结构体
{
char fileName[256];
long int fileSize;
};
int main()
{
/*定义网络连接的相关变量*/
int sock_client; //定义套接字
struct sockaddr_in server_addr; //用于存放服务器地址的变量
int addr_len = sizeof(struct sockaddr_in); //地址长度
/*初始化winsock DLL*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
cout << "加载winsock动态链接库失败!\n";
return 0;
}
char filename[500]; //用于存储要传输的文件的文件路径
cout << "输入要输入的文件路径:";
cin.getline(filename, 500);
/*创建套接字*/
if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "创建套接字失败!\n";
WSACleanup();
return 0;
}
/*输入服务器IP地址及端口号*/
char IP[20];
// unsigned short port;
in_addr a;
cout << "请输入服务器IP地址:";
cin >> IP;
inet_pton(AF_INET, IP, &a);
memset((void*)&server_addr, 0, addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(65432);
server_addr.sin_addr.s_addr = a.S_un.S_addr;
if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0)
{
cout << "连接失败!\n";
closesocket(sock_client);
WSACleanup();
return 0;
}
char OK[3], fileBuffer[1000]; //定义接收“OK”的缓冲区和发送缓冲区
struct fileMessage fileMsg; //定义保存文件名及文件长度的结构变量
ifstream inFile(filename, ios::in | ios::binary); //定义文件对象并打开文件
if (!inFile.is_open())
{
cout << "CAnnot open" << filename << endl;
closesocket(sock_client);
WSACleanup();
return 0; //文件打开失败则退出
}
/*从文件路径中提取文件名保存到结构变量fileMsg中*/
unsigned int size = strlen(filename);
while (filename[size] != '\\' && size > 0)size--;
strcpy_s(fileMsg.fileName, filename + size);
/*获取文件长度并存入结构变量fileMsg中*/
inFile.seekg(0, ios::end); //将文件的位置指针移到文件末尾
size = inFile.tellg(); //获取当前文件位置指针值
fileMsg.fileSize = htonl(size); //将文件长度存入结构变量fileMeg
send(sock_client, (char*)&fileMsg, sizeof(fileMsg), 0);//发送fileMeg
if (recv(sock_client, OK, sizeof(OK), 0) <= 0) //接收对方发来的OK信息
{
cout << "接收OK失败,程序退出!\n";
closesocket(sock_client);
WSACleanup();
return 0;
}
if (strcmp(OK, "OK") == 0) //如果对方已准备好接收则发送文件内容
{
inFile.seekg(0, ios::beg); //将文件的位置指针返回到文件头
while (!inFile.eof())
{
inFile.read(fileBuffer, sizeof(fileBuffer));
size = inFile.gcount(); //读取实际读取的字节数
send(sock_client, fileBuffer, size, 0);
}
cout << "File Transfer Finished!\n";
inFile.close(); //关闭文件
}
else
{
cout << "对方无法接收文件!";
}
closesocket(sock_client);
WSACleanup();
return 0;
}
实现效果:
实验要求:服务器同时向多个客户端发送文件
#include<iostream>
#include"fstream"
#include"winsock2.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
struct fileMessage //定义存储文件信息的结构体
{
char fileName[256];
long int fileSize;
};
int main()
{
SOCKET sock_server; //定义监听套接字
struct sockaddr_in addr;
struct sockaddr_in client_addr; //存放本地地址和客户地址的变量
SOCKET newsock; //储存accept()返回的套接字描述符
/*初始化winsock DLL*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
cout << "加载winSock动态链接库失败!\n";
return 0;
}
char filename[500]; //用于存储要传输的文件的文件路径
cout << "输入要输入的文件路径:";
cin.getline(filename, 500);
/*创建监听套接字*/
if ((sock_server=socket(AF_INET,SOCK_STREAM,0))<0)
{
cout << "创建套接字失败!\n";
WSACleanup();
return 0;
}
/*绑定IP地址与端口*/
memset((void*)&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(65432);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_server,(struct sockaddr*)&addr,sizeof(addr))!=0)
{
cout << "绑定失败!\n";
closesocket(sock_server);
WSACleanup();
return 0;
}
if (listen(sock_server,5)!=0)
{
cout << "listen函数调用失败!\n";
closesocket(sock_server);
WSACleanup();
return 0;
}
else
{
cout << "listenning.....\n";
}
/*接收客户连接请求*/
int addr_len = sizeof(struct sockaddr_in);
if ((newsock=accept(sock_server,(struct sockaddr*)&client_addr,&addr_len))==INVALID_SOCKET)
{
cout << "accept函数调用失败!\n";
closesocket(sock_server);
WSACleanup();
return 0;
}
cout << "客户连接成功!" << endl;
char OK[3], fileBuffer[1000]; //定义接收“OK”的缓冲区和发送缓冲区
struct fileMessage fileMsg; //定义保存文件名及文件长度的结构变量
ifstream inFile(filename, ios::in | ios::binary); //定义文件对象并打开文件
if (!inFile.is_open())
{
cout << "CAnnot open" << filename << endl;
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0; //文件打开失败则退出
}
/*从文件路径中提取文件名保存到结构变量fileMsg中*/
unsigned int size = strlen(filename);
while (filename[size] !='\\' && size> 0)size--;
strcpy_s(fileMsg.fileName, filename + size);
/*获取文件长度并存入结构变量fileMsg中*/
inFile.seekg(0, ios::end); //将文件的位置指针移到文件末尾
size = inFile.tellg(); //获取当前文件位置指针值
fileMsg.fileSize = htonl(size); //将文件长度存入结构变量fileMeg
send(newsock, (char*)&fileMsg, sizeof(fileMsg), 0);//发送fileMeg
if (recv(newsock,OK,sizeof(OK),0)<=0) //接收对方发来的OK信息
{
cout << "接收OK失败,程序退出!\n";
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
if (strcmp(OK,"OK")==0) //如果对方已准备好接收则发送文件内容
{
inFile.seekg(0, ios::beg); //将文件的位置指针返回到文件头
while (!inFile.eof())
{
inFile.read(fileBuffer, sizeof(fileBuffer));
size = inFile.gcount(); //读取实际读取的字节数
send(newsock, fileBuffer, size, 0);
}
cout << "File Transfer Finished!\n";
inFile.close(); //关闭文件
}
else
{
cout << "对方无法接收文件!";
}
closesocket(newsock);
closesocket(sock_server);
WSACleanup();
return 0;
}
客户端代码:
#include<iostream>
#include"fstream"
#include"winsock2.h"
#include"WS2tcpip.h"
#include"direct.h"
#pragma comment(lib,"ws2_32.lib")
using namespace std;
struct fileMessage
{
char fileName[256];
long int fileSize;
};
int main()
{
/*定义网络连接的相关变量*/
int sock_client; //定义套接字
struct sockaddr_in server_addr; //用于存放服务器地址的变量
int addr_len = sizeof(struct sockaddr_in); //地址长度
/*初始化winsock DLL*/
WSADATA wsaData;
if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
{
cout << "加载winsock动态链接库失败!\n";
return 0;
}
/*创建套接字*/
if ((sock_client=socket(AF_INET,SOCK_STREAM,0))<0)
{
cout << "创建套接字失败!\n";
WSACleanup();
return 0;
}
/*输入服务器IP地址及端口号*/
char IP[20];
// unsigned short port;
in_addr a;
cout << "请输入服务器IP地址:";
cin >> IP;
inet_pton(AF_INET, IP, &a);
memset((void*)&server_addr, 0, addr_len);
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(65432);
server_addr.sin_addr.s_addr = a.S_un.S_addr;
if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0)
{
cout << "连接失败!\n";
closesocket(sock_client);
WSACleanup();
return 0;
}
/*定义文件传输所需变量*/
struct fileMessage fileMsg;
long int filelen;
char filename[500] = "D:\\BaiduNetdiskDownload\\visualstudio\\vsfile\\transferfileclient"; //指定文件的保存目录
char ok[3] = "OK";
char fileBuffer[1000]; //接收文件数据的缓冲区
_mkdir(filename); //_mkdir()用于创建文件夹,其声明包含在direct.h中
/*接收文件名及文件长度信息*/
if ((filelen=recv(sock_client,(char*)&fileMsg,sizeof(fileMsg),0))<=0)
{
cout << "未接收到文件名及文件长度!\n";
closesocket(sock_client);
WSACleanup();
return 0;
}
filelen = ntohl(fileMsg.fileSize);
strcat_s(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; //文件打开失败则退出
}
send(sock_client, ok, sizeof(ok), 0); //发送接收文件数据的确认信息
int size = 0;
do
{
size = recv(sock_client, fileBuffer, sizeof(fileBuffer), 0);
if (size <= 0)break;
outFile.write(fileBuffer, size);
filelen -= size;
} while (filelen>0);
if (filelen==0)
{
cout << "Transfer finished!\n";
}
else
{
cout << "Transfer Failed!\n";
}
outFile.close();
closesocket(sock_client);
WSACleanup();
return 0;
}