分别使用多线程和Select模型,留档等工作了再回头看看。写得又乱又差...但就目前而言能写出来就算成功。
多线程:
#define PORT 2023
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define filepath "F:\\Codes\\Cpp\\Files\\server\\"
#include <WinSock2.h>
#include <iostream>
#include <string>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
DWORD ThreadFunc(LPVOID lpParameter);
struct Parameters
{
SOCKET sock_server;
SOCKET sock_client;
sockaddr_in addr_client;
}; // 自定义结构体用于向线程内传参
char msgbuffer[1000] = {};
char filebuffer[2048] = {};
char checkmsg[] = "20210806xxxxxxxx";
int cnt_client = 0;
int main()
{
SOCKET sock_server;
SOCKET sock_client;
struct sockaddr_in addr_server;
struct sockaddr_in addr_client;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)
{
cout << "初始化winsock.dll失败!" << endl;
return -1;
}
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
{
cout << "创建套接字失败!" << endl;
WSACleanup();
return -1;
}
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(PORT);
addr_server.sin_addr.s_addr = INADDR_ANY;
int addr_len = sizeof(addr_server);
if (bind(sock_server, (struct sockaddr*)&addr_server, sizeof(addr_server)) != 0)
{
cout << "地址绑定失败!" << endl;
closesocket(sock_server);
WSACleanup();
return -1;
}
listen(sock_server, 5);
cout << "监听中..." << endl;
while (true)
{
if ((sock_client = accept(sock_server, (struct sockaddr*)&addr_client, &addr_len)) == INVALID_SOCKET)
{
cout << "连接失败!" << endl;
closesocket(sock_client);
WSACleanup();
return -1;
}
Parameters parameter;
parameter.sock_server = sock_server;
parameter.sock_client = sock_client;
parameter.addr_client = addr_client;
CreateThread(NULL, 0, ThreadFunc, ¶meter, 0, NULL);
}
closesocket(sock_server);
closesocket(sock_client);
WSACleanup();
return 0;
}
DWORD ThreadFunc(LPVOID lpParameter)
{
Parameters *pm = (Parameters*) lpParameter;
SOCKET sock_server = pm->sock_server;
SOCKET sock_client = pm->sock_client;
sockaddr_in addr_client = pm->addr_client;
int size;
char op[10];
char* result = NULL;
char* start = NULL;
string file_part[10] = {};
while (true)
{
size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0);
if (strcmp(msgbuffer, checkmsg) == 0)
{
size = send(sock_client, "1145141919810", strlen("1145141919810"), 0);
break;
}
else
{
size = send(sock_client, "密码不正确!", strlen("密码不正确!"), 0);
}
}
cout << endl << "客户端[线程:" << GetCurrentThreadId() << "]已连接" << endl;
while (true)
{
size = recv(sock_client, msgbuffer, sizeof(msgbuffer), 0);
strncpy(op, msgbuffer, 3); // 截取指令部分
op[3] = '\0'; // 手动添加结束符
int tmp = 0;
while (result != NULL)
{
file_part[tmp] = result;
tmp++;
}
if (strcmp("quit", msgbuffer) == 0)
{
cout << endl << "客户端[线程:" << GetCurrentThreadId() << "]主动断开!" << endl;
break;
}
else if (strcmp("get", op) == 0)
{
result = strtok_s(msgbuffer, " ", &start);
result = strtok_s(NULL, " ", &start);
file_part[1] = result;
string FileName(file_part[1]);
string FilePath(filepath);
FilePath.append(FileName);
cout << endl << "客户端[线程:" << GetCurrentThreadId() << "]请求下载文件[" << file_part[1] << "]" << endl;
FILE* fp = fopen(FilePath.c_str(), "rb"); // 以二进制方式打开文件
if (fp == NULL)
{
cout << "客户端请求的文件不存在!" << endl;
size = send(sock_client, "客户端请求的文件不存在!", strlen("客户端请求的文件不存在!"), 0);
break;
}
else
{
cout << "正在传输..." << endl;
while ((size = fread(filebuffer, 1, sizeof(filebuffer), fp)) > 0)
{
send(sock_client, filebuffer, size, 0);
}
shutdown(sock_client, SD_SEND); // 关闭输出流
fclose(fp);
cout << endl << "文件传输完毕!" << endl;
}
}
else if (strcmp("put", op) == 0)
{
result = strtok_s(msgbuffer, " ", &start);
result = strtok_s(NULL, " ", &start);
file_part[1] = result;
result = strtok_s(NULL, " ", &start);
file_part[2] = result;
int data = stoi(file_part[2]); // 文件大小转换为数字
int end_data = 0; // recv结束条件
string FileName(file_part[1]);
string FilePath(filepath);
FilePath.append(FileName);
cout << endl << "客户端[线程:" << GetCurrentThreadId() << "]请求上传文件[" << file_part[1] << "]"
<< ",文件大小为:" << file_part[2] << endl;
FILE* fp = fopen(FilePath.c_str(), "wb"); // 二进制方式打开或创建文件
while ((size = recv(sock_client, filebuffer, sizeof(filebuffer), 0)) > 0)
{
if (strcmp("客户端上传的文件不存在!", filebuffer) == 0)
{
cout << endl << "客户端无法上传该文件!" << endl;
break;
}
else
{
fwrite(filebuffer, size, 1, fp);
end_data += sizeof(filebuffer);
if (end_data > data)
break;
}
}
fclose(fp);
cout << endl << "文件上传完毕!" << endl;
}
}
return 0;
}
select模型:
#define PORT 2023
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define filepath "F:\\Codes\\Cpp\\Files\\server\\"
#include <WinSock2.h>
#include <iostream>
#include <string>
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int main()
{
SOCKET sock_server, sock_client;
struct sockaddr_in addr_server;
struct sockaddr_in addr_client;
int addr_len = sizeof(struct sockaddr_in);
char msgbuffer[1000] = {};
char checkmsg[] = "20210806xxxxxxx";
int client_cnt = 0;
int flag;
int index;
int index_ports = 0;
u_short ports[64] = {};
memset(ports, 0, sizeof(ports)); // 数组初始化
char op[10] = {};
char filename[1000] = {};
char filedata[1000] = {};
char filebuffer[2048] = {};
char filepathbuffer[2000] = {};
int record[100] = {};
fd_set fdsock;
fd_set fdread;
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)
{
cout << "加载winsock.dll失败!" << endl;
return -1;
}
if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "创建套接字失败!" << endl;
WSACleanup();
return -1;
}
addr_server.sin_family = AF_INET;
addr_server.sin_port = htons(PORT);
addr_server.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sock_server, (struct sockaddr*)&addr_server, sizeof(addr_server)) != 0)
{
cout << "地址绑定失败!" << endl;
closesocket(sock_server);
WSACleanup();
return -1;
}
if (listen(sock_server, 5) != 0)
{
cout << "listen函数调用失败!" << endl;
closesocket(sock_server);
WSACleanup();
return -1;
}
else
{
cout << "监听中..." << endl;
}
FD_ZERO(&fdsock);
FD_SET(sock_server, &fdsock);
while (true)
{
FD_ZERO(&fdread); // 每次循环都要初始化
fdread = fdsock;
memset(msgbuffer, '\0', sizeof(msgbuffer));
if (select(0, &fdread, NULL, NULL, NULL) > 0)
{
for (int i = 0; i < fdsock.fd_count; i++)
{
if (FD_ISSET(fdsock.fd_array[i], &fdread)) // 在fdread内的第i个套接字是否有响应
{
if (fdsock.fd_array[i] == sock_server) // 响应为请求连接
{
sock_client = accept(sock_server, (struct sockaddr*)&addr_client, &addr_len);
if (sock_client == INVALID_SOCKET)
{
cout << "accept函数调用失败!" << endl;
for (int j = 0; i < fdsock.fd_count; j++)
{
closesocket(fdsock.fd_array[j]); // accept函数调用错误后关闭所有连接
}
WSACleanup();
return -1;
}
else
{
if (fdsock.fd_count > FD_SETSIZE)
{
cout << endl << "客户端连接已达上限!" << endl;
}
else
{
cout << endl << "客户端连接成功!" << endl;
FD_SET(sock_client, &fdsock);
client_cnt++;
}
}
}
else
{
int size = 0;
getpeername(fdsock.fd_array[i], (struct sockaddr*)&addr_client, &addr_len);
flag = 1;
for (int j = 0; j < sizeof(ports) / 2; j++)
{
if (addr_client.sin_port == ports[j])
{
flag = 0;
break;
}
}
if (flag == 1) // 目前客户端端口未存储, 需要输入密码
{
size = recv(fdsock.fd_array[i], msgbuffer, sizeof(msgbuffer), 0);
if (strcmp(msgbuffer, checkmsg) != 0)
{
size = send(fdsock.fd_array[i], "密码不正确!", strlen("密码不正确!"), 0);
break;
}
else
{
size = send(fdsock.fd_array[i], "1145141919810", strlen("1145141919810"), 0);
}
}
if (size > 0 || flag == 0) // 不需要再次输入密码, flag==1的if语句跳过
{
getpeername(fdsock.fd_array[i], (struct sockaddr*)&addr_client, &addr_len);
flag = 1;
for (int j = 0; j < sizeof(ports) / 2; j++)
{
if (ports[j] == addr_client.sin_port) // 输入正确的密码后保存端口,防止下次select再次进行输入密码
{
index_ports++;
flag = 0;
break;
}
}
if (flag == 1)
{
ports[index_ports] = addr_client.sin_port;
}
size = recv(fdsock.fd_array[i], msgbuffer, sizeof(msgbuffer), 0);
if (strcmp(msgbuffer, "quit") == 0 || size <= 0)
{
getpeername(fdsock.fd_array[i], (struct sockaddr*)&addr_client, &addr_len);
cout << endl << "端口号为[" << addr_client.sin_port << "]的客户端已断开连接!" << endl;
for (int j = 0; j < sizeof(ports) / 2; j++)
{
if (ports[j] == addr_client.sin_port)
{
ports[j] = 0; // 对应端口断开后, 将该端口在数组内更改为0
break;
}
}
closesocket(fdsock.fd_array[i]);
FD_CLR(fdsock.fd_array[i], &fdsock);
client_cnt--;
cout << endl << "---------------------------";
cout << endl << "当前连接的客户端数: " << client_cnt << endl;
cout << "---------------------------" << endl;
}
memset(op, '\0', sizeof(op));
memset(filename, '\0', sizeof(filename));
memset(filedata, '\0', sizeof(filedata));
memset(record, 0, sizeof(record));
strncpy(op, msgbuffer, 3); // 截取指令部分
op[3] = '\0'; // strncpy不会自动添加\0, 需要手动添加
index = 0;
for (int j = 0; j < sizeof(msgbuffer); j++)
{
if (msgbuffer[j] == ' ')
{
record[index] = j; // 记录空格出现的位置
index++;
}
else if (msgbuffer[j] == '\0')
{
record[index] = j; // 记录字符数组末尾位置
index++;
}
if (record[2] > 0)
break;
}
index = 0;
for (int j = 4; j < record[1]; j++)
{
filename[index] = msgbuffer[j];
index++;
}
if (record[2] > 0)
{
index = 0;
for (int j = record[1] + 1; j <= record[2]; j++)
{
filedata[index] = msgbuffer[j];
index++;
}
}
if (strcmp(op, "get") == 0)
{
getpeername(fdsock.fd_array[i], (struct sockaddr*)&addr_client, &addr_len);
cout << endl << "客户端[" << addr_client.sin_port << "]请求下载文件[" << filename << "]" << endl;
string FileName(filename);
string FilePath(filepath);
FilePath.append(FileName);
strcpy(filepathbuffer, FilePath.c_str()); // 拼接出文件的绝对路径
FILE* fp = fopen(filepathbuffer, "rb"); // 以二进制方式打开文件
if (fp == NULL)
{
cout << "客户端请求的文件不存在!" << endl;
size = send(fdsock.fd_array[i], "客户端请求的文件不存在!", strlen("客户端请求的文件不存在!"), 0);
break;
}
else
{
cout << "正在传输..." << endl;
while ((size = fread(filebuffer, 1, sizeof(filebuffer), fp)) > 0)
{
send(fdsock.fd_array[i], filebuffer, size, 0);
}
shutdown(fdsock.fd_array[i], SD_SEND); // 关闭输出流
fclose(fp);
cout << endl << "文件传输完毕!" << endl;
}
}
else if (strcmp(op, "put") == 0)
{
int data = stoi(filedata); // 文件大小转换为数字
int end_data = 0; // recv结束条件
getpeername(fdsock.fd_array[i], (struct sockaddr*)&addr_client, &addr_len);
cout << endl << "客户端[" << addr_client.sin_port << "]请求上传文件[" << filename << "], 文件大小为" << filedata << endl;
string FileName(filename);
string FilePath(filepath);
FilePath.append(FileName);
strcpy(filepathbuffer, FilePath.c_str()); // 拼接出文件的绝对路径
FILE* fp = fopen(filepathbuffer, "wb"); // 二进制方式打开或创建文件
while ((size = recv(fdsock.fd_array[i], filebuffer, sizeof(filebuffer), 0)) > 0)
{
if (strcmp("客户端上传的文件不存在!", filebuffer) == 0)
{
cout << endl << "客户端无法上传该文件!" << endl;
break;
}
else
{
fwrite(filebuffer, size, 1, fp);
end_data += sizeof(filebuffer);
if (end_data > data)
break;
}
}
fclose(fp);
cout << endl << "文件上传完毕!" << endl;
}
}
else if (size <= 0)
{
getpeername(fdsock.fd_array[i], (struct sockaddr *)&addr_client, &addr_len);
cout << endl << "端口号为[" << addr_client.sin_port << "]的客户端已断开连接!" << endl;
closesocket(fdsock.fd_array[i]);
FD_CLR(fdsock.fd_array[i], &fdsock);
client_cnt--;
cout << endl << "---------------------------";
cout << endl << "当前连接的客户端数: " << client_cnt << endl;
cout << "---------------------------" << endl;
}
}
}
} // 遍历套接字的for语句的花括号
} // select语句的花括号
else
{
cout << "select函数调用失败!" << endl;
break; // 直接结束while循环
}
} // while循环的花括号
for (int i = 0; i < fdsock.fd_count; i++)
{
closesocket(fdsock.fd_array[i]);
}
WSACleanup();
return 0;
}
客户端:
#define PORT 2023
#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#define filepath "F:\\Codes\\Cpp\\Files\\client\\"
#include <string>
#include <io.h>
#include <iostream>
#include <winsock2.h>
#pragma comment(lib, "Ws2_32.lib")
using namespace std;
int main()
{
int sock_client; // 客户端套接字
int addr_len = sizeof(struct sockaddr_in);
struct sockaddr_in server_addr; // 存放服务器地址
char msgbuffer[1000] = {'\0'};
char filebuffer[2048] = {0};
char checkmsg[1000] = {'\0'};
char op[1000] = {'\0'};
char op_head[5] = {};
char filename[1000] = {};
char filedata[1000] = {};
char filepathbuffer[2000] = {};
int record[100] = {};
int index;
// 初始化winsock2.dll
WSADATA wsaData;
WORD wVersionRequested = MAKEWORD(2, 2);
if (WSAStartup(wVersionRequested, &wsaData) != 0)
{
cout << "初始化winsock失败!" << endl;
return 0;
}
// 创建套接字
if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
cout << "创建套接字失败!错误代码: " << WSAGetLastError() << endl;
WSACleanup();
return 0;
}
memset((void*)&server_addr, 0, addr_len); // 地址结构清0
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() << endl;
closesocket(sock_client);
WSACleanup();
return 0;
}
int size;
cout << "请输入学号和姓名, 例:[20210806xxxx张三]: " << endl;
while (cin >> msgbuffer)
{
size = send(sock_client, msgbuffer, sizeof(msgbuffer), 0); // 发送客户端输入的密码
size = recv(sock_client, checkmsg, sizeof(checkmsg), 0); // 接收服务器回复的验证
if (strcmp("密码不正确!", checkmsg) == 0)
{
cout << endl << "密码不正确!请重新输入: " << endl;
continue;
}
else
{
cout << endl << "密码正确!" << endl;
break;
}
}
// cout << endl << checkmsg << endl;
cin.ignore();
while (true)
{
cout << endl << "----------------------------------------" << endl;
cout << "1.下载文件, 指令:[get 文件名(带后缀名)]" << endl;
cout << "2.上传文件, 指令:[put 文件名(带后缀名) 文件长度]" << endl;
cout << "3.退出, 指令:[quit]" << endl;
cout << "----------------------------------------" << endl;
cout << "请输入指令: " << endl;
cin.getline(op, 1000);
strncpy(op_head, op, 3); // 截取命令部分
op_head[3] = '\0';
memset(filename, '\0', sizeof(filename));
memset(filedata, '\0', sizeof(filedata));
memset(record, 0, sizeof(record));
index = 0;
for (int j = 0; j < sizeof(op); j++)
{
if (op[j] == ' ')
{
record[index] = j; // 记录空格出现的位置
index++;
}
else if (op[j] == 0)
{
record[index] = j; // 记录字符数组末尾位置
index++;
}
if (record[2] > 0)
break;
}
index = 0;
for (int j = 4; j < record[1]; j++)
{
filename[index] = op[j];
index++;
}
if (record[2] > 0)
{
index = 0;
for (int j = record[1] + 1; j < record[2]; j++)
{
filedata[index] = op[j];
index++;
}
}
string FileName(filename);
string FilePath(filepath);
FilePath.append(FileName);
strcpy(filepathbuffer, FilePath.c_str()); // 拼接出文件的绝对路径
if (strcmp("quit", op) == 0)
{
size = send(sock_client, op, sizeof(op), 0);
cout << "客户端主动断开!" << endl;
break;
}
else if (strcmp(op_head, "get") == 0)
{
size = send(sock_client, op, sizeof(op), 0);
FILE* fp = fopen(filepathbuffer, "wb"); // 二进制方式打开或创建文件
while ((size = recv(sock_client, filebuffer, sizeof(filebuffer), 0)) > 0)
{
if (strcmp("客户端请求的文件不存在!", filebuffer) == 0)
{
cout << endl << "该文件不存在!" << endl;
break;
}
else
{
fwrite(filebuffer, size, 1, fp);
}
}
fclose(fp);
cout << endl << "文件下载完毕!" << endl;
}
else if (strcmp(op_head, "put") == 0)
{
size = send(sock_client, op, sizeof(op), 0);
FILE* fp = fopen(filepathbuffer, "rb"); // 以二进制方式打开文件
if (fp == NULL)
{
cout << "客户端上传的文件不存在!" << endl;
size = send(sock_client, "客户端上传的文件不存在!", strlen("客户端上传的文件不存在!"), 0);
break;
}
else
{
cout << endl << "正在上传..." << endl;
while ((size = fread(filebuffer, 1, sizeof(filebuffer), fp)) > 0)
{
send(sock_client, filebuffer, size, 0);
}
// shutdown(sock_client, SD_SEND); // 关闭输出流, 会发送一个FIN包给recv返回0
fclose(fp);
cout << endl << "文件上传完毕!" << endl;
}
}
}
closesocket(sock_client);
WSACleanup();
return 0;
}