공부

TCP 파일전송 프로그램

글로벌디노 2020. 10. 13. 17:07

TCP 파일전송 프로그램

 

 

서버정보 localhost(127.0.0.1):7000

송신할 파일정보

이름 Blackpink.jpg

파일크기 415,128 바이트

 

 

실행결과

서버

클라이언트

 

 

 

서버 코드

#include <stdio.h>
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")

#pragma pack(push, 1)
typedef struct st_PACKET_HEADER
{
	DWORD dwPacketCode;		// 0x11223344 우리의 패킷확인 고정값
	WCHAR szName[32];		// 본인이름, 유니코드 NULL 문자 끝
	WCHAR szFileName[128];	// 파일이름, 유니코드 NULL 문자 끝
	int iFileSize;
} PACKET_HEADER;
#pragma pack(pop)

int recvn(SOCKET socket, char* buf, int bufSize, int maxSize, int flag);

int main()
{
	WSADATA wsaData;
	int ret;

	ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (ret != 0)
	{
		wprintf_s(L"error WSAStartup() [%d]\n", ret);
		return 1;
	}

	SOCKET listenSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	if (listenSock == INVALID_SOCKET)
	{
		wprintf_s(L"error socket() [%d]\n", WSAGetLastError());
		return 1;
	}

	SOCKADDR_IN servAddr;
	ZeroMemory(&servAddr, sizeof(servAddr));
	servAddr.sin_family = AF_INET;
	servAddr.sin_port = htons(7000);
	servAddr.sin_addr.s_addr = htonl(INADDR_ANY);

	// bind
	if (bind(listenSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR)
	{
		wprintf_s(L"error bind() [%d]\n", WSAGetLastError());
		return 1;
	}

	// listen
	if (listen(listenSock, 5) == SOCKET_ERROR)
	{
		wprintf_s(L"error listen() [%d]\n", WSAGetLastError());
		return 1;
	}

	SOCKET clientSock;
	SOCKADDR_IN clientAddr;
	int addrLen = sizeof(clientAddr);

	while (1)
	{
		// accept
		wprintf_s(L"Accept Ready ...\n");

		clientSock = accept(listenSock, (SOCKADDR*)&clientAddr, &addrLen);
		if (clientSock == INVALID_SOCKET)
		{
			wprintf_s(L"error accept() [%d]\n", WSAGetLastError());
			continue;
		}

		do 
		{
			// 연결된 소켓정보 출력
			wchar_t ipBuf[16];
			InetNtopW(clientAddr.sin_family, &clientAddr.sin_addr.s_addr, ipBuf, 16);
			wprintf_s(L"Connected IP: %s, Port: %d\n", ipBuf, ntohs(clientAddr.sin_port));

			// 헤더 수신
			PACKET_HEADER packetHeader;
			ret = recvn(clientSock, (char*)&packetHeader, sizeof(packetHeader), sizeof(packetHeader), 0);
			if (ret == 0 || ret == SOCKET_ERROR)
			{
				wprintf_s(L"error recvn header [%d]\n", WSAGetLastError());
				break;
			}

			// 헤더의 패킷코드 확인
			if (packetHeader.dwPacketCode != 0x11223344)
			{
				wprintf_s(L"packet code not equal\n");
				break;
			}

			// 파일 이름 만들기
			WCHAR fileName[160];
			wsprintfW(fileName, L"%s_%s", packetHeader.szName, packetHeader.szFileName);

			// 수신할 데이터 크기만큼 메모리 할당 후 데이터 수신
			char* recvData = new char[packetHeader.iFileSize];
			ret = recvn(clientSock, recvData, 1000, packetHeader.iFileSize, 0);
			if (ret == 0 || ret == SOCKET_ERROR)
			{
				wprintf_s(L"error recvn() [%d]\n", WSAGetLastError());
				delete[] recvData;
				break;
			}

			// 수신한 데이터를 파일로 저장
			FILE* file;
			ret = _wfopen_s(&file, fileName, L"wb");
			if (ret != 0 || file == NULL)
			{
				wprintf_s(L"error _wfopen_s() [%d]\n", ret);
				delete[] recvData; 
				break;
			}

			fwrite(recvData, packetHeader.iFileSize, 1, file);

			fclose(file);
			delete[] recvData;

			// 데이터 수신 성공 메시지 송신
			int success = 0xdddddddd;
			if (send(clientSock, (char*)&success, sizeof(success), 0) == SOCKET_ERROR)
			{
				wprintf_s(L"error send() [%d]\n", WSAGetLastError());
				break;
			}

		} while (0);

		closesocket(clientSock);
	}

	closesocket(listenSock);
	WSACleanup();

	return 0;
}

int recvn(SOCKET socket, char* buf, int bufSize, int maxSize, int flag)
{
	int size = maxSize;
	while (size > 0)
	{
		int len = size;
		if (len > bufSize)
			len = bufSize;

		len = recv(socket, buf, len, flag);
		if (len == 0 || len == SOCKET_ERROR)
			return len;

		buf += len;
		size -= len;

		int recvSize = maxSize - size;
		wprintf_s(L"recv %d / %d [ %.2f%% ]\n", maxSize, recvSize, (float)recvSize * 100 / maxSize);
	}

	return maxSize;
}

 

클라이언트 코드

#include <stdio.h>
#include <WinSock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")

#pragma pack(push, 1)
typedef struct st_PACKET_HEADER
{
	DWORD dwPacketCode;		// 0x11223344 우리의 패킷확인 고정값
	WCHAR szName[32];		// 본인이름, 유니코드 NULL 문자 끝
	WCHAR szFileName[128];	// 파일이름, 유니코드 NULL 문자 끝
	int iFileSize;
} PACKET_HEADER;
#pragma pack(pop)

int recvn(SOCKET socket, char* buf, int bufSize, int maxSize, int flag);

int main()
{
	WSADATA wsaData;
	int ret;

	ret = WSAStartup(MAKEWORD(2, 2), &wsaData);
	if (ret != 0)
	{
		wprintf_s(L"error WSAStartup() [%d]\n", ret);
		return 1;
	}

	SOCKADDR_IN sockAddr;
	ZeroMemory(&sockAddr, sizeof(sockAddr));
	sockAddr.sin_family = AF_INET;
	sockAddr.sin_port = htons(7000);
	InetPtonW(sockAddr.sin_family, L"127.0.0.1", &sockAddr.sin_addr);

	// 파일 오픈
	FILE* file;
	ret = _wfopen_s(&file, L"Blackpink.jpg", L"rb");
	if (ret != 0 || file == NULL)
	{
		wprintf_s(L"error _wfopen_s() [%d]\n", ret);
		return 1;
	}

	// 파일 크기 구하기
	fseek(file, 0, SEEK_END);
	int fileSize = ftell(file);
	rewind(file);

	// 파일 크기만큼 메모리 할당 후 읽기
	char* data = new char[fileSize];
	fread_s(data, fileSize, fileSize, 1, file);
	fclose(file);

	// packet header 만들기
	PACKET_HEADER packetHeader;
	packetHeader.dwPacketCode = 0x11223344;
	wcscpy_s(packetHeader.szName, L"최영진");
	wcscpy_s(packetHeader.szFileName, L"Blackpink.jpg");
	packetHeader.iFileSize = fileSize;
	
	// socket()
	SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
	if (sock == INVALID_SOCKET)
	{
		wprintf_s(L"error socket() [%d]\n", WSAGetLastError());
		return 1;
	}

	// connect()
	ret = connect(sock, (SOCKADDR*)&sockAddr, sizeof(sockAddr));
	if (ret == SOCKET_ERROR)
	{
		wprintf_s(L"error connect() [%d]\n", WSAGetLastError());
		return 1;
	}

	// send header
	if (send(sock, (char*)&packetHeader, sizeof(packetHeader), 0) == SOCKET_ERROR)
	{
		wprintf_s(L"error header send() [%d]\n", WSAGetLastError());
		return 1;
	}

	// send file
	int sendSize = 0;
	while (sendSize < fileSize)
	{
		int elementSize = fileSize - sendSize;
		if (elementSize > 1000)
			elementSize = 1000;

		wprintf_s(L"elementSize: %d, ", elementSize);

		if (send(sock, data + sendSize, elementSize, 0) == SOCKET_ERROR)
		{
			wprintf_s(L"error data send() [%d]\n", WSAGetLastError());
			break;
		}

		sendSize += elementSize;
		wprintf_s(L"sendSize: %d\n", sendSize);
	}
	delete[] data;
	
	// recv data
	int recvData = 0;
	ret = recvn(sock, (char*)&recvData, sizeof(recvData), sizeof(recvData), 0);
	if (ret == 0 || ret == SOCKET_ERROR)
	{
		wprintf_s(L"error recvn() [%d]\n", WSAGetLastError());
		return 1;
	}

	wprintf_s(L"result: %x\n", recvData);

	closesocket(sock);
	WSACleanup();

	wprintf_s(L"== Done ==\n");
	return 0;
}

int recvn(SOCKET socket, char* buf, int bufSize, int maxSize, int flag)
{
	int size = maxSize;
	while (size > 0)
	{
		int len = size;
		if (len > bufSize)
			len = bufSize;

		len = recv(socket, buf, len, flag);
		if (len == 0 || len == SOCKET_ERROR)
			return len;

		buf += len;
		size -= len;

		int recvSize = maxSize - size;
		wprintf_s(L"recv %d / %d [ %.2f%% ]\n", maxSize, recvSize, (float)recvSize * 100 / maxSize);
	}

	return maxSize;
}
반응형

'공부' 카테고리의 다른 글

WSAAsyncSelect 모델 서버 프로그래밍  (0) 2020.10.19
Select모델 에코서버 프로그래밍  (0) 2020.10.17
TCP 에코서버 프로그래밍  (0) 2020.10.10
내 PC의 backlog 큐 개수 구하기  (2) 2020.10.08
도메인으로 IP 구하기  (0) 2020.10.08