본문 바로가기
IT창고/Network

파일전송 서버/클라이언트

by 창구창고 2007. 1. 22.

📑 목차

    반응형

    //file server

    #define WIN32_LEAN_AND_MEAN // windows.h 에서 자주 사용하지 않은 것은 컴파일에서 제외 한다.
    							// winsock2.h외의 충돌을 막아 준다.
    
    #include<stdio.h>
    #include<windows.h>
    #include<winsock2.h>
    #include<vector>// STL의 vector
    using namespace std;
    
    #pragma comment(lib, "ws2_32.lib")
    
    char filename[260] = "C:\\a.zip"; //전송할 파일
    
    struct FILE_INFO
    {
    	char FileName[260];	//전송할 파일 이름
    	int size;			//파일 크기
    };
    //전속한 클라이언트에게 파일을 보낸다.
    DWORD WINAPI FileServer(void * p)
    {
    	SOCKET s  = (SOCKET)p;
    
    	//전송할 파일 오픈
    	HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
    								0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    	if(hFile == INVALID_HANDLE_VALUE)
    	{
    		printf("Can't Open File\n");
    		closesocket(s);
    		return 0;
    	}
    
    	//크기를 구하고 파일의 정보를 전송한다.
    	DWORD size1;
    	DWORD size2 = GetFileSize(hFile, &size1);
    
    	FILE_INFO fi;
    	strcpy(fi.FileName, filename);
    	fi.size = size2;
    
    	send(s,(char *)&fi, sizeof(fi), 0);
    	//-----------------------------------------------------
    	//파일 전송
    	int total = size2; //전송할 전체 크기
    	int current = 0 ;	//전송한 크기
    	int nRead = 0;
    	char buf[4096];  //4K버퍼
    
    	while(total > current)
    	{
    		DWORD len;
    		nRead = ReadFile(hFile, buf, 4096, &len, 0);
    
    		if(len <= 0)break;
    
    		int nSend = send( s, buf, len, 0 );
    		if(nSend <= 0) break;
    
    		current += nSend;
    	}
    	if(total != current )		printf("전송 에러\n");
    	else						printf("전송완료]\n");
    	closesocket(s);
    	return 0;
    }
    
    void main()
    {
    	WSADATA wsadata;
    
    	//if(WSAStartup(0x0202, &wsadata) != 0)			//0x0202는 뒤에서부터 읽어서 2.2버젼을 쓰라는 이야기다.
    	if(WSAStartup(MAKEWORD(2,2), &wsadata) != 0)	//많이 사용... 앞에서 부터 읽는다.
    	{
    		printf("Can't Initialize Socket !\n");
    		return ;
    	}
    	//------------------------------------------
    	//1. socket생성 : TCP: SOCK_STREAM : UDP :SOCK_DGRAM
    	SOCKET s = socket(AF_INET,  SOCK_STREAM, 0);
    
    	//2. 생성된 소켓에 주소를 지정.
    	SOCKADDR_IN addr = { 0 };
    	addr.sin_family = AF_INET;	// 주소 종류 (AF_INET : IP 주소라는 의미..
    	addr.sin_port = htons(5000);	//Port #
    	addr.sin_addr.s_addr = INADDR_ANY;//inet_addr("61.81.99.54");
    	
    	if(bind(s,(SOCKADDR*)&addr, sizeof(addr)) == -1)	//서버의 닫혀 있는 상태를 대기 상태로 바꿔준다. 이순간 소켓은 내부적으로 접속요청 큐와 접속 완료 큐가 만들어진다.
    	{
    		printf("Can't bind \n"); 
    		return;
    		
    	}
    	
    	//3. 소켓을 대기 상태로 전환한다.
    	if(listen(s, 10) == -1)
    	{
    		printf("Can't Listen\n");
    		closesocket(s); // 소켓 닫기
    		return;
    	}
    	
    	printf("클리이언트를 대기합니다. \n");
    	
    	//4. 이제 Client 에서 부터 전달된 요청을 허용한다.
    	while(1)
    	{
    		SOCKADDR_IN c_addr;
    		int size = sizeof(c_addr);
    		
    		SOCKET c_s = accept(s, (SOCKADDR*)&c_addr, &size);	//억셉트를 눌렀는데 대기 큐에 아무도 없으면 대기한다.
    		//억셉트를 누르는 순간 새로운 소켓을 만들어서 
    		//상태를 연걸상태로 
    		//IP는 자신의 IP로 포트는 놀고있는 임의의 포트로 설정해준다.->4000번 포트로 접속해서 다른포트로 통신
    		//상대 IP와 상대 포트를 지정... 상대의 포트도 접속후에는 통신하는 포트로 지정한다.
    		//->접속하는 소켓은 대기만하고 접속하면 새로운 소켓이 통신을 한다.
    		
    		printf("클라이언트가 접속했습니다. IP : %s\n", inet_ntoa(c_addr.sin_addr));
    
    		
    		//새로운 스레드를 생성해서 클라이언트의 요청을 처리한다.
    		HANDLE hThread = CreateThread(0 , 0, FileServer, (void *)c_s, 0,0);
    		CloseHandle(hThread);
    	}
    	
    	//---------------------------------------------------------------------------
    	closesocket(s); // 소켓 닫기
    	
    	//--------------------------------------------------------------
    	
    	//------------------------------------------
    	WSACleanup();
    }
    
     
    //client
    #define WIN32_LEAN_AND_MEAN
    #include<winsock2.h>
    #include<windows.h>
    #include<commctrl.h>
    #include<stdio.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    struct FILE_INFO
    {
    	char FileName[260];
    	int size;
    };
    
    FILE_INFO g_info;
    
    LRESULT CALLBACK WndProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam);
    DWORD WINAPI FileClient(void * p)
    {
    	HWND hwnd = (HWND)p;
    
    	WSADATA w;
    	WSAStartup(MAKEWORD(2,2), &w);
    
    	SOCKET s = socket( AF_INET, SOCK_STREAM, 0);
    
    	SOCKADDR_IN addr;
    	addr.sin_family = AF_INET;
    	addr.sin_port	= htons(5000);
    	addr.sin_addr.s_addr = inet_addr("61.81.99.138");
    
    	if ( connect(s, (SOCKADDR *)&addr, sizeof(addr)) == -1)
    	{
    		MessageBox( 0, "Connect Error !!","",MB_OK);
    		return 0;
    	}
    
    	//-------------------------------------------------------------
    	// 파일 정보를 수신한다.
    	recv(s ,(char *)&g_info, sizeof(g_info), 0);
    
    	//주 스레드에 알려준다. -> 주스레드가 UI를 업데이트 한다.!
    	PostMessage(hwnd, WM_USER+100,0,0);
    	//-------------------------------------------------------------
    
    	char name[260];
    	strcpy(name, g_info.FileName);
    	strcat(g_info.FileName, "_bak");
    
    	HANDLE hFile = CreateFile(name, GENERIC_READ, FILE_SHARE_READ,
    								0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    	int total = g_info.size;
    	int current = 0;
    	char buf[4096];
    	while(total > current)
    	{
    		int nRecv = recv(s, buf, 4096, 0);
    		if( nRecv <= 0)break;
    
    		DWORD len;
    		WriteFile(hFile, buf, nRecv, &len, 0);
    
    		current += nRecv;
    		PostMessage(hwnd, WM_USER+200,0,(LPARAM)current);
    		//------------------------------------------------------------
    	}
    	if(total != current)	MessageBox(0,"Error","",MB_OK);
    	else					MessageBox(0,"OK","",MB_OK);
    	closesocket(s);
    	CloseHandle(hFile);
    	WSACleanup();
    	return 0;
    }
    
    TCHAR lpszClass[] = TEXT("first");
    
    int WINAPI WinMain(HINSTANCE hInstance,
    				   HINSTANCE hPrev,
    				   LPSTR lpCmdLine,
    				   int nShowCmd)
    {
    	//AllocConsole();	//	콘솔창 생성
    
    	//freopen("CONOUT$",	//콘솔을
    	//	"wt",			//text write모드로
    	//	stdout);		//stdoutrhk 연결
    	MSG Message;
    	//1. 위도우 클래스 만들기 (10가지를 다 정확히 입력하지 않으면 화면이 뜨지 않는다.)
    	WNDCLASS wc;		//미리정의된 10개 항목을 채우는 클래스 (WNDCLASSEX 12개 항목 10개 항목에 작은 아이콘, 구조체 크기를 포함한다.)
    	wc.cbClsExtra = 0;
    	wc.cbWndExtra = 0;
    	wc.hbrBackground	=	(HBRUSH)GetStockObject(	WHITE_BRUSH);
    
    	wc.hCursor		=	LoadCursor	(	0, IDC_CROSS);
    	wc.hIcon		=	LoadIcon	(	0, IDI_WINLOGO	);
    	wc.hInstance	=	hInstance;
    	wc.lpfnWndProc	=	WndProc;	//<~ 이부분을 자신이 만드는 함수로 바꿔줘야 한다.	메시지 함수등록
    	wc.lpszClassName=	lpszClass;
    	wc.lpszMenuName	=	0;
    	wc.style		=	0;
    
    	//2. 윈도우 클래스 등록하기.
    	RegisterClass( & wc	);	// 등록을 하는 함수도 2가지가 있다. RegisterClass와 RegisterClassEx가 있다.
    	//WNDCLASS로 만들었으면 RegisterClass로 등록하고 WNDCLASSEX로 만들었으면 RegisterClassEx로 등록
    
    	//3. 등록된 클래스를 사용해서 윈도우 만들기.
    	// typedef long HWND;	//	윈도우의 번호를 담을때 사용
    	HWND hwnd	=	CreateWindowEx(0 ,			// 확장 윈도우 스타일
    									lpszClass,				// 윈도우 클래스 이름
    									TEXT("첫시작"),					// 창이름
    									WS_OVERLAPPEDWINDOW,	// 기본 Window Styles : & ~ 연산으로 기존스타일 제거하기
    															// WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX
    									CW_USEDEFAULT,	0,	CW_USEDEFAULT,	0,	// X,Y,W,H
    									0,						// 부모 윈도우 핸들( 번호 )
    									0,						// 메뉴 핸들( 번호 )
    									hInstance,				// 인스턴스 핸들
    									0);						// 생성인자.( MDI 만들때 사용 )
    	
    	//4. 윈도우 보여주기
    	ShowWindow(hwnd, nShowCmd);
    
    	while(GetMessage(&Message,0,0,0))	//메시지 큐에 가서 메시지를 꺼내오고 가져온 메시지를 윈도우 클래스에 등록된 메세지 처리함수로 전달한다.
    	{
    		//여기서 메시지를 처리하면 부모뿐 아니라 모든 자식윈도우로 전달되는 메시지도 먼저 처리할 수 있다.
    
    		TranslateMessage(&Message);
    		if (Message.message	==	WM_SYSKEYDOWN && Message.wParam == 'X')
    		{
    			PostQuitMessage(0);
    			MessageBox(hwnd, "종료","질문",MB_OK);
    			//SendMessage(hwnd, WM_CLOSE,0,0);
    			continue;
    		}
    
    		//PreTranslateMessae(&Message);
    		DispatchMessage(&Message);//가져온 메시지를 윈도우 클래스에 등록된 메시지 처리함수로 전달한다.
    	}
    	
    	//MessageBox(0, "이제 알겠죠?","물음",MB_OKCANCEL);//종료되지 않게 하기 위해
    	return 0;
    }
    LRESULT CALLBACK WndProc(HWND hwnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
    {
    	static HWND hEdit1, hEdit2, hPrg;
    	switch(iMessage){
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0 ;
    	case WM_CREATE:
    		hEdit1 = CreateWindow("edit","",
    			WS_CHILD | WS_VISIBLE | WS_BORDER,// | WS_VSCROLL | ES_MULTILINE,
    			10,10,200,20,hwnd,(HMENU)1,0,0);
    		hEdit2 = CreateWindow("edit","",
    			WS_CHILD | WS_VISIBLE | WS_BORDER,// | WS_VSCROLL | ES_MULTILINE,
    			10,40,200,20,hwnd,(HMENU)2,0,0);
    		hPrg = CreateWindow(PROGRESS_CLASS,"",
    			WS_CHILD | WS_VISIBLE | WS_BORDER | PBS_SMOOTH,
    			10,70,400,20,hwnd,(HMENU)3,0,0);
    		return 0 ;
    	case WM_USER+100:
    		{
    			SetWindowText(hEdit1, g_info.FileName);
    			
    			char buf[256];
    			wsprintf(buf, "%d", g_info.size);
    			SetWindowText(hEdit2, buf);
    
    			//프로그래스 초기화
    			SendMessage(hPrg , PBM_SETRANGE32, 0, g_info.size);
    		}
    		return 0;
    	case WM_USER+200:
    		{
    			SendMessage(hPrg, PBM_SETPOS,lParam,0);
    		}
    		return 0;
    	case WM_LBUTTONDOWN:
    		{
    			CloseHandle(CreateThread(0, 0, FileClient, (void *)hwnd, 0,0));
    		}
    		return 0;
    	}
    	//꺼내온 메시지를 처리하지 않은경우 -> 바드시 아래 함수를 처리한다.
    	return(DefWindowProc(hwnd,iMessage,wParam,lParam));
    }
    반응형

    "이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."