🧼C, C++/네트워크

소켓 파일전송 프로그램 C++ #4

Mawile 2021. 1. 21.
728x90

 

개발환경 >> Visual Studio

언어 >> C++20

운영체제 >> Windows10

 


 

안녕하세요

어제 파일전송 #3을 만들고 할거없어서 그냥 바로 또 #4 만들었습니다 ㅋㅋ

#4는 어떤기능을 추가했냐면, 파일을 이제 다중으로 동시에 여러파일을 받아올 수 있게 설계했습니다.

 

그럼 시작하겠습니다!

( 하단에 다운로드링크로 배포중인 배포파일내에 소스파일과 블로그에서 소스파일은 일부 다릅니다.

이유는 블로그 포스팅하면서 좀 수정함 ㅋㅋ. 그래서 다시 압축하고 재배포하기 귀찮아서 ㅋㅋ )

 


{[ 추천강좌 ]}

mawile.tistory.com/100

 

다중 스트림서버 C++ TCP #1

개발환경 >> Visual Studio 언어 >> C++17 운영체제 >> Windows10 안녕하세요... 오랜만입니다..! 이번에 시험이 끝나고 쓰는 정식적인 첫 강좌 글이네요. 이번에는 예전부터 쓴다고 예고했던 소켓 다중 스

mawile.tistory.com

mawile.tistory.com/124

 

소켓 파일전송 C++ #3

개발환경 >> Visual Studio 언어 >> C++20 운영체제 >> Windows10 안녕하세요!!! 이번에는 엄청난 파일전송속도와 안정성을 가지고 왔습니다. 나중에는 이것보다 더 체계적으로 설계해서 속도와 안정성을

mawile.tistory.com

 


{[ 다운로드 ]}

다운로드

 

MultiFileTransfer.zip

 

drive.google.com

 

 

 

 

 


{[ 서버 ]}

#include "Sheader.h"

void FileTransfer(SOCKET client, const char* filepath, const char* filename) {
	FILE* fp = 0;
	std::string str;
	char buffer[PKT] = { 0 },
		FileR[FILEMAX] = { 0 },
		name[PKT] = { 0 };

	send(client, filepath, PKT, 0);
	recv(client, buffer, PKT, 0);
	fopen_s(&fp, filename, "wb");

	int filesize = atoi(buffer);

	while (true) {
		ZeroMemory(FileR, FILEMAX);
		ZeroMemory(buffer, PKT);

		recv(client, buffer, PKT, 0);
		recv(client, FileR, atoi(buffer), 0);
		fwrite(FileR, sizeof(char), atoi(buffer), fp);

		std::cout << "received " << buffer << " bytes." << std::endl;

		filesize -= atoi(buffer);
		if (filesize <= 0) break;
	}
	std::cout << "Input a command (send_data , add_stream): ";
	fclose(fp);
}

SOCKET recvClient() {
	WSADATA wsa;
	SOCKET server, client;
	SOCKADDR_IN addr = { 0 }, clientaddr = { 0 };
	int clientsize;

	WSAStartup(MAKEWORD(2, 2), &wsa);

	server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	addr.sin_port = htons(MasterPort);
	addr.sin_family = AF_INET;

	bind(server, (SOCKADDR*)&addr, sizeof(addr));
	listen(server, SOMAXCONN);

	std::cout << "MasterClient connecting..." << std::endl;

	clientsize = sizeof(clientaddr);
	client = accept(server, (SOCKADDR*)&clientaddr, &clientsize);

	std::cout << "MasterClient connected !" << std::endl;
	std::cout << "Input a command (send_data , add_stream): ";
	return client;
}

int main() {
	SOCKET client = recvClient();

	std::string str;
	char filename[PKT],
		command[PKT];
	int num;

	while (true) {
		str.clear();
		ZeroMemory(command, PKT);
		ZeroMemory(filename, PKT);

		std::cin >> command;

		if (!strcmp(command, "add_stream")) std::thread([&]() {
				streams.push_back(stream(client, BasePort + clientcnt));
				std::cout << "Created a stream number " << clientcnt << std::endl;
				clientcnt += 1;
				std::cout << "Input a command (send_data , add_stream): ";
			} ).detach();
		else if (!strcmp(command, "send_data")) {
			std::cout << "Input a stream number: ";
			std::cin >> num;

			if (num > clientcnt - 1) continue;

			send(client, "sends", PKT, 0);

			ZeroMemory(command, PKT);
			_itoa_s(num, command, 10);
			send(client, command, PKT, 0);

			std::cout << "Input a filepath on client: ";
			std::cin.ignore();
			std::getline(std::cin, str);

			std::cout << "Input a filename on server: ";
			std::cin >> filename;

			pdd.push_back(Pdata(str.c_str(), filename));
			pddcnt += 1;
			std::thread(FileTransfer, streams[num].GetClient(), pdd[pddcnt-1].filepath, pdd[pddcnt-1].filename).detach();
		}
	}
}

 

{[ 서버 헤더파일 ]}

/*
* RECEIVER
*/

#pragma once
#pragma comment(lib, "ws2_32.lib")

#define PKT 1024
#define FILEMAX 100000

#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <string>
#include <vector>
#include <thread>

const int MasterPort = 4321;
int BasePort = 8080, clientcnt = 0, pddcnt = 0;

class stream {
private:
	WSADATA wsa;
	SOCKET server, client;
	SOCKADDR_IN addr = { 0 }, clientaddr = { 0 };
	int clientsize;

public:
	stream() { }
	stream(SOCKET s, int port) {
		if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return;

		server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (server == INVALID_SOCKET) return;

		addr.sin_addr.s_addr = htonl(INADDR_ANY);
		addr.sin_port = htons(port);
		addr.sin_family = AF_INET;

		if (bind(server, (SOCKADDR*)&addr, sizeof(addr)) == SOCKET_ERROR) return;
		if (listen(server, SOMAXCONN) == SOCKET_ERROR) return;

		send(s, "adds", PKT, 0);

		std::cout << "Listening from client... " << port - BasePort << std::endl;

		clientsize = sizeof(clientaddr);
		client = accept(server, (SOCKADDR*)&clientaddr, &clientsize);
		if (client == INVALID_SOCKET) return;

		std::cout << "Joined a client number " << port - BasePort << std::endl;
	}
	SOCKET& GetClient() { return this->client; }
}; std::vector<stream>streams;

typedef struct __data_T {
	char filepath[PKT] = { 0 },
		filename[PKT] = { 0 };
	int number;
	__data_T() { }
	__data_T(const char* f1, const char* f2) {
		strcpy_s(filepath, f1);
		strcpy_s(filename, f2);
	}
}Pdata; std::vector<Pdata>pdd;

 

{[ 클라이언트 ]}

#include "Cheader.h"

void FileTransfer(SOCKET server) {
	FILE* fp = 0;
	char buffer[PKT],
		FileR[FILEMAX];
	int filesize, recvdsize;

	ZeroMemory(buffer, PKT);
	recv(server, buffer, PKT, 0);

	std::cout << "received filepath => " << buffer << std::endl;

	fopen_s(&fp, buffer, "rb");

	fseek(fp, 0, SEEK_END);
	filesize = ftell(fp);
	fseek(fp, 0, SEEK_SET);

	std::cout << "received filesize => " << filesize << std::endl;

	ZeroMemory(buffer, PKT);
	sprintf_s(buffer, "%d", filesize);
	send(server, buffer, PKT, 0);

	while (true) {
		ZeroMemory(buffer, PKT);
		ZeroMemory(FileR, FILEMAX);

		recvdsize = fread(FileR, sizeof(char), FILEMAX, fp);
		_itoa_s(recvdsize, buffer, 10);
		send(server, buffer, PKT, 0);
		send(server, FileR, recvdsize, 0);

		std::cout << "sending " << recvdsize << " bytes." << std::endl;

		filesize -= recvdsize;
		if (filesize <= 0) break;
	}

	fclose(fp);
}

void addStreams(SOCKET client) {
	char buffer[PKT],
		num[PKT];
	while (true) {
		ZeroMemory(buffer, PKT);
		recv(client, buffer, PKT, 0);

		if (!strcmp(buffer, "adds")) {
			streams.push_back(stream(BasePort + clientcnt));
			std::cout << "Created a stream number " << clientcnt << std::endl;
			clientcnt += 1;
		}

		else if (!strcmp(buffer, "sends")) {
			ZeroMemory(num, PKT);
			recv(client, num, PKT, 0);
			std::thread(FileTransfer, streams[atoi(num)].GetServer()).detach();
		}
	}
}

SOCKET Master() {
    std::cout << "Input the server ip address: ";
	std::cin >> IP;
    
	WSADATA wsa;
	SOCKET server;
	SOCKADDR_IN addr = { 0 };

	WSAStartup(MAKEWORD(2, 2), &wsa);

	server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	addr.sin_addr.s_addr = inet_addr(IP);
	addr.sin_port = htons(MasterPort);
	addr.sin_family = AF_INET;

	std::cout << "Connecting to MasterServer..." << std::endl;

	while (connect(server, (SOCKADDR*)&addr, sizeof(addr)));

	std::cout << "Connected to MasterServer !" << std::endl;
	return server;
}

int main() {
	SOCKET server = Master();

	std::thread(addStreams, server).detach();
	while (true);

	closesocket(server);
	WSACleanup();
}

 

{[ 클라이언트 헤더파일 ]}

 

/*
* SENDER
*/

#pragma once
#pragma comment(lib, "ws2_32.lib")

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define PKT 1024
#define FILEMAX 100000

#include <winsock2.h>
#include <windows.h>
#include <iostream>
#include <vector>
#include <thread>

char IP[PKT] = { 0 };
const int MasterPort = 4321;
int BasePort = 8080, clientcnt = 0;

void t(const char* chr) {
	std::cout << chr << std::endl;
}

class stream {
private:
	WSADATA wsa;
	SOCKET server;
	SOCKADDR_IN addr = { 0 };

public:
	stream() { }
	stream(int port) {
		if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return;

		server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (server == INVALID_SOCKET) return;

		addr.sin_addr.s_addr = inet_addr(IP);
		addr.sin_port = htons(port);
		addr.sin_family = AF_INET;

		std::cout << "Connecting to server... " << port - BasePort << std::endl;

		while (connect(server, (SOCKADDR*)&addr, sizeof(addr)));

		std::cout << "Connected to server ! " << port - BasePort << std::endl;
	}
	SOCKET& GetServer() { return this->server; }
}; std::vector<stream>streams;

 

 

 


{[ 시연영상 ]}

 

 

궁금한 부분있으면 댓글로 질문 주세요 ㅠㅠ!!

그럼 봐주셔서 감사합니다~!

 


728x90

댓글