简单的Socket文件传输

分别使用多线程和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, &parameter, 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;
}              

  • 9
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值