파일 전송

Download Report

Transcript 파일 전송

16.

DLL

1. DLL (Dynamic Link Library)

– 동적 연결 라이브러리 (DLL) : • Microsoft Windows의 가장 중요한 구조적 요소 중 하나이다.

– 라이브러리의 기초 • DLL은 직접 실행될 수 없다.

• 메시지를 받지 않는다.

• 프로그램에서 호출되는 함수들을 가진 별도의 파일이다.

• 프로그램이 라이브러리 내의 함수들 중 하나를 호출할 때만 동작한다.

• 확장자가 DLL이면 자동으로 로드 된다.

– DLL의 목적 • 다수의 서로 다른 프로그램들에 의해 사용될 수 있는 함수와 자원을 제공 – DllMain • DLL이 실행 파일에 의해 요청되거나 해제될 때 호출된다.

• DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved) • hInstance : 라이브러리의 인스턴스 핸들 • dwReason : Windows가 DllMain을 호출하는 이유 – DLL_PROCESS_ATTACH – 동적 연결 라이브러리가 프로세스의 주소 공간으로 매핑되어 있음을 나 타낸다.

– 프로세스가 수행되는 동안 오직 한번의 호출된다.

1. DLL (Dynamic Link Library)

– DLL_PROCESS_DETACH – 해당 프로세스에 DLL이 더 이상 필요로 하지 않는다는것을 의미한다.

– 라이브러리가 자신을 정리한다.

– DLL_THREAD_ATTACH – 추가된 프로세스가 새로운 스레드를 만든다.

– DLL_THREAD_DETACH – 스레드가 종료될 때 Window는 호출한다.

– 우선 함수를 제공하는 DLL에서는 자신이 제공하는 함수에 대한 정 보를 밖으로 공개해 놓아야 한다. Export – DLL을 사용하는 클라이언트에서는 어떤 DLL에 있는 어떤 함수를 사용하겠다고 선언해야 한다. Import – __declspec ( extended-decl-modifier-seq ) • 함수에 대한 정보를 제공하는 선언문이며 엑스포트 또는 임포트하는 함수 앞에 수식어로 이문구가 있어야 한다.

• extern "C" __declspec(dllexport) int InitHook( HINSTANCE hDll, HWND hWndHost ) • extern "C" typedef __declspec(dllimport) int (*PFNInitHook)( HINSTANCE hDll, HWND hWndHost ); • extern "C" typedef __declspec(dllimport) void (*PFNGetDeadWndTxt)( char *pszBuf, int nMaxBuf ); • extern "C" typedef __declspec(dllimport) void (*PFNReleaseHook)();

1. DLL (Dynamic Link Library)

– extern “ C ” • mangled name을 만들지 않도록 지정함으로써 C형식으로 함수의 정 보를 공개하도록 한다.

• 명시적 연결

m_hInstDll = ::LoadLibrary( "l3t_hook.dll" ); if( !m_hInstDll ) { MessageBox( "l3t_hook.dll 을 찾을 수 없습니다.", "오류" ); return FALSE; } m_pfnInitHook = (PFNInitHook)::GetProcAddress( m_hInstDll, "InitHook" ); m_pfnReleaseHook = (PFNReleaseHook)::GetProcAddress( m_hInstDll, "ReleaseHook" ); m_pfnGetDeadWndTxt = (PFNGetDeadWndTxt)::GetProcAddress( m_hInstDll, "GetDeadWndTxt" ); if( (!m_pfnInitHook) || (!m_pfnReleaseHook) ) { MessageBox( "잘못된 dll입니다.", "오류" ); ::FreeLibrary( m_hInstDll ); m_hInstDll = 0; return FALSE; }

17.

소켓의 기초

1. 서버 소켓

• 소켓이 작업하는 방식

– 1. 연결의 기다리는 소켓 : 서버 소켓 – 2. 연결을 시도하는 소켓 : 클라이언트 소켓

• 서버 소켓

– 연결을 시도하는 클라이언트 소켓과의 연결을 구축한다.

– 서버 소켓은 데이터의 흐름에 대해서는 신경 쓰지 않는다. 오직 연결만 처리한다.

– 데이터의 흐름은 같은 프로그램 내의 다른 소켓이 담당하게 된다.

서버 1. 연결 시도 클라이언트 (원격 소켓) 2. 소켓 생성 3. 연결 및 데이터 송수신 클라이언트 (로컬 소켓)

1. 서버 소켓

• 1. 서버 소켓이 존재하는 상태에서 원격 소켓이 연결을 시도 • 2. 서버 소켓은 패킷 송수신을 담당할 로컬 소켓을 생성 • 3. 로컬 소켓과 연결을 시도한 원격 소켓을 연결 • 4. 서버 로컬 소켓과 원격 소켓 간의 데이터 송수신 – 연결을 시도하는 소켓은 무조건 큐에 들어간다.

– 큐에 들어가서 자신이 처리될 순서를 기다린다.

– 서버 소켓은 큐에 들어 있는 원격 소켓을 하나씩 처리한다.

1. 서버 소켓

• 서버 소켓 흐름도

소켓 생성 : socket() 결합 : bind() 듣기 : listen () 항상, 참 대기 : Accept() 로컬 소켓 생성 연결구축, 로컬 소켓과 원격 소켓 1회 실행 무한 반복

#include #include #include "resource.h" BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; WSACleanup(); return TRUE; } BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEdit1,hEdit2; static HWND hButton1,hButton2; static SOCKET hServerSock; static SOCKET hClientSock; switch (message) { case WM_INITDIALOG : { hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hEdit2 = GetDlgItem(hDlg,IDC_EDIT2); hButton1 = GetDlgItem(hDlg,IDC_BUTTON1); hButton2 = GetDlgItem(hDlg,IDC_BUTTON2); EnableWindow(hButton1,FALSE); EnableWindow(hButton2,FALSE); hServerSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in ServerAddr; ZeroMemory(&ServerAddr,sizeof(sockaddr_in)); ServerAddr.sin_addr.s_addr = ADDR_ANY; ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(50000);

bind(hServerSock,(sockaddr *)&ServerAddr,sizeof(sockaddr_in)); listen(hServerSock,SOMAXCONN); SetWindowText(hEdit1,"클라이언트 접속을 기다리고 있습니다."); } return TRUE ; case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_ACCEPT: { sockaddr_in ClientAddr; int nAddrLen = sizeof(ClientAddr); hClientSock = accept(hServerSock,(sockaddr *)&ClientAddr,&nAddrLen); if (hClientSock == INVALID_SOCKET) { int ErrorCode = WSAGetLastError(); char errMsg[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,ErrorCode,0,errMsg,1204,NULL); MessageBox(NULL,errMsg,"",MB_OK); } char temp[256]; wsprintf(temp,"%s 클라이언트 접속 요청",inet_ntoa(ClientAddr.sin_addr)); SetWindowText(hEdit1,temp); EnableWindow(hButton1,TRUE); EnableWindow(hButton2,TRUE); return TRUE; } case IDC_BUTTON1: { char temp[256]; recv(hClientSock,temp,256,NULL); SetWindowText(hEdit2,temp); return TRUE; }

} break ; } return FALSE ; case IDC_BUTTON2: { char temp[256]; GetWindowText(hEdit2,temp,256); send(hClientSock,temp,256,NULL); return TRUE; } case IDOK : case IDCANCEL : closesocket(hServerSock); closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; }

1. 서버 소켓

– accept 함수 • 클라이언트 소켓이 연결을 시도할 때까지 블로킹상태에 빠지기 때 문에 프로그램이 죽은 것처럼 보인다.

• 첫 번째 인자 : 대기 모드에 들어가 있는 소켓의 핸들. 반드시 listen 함수 호출에서 성공한 핸들이어야 한다.

• 두 번째 인자 : 연결을 시도한 클라이언트 소켓의 번호를 받을 sockaddr_in 구조체의 주소 • 세 번째 인자 : 두 번째 인자로 들어가는 구조체의 크기 • 원격지에서 연결을 시도한 소켓과 연결을 담당한다.

• 두 번째 인자를 통하여 넘어온 IP를 확인하여 연결을 허락할지 끊어 야 할지를 결정한다.

– 연결을 끊을 때는 closesocket함수를 이용하낟.

• 리턴 값 : 원격지 소켓과의 데이터 송수신을 처리할 소켓의 핸들을 반환한다. (accept함수 내부에서 생성) – 실패하면 INVALID_SOCKET 이 리턴된다.

• accept함수가 성공하면 프로그램에는 소켓이 두 개가 존재하게 된 다.

2. 클라이언트(원격) 소켓

– 원격 소켓 • 원격 소켓의 역할은 서버 소켓에 연결을 시도하는 것이다.

• 원격 소켓이 서버에 연결하기 위해서는 반드시, 서버의 주소와 포트 번호를 알고 있어야 한다.

• 클라이언트 프로그램이 종료되면, 원격 소켓은 자동으로 종료된다.

• 소켓은 종료할 때, 자신과 연결된 상대 소켓에게 종료되었다고 알려 준다.

2. 클라이언트(원격) 소켓

• 클라이언트(원격) 소켓 흐름도

실패 종료 : closesocket() 예 소켓 생성 : socket() 서버에 연결 : connect () 연결 ?

성공 작업 완료?

데이터 송수신 send(),receive() 1회 실행 무한 반복

#include #include #include "resource.h" BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; WSACleanup(); return TRUE; } BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEdit1,hEdit2; static HWND hButton1,hButton2; static SOCKET hClientSock; switch (message) { case WM_INITDIALOG : { hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hEdit2 = GetDlgItem(hDlg,IDC_EDIT2); hButton1 = GetDlgItem(hDlg,IDC_BUTTON1); hButton2 = GetDlgItem(hDlg,IDC_BUTTON2); EnableWindow(hButton1,FALSE); EnableWindow(hButton2,FALSE); } return TRUE ; hClientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

} case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_CONNECT: { sockaddr_in ServerAddr; ZeroMemory(&ServerAddr,sizeof(sockaddr_in)); ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(50000); connect(hClientSock,(sockaddr *)&ServerAddr,sizeof(ServerAddr)); SetWindowText(hEdit1,"서버에 접속되었습니다."); EnableWindow(hButton1,TRUE); EnableWindow(hButton2,TRUE); break ; } return FALSE ; return TRUE; } case IDC_BUTTON1: { char temp[256]; recv(hClientSock,temp,256,NULL); SetWindowText(hEdit2,temp); return TRUE; } case IDC_BUTTON2: { char temp[256]; GetWindowText(hEdit2,temp,256); send(hClientSock,temp,256,NULL); return TRUE; } case IDOK : case IDCANCEL : closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; }

3. TCP

• UDP

– 연결이 존재하지 않는다.

– 최선형 (best effort) 프로토콜로 최선을 다해서 데이터가 도착하 도록 노력은 하지만, 도착하지 않아도 책임은 지지 않는다.

– 도착하지 않았을 때의 책임은 각각의 프로그램에서 담당한다.

– 연결이 존재하지 않기 때문에 각각의 패킷은 서로 연관성이 없어 야 한다.

– 전송 패킷은 반드시 한 번에 전송되어야 한다.

• TCP의 경우는 여러 번에 걸쳐 전송될 수도 있다.

• TCP

– TCP프로토콜은 가상으로 연결된 상태이다.

– 한 번에 전송한 패킷이 한번에 전송될 수도 있고 여러 번에 걸쳐 서 전송될 수도 있다.

3. TCP

– 여러 번에 걸쳐서 전송된 패킷이 한번에 전송될 수도 있다.

– 연결이 된 이후부터 연결을 닫을 때까지 전송한 데이터가 모두 하 나의 데이터이다.

– TCP에서는 어디서부터 어디까지가 의미 있는 하나의 패킷인지 확 인하는 작업이 필수적이다.

– 전송 측과 수신 측 모두 두 개의 버퍼를 사용한다.

• 애플리케이션 버퍼, 전송 또는 수신을 위한 소켓 라이브러리 버퍼 • send 함수를 호출했다고 해서 패킷이 실제로 상대 소켓으로 전달되 었다고 가정해서는 안 된다.

• send함수는 소켓 라이브러리의 버퍼로 데이터를 옮겨놓는 순간 반환 된다.

• 만약에 소켓 라이브러리 버퍼가 꽉 차면 블로킹 상태가 된다.

• 상대 소켓으로 데이터를 전송하고 나서 버퍼에 여유가 생겨서 send 함수가 모든 데이터를 이동하면, 그때 블로킹이 풀린다.

– TCP 프로토콜에서 연결이 구축되어 있는 동안 전송되는 패킷은 모두 연속되어 있다. 패킷을 처리할 때는, 각각의 패킷 길이만큼 잘라서 처리해야 한다.

4. 패킷

– 패킷은 크게 두 부분으로 나뉜다. ( 헤더와 데이터 ) – 헤더에는 반드시 전체 패킷의 크기가 들어가야 한다.

• 한 패킷을 잘라 오기 위하여 – 패킷 헤더는 일반적으로 어떠한 패킷이던지 동일한 길이로 구성 한다.

헤더 패킷 전체 길이 (4byte) 로그인 24 파일요청 80 식별자 (4byte) LOGIN FILE_REQUEST 파일 전송 파일길이+8 FILE_TRANSFER 회원ID (8byte) 회원ID (8byte) PassWord (8byte) 파일의 HashKey (64byte) 파일내용 가변길이

18.

소켓 초기화

1. WSAStartup함수

– 윈도우 소켓을 초기화한다.

– Ws2_32.dll함수를 응용 프로그램의 영역으로 로드한다.

WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); – WSADATA구조체 변수는 WSAStartup함수가 반환하는 윈도우 소 켓의 세부 정보를 가져 온다.

– 첫 번째 인자에는 소켓 라이브러리의 버전을 저장한다.

• 하위 바이트에는 메이저 버전 : 2 • 상위 바이트에는 마이너 버전 : 2 • MAKEWORD(하위, 상위) – MAKEWORD(3,5) : 이 코드는 윈도우 버전 3.5를 의미한다.

2. WSACleanup함수

– 윈도우 소켓을 종료하는 함수이다.

– Ws2_32.dll을 사용하지 못하게 한다.

WSACleanup();

3. 메모리 바이트 순서

– 인텔 계열의 CPU는 리틀 엔디안이라는 방식으로 데이터를 메모 리에 저장한다.

• 16진수 “2F78 ” 은 782F로 메모리에 저장된다.

– 모토로라의 CPU는 빅 엔디안이라는 방식으로 데이터를 메모리에 저장한다.

• 16진수 “2F78 ” 은 2F78 – 네트워크 바이트 순서는 빅 엔디언을 이용합니다.

• htons 함수

– htons 함수는 “host to network short ” 의 약자이다.

– 호스트 바이트 순서로 되어있는 unsigned short를 네트워크 바이 트 순서로 변환한다.

– 이 함수는 소켓 프로그래밍에서 포트 번호를 변환하기 위해서 사 용한다.

• ntohs 함수

– ntohs 함수는 “network to host short ” 의 약자이다.

– 네트워크 바이트 순서로 되어 있는 unsigned short자료형을 호스 트 바이트 순서로 변환한다.

3. 메모리 바이트 순서

• htonl함수

– htonl함수는 “host to network long ” 의 약자이다.

– 이 함수는 호스트 바이트 순서로 된 unsigned long자료형을 네트 워크 바이트 순서로 변환한다.

– 이 함수는 소켓 프로그래밍에서 IP주소를 변환하기 위해 사용한다.

• ntohl함수

– ntohl함수는 “network to host long ” 의 약자이다.

– 네트워크 바이트 순서로 된 unsigned long자료형을 호스트 바이 트 순서로 변환한다.

• inet_ntoa함수

– 4바이트로 된 IP주소를 도트 표기법에 기반한 문자열로 변환한다.

– 클라이언트의 주소를 문자열로 변환해서 보여줄 때 사용

• inet_addr함수

– inet_addr함수는 internet address의 약자이다.

– 도트 표기법으로 되어 있는 주소 문자열을 4바이트 IP주소로 변환

19.

파일 전송

1. TransmitFile함수

BOOL TransmitFile( SOCKET HANDLE DWORD DWORD LPOVERLAPPED LPTRANSMIT_FILE_BUFFERS DWORD hSocket, hFile, nNumberOfBytesToWrite, nNumberOfBytesPerSend, lpOverlapped, lpTransmitBuffers, dwFlags ); – hSocket : 파일을 보낼 소켓의 핸들 – hFile : 전송할 파일의 핸들 – nNumberOfBytesToWrite : 전송할 양으로 파일 전체를 전송할 때 는 0을 사용한다.

– nNumberOfBytesPerSend : 한 번에 전송할 패킷의 크기. 패킷의 크기를 시스템에 맡길 경우, 0을 사용한다.

– lpOverlapped : 중첩 입출력 구조체로 비동기 작업을 수행할 수 있도록 한다.

– lpTransmitBuffers : 파일을 전송하기 전에 전송할 헤더와 전송 후 에 전송할 테일을 가리키는 구조체 포인터이다.

#include #include #include "resource.h" #include #include BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; WSACleanup(); return TRUE; } void DispErrorMessage() { DWORD ErrorCode = GetLastError(); char errMsg[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,ErrorCode,0,errMsg,1204,NULL); MessageBox(NULL,errMsg,"",MB_OK); } BOOL GetFileName(char temp[]) { strcpy(temp,"123.txt"); OPENFILENAME ofn; ZeroMemory(&ofn,sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); ofn.hwndOwner = NULL; ofn.lpstrFilter = "모든 파일(*.*)\0*.*\0텍스트 파일(*.txt)\0*.txt\0\0\0"; ofn.lpstrFile = temp; ofn.nFilterIndex = 2; ofn.nMaxFile = 256; ofn.Flags = OFN_EXPLORER | OFN_ALLOWMULTISELECT | OFN_ENABLESIZING ; return GetOpenFileName(&ofn); }

typedef struct Tansmitstruct { char pFileName[256]; int nFileSize; }TRANSMITSTRUCT; BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEdit1; static HWND hButton1; static SOCKET hServerSock; static SOCKET hClientSock; switch (message) { case WM_INITDIALOG : { hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hButton1 = GetDlgItem(hDlg,IDC_BUTTON1); EnableWindow(hButton1,FALSE); hServerSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in ServerAddr; ZeroMemory(&ServerAddr,sizeof(sockaddr_in)); ServerAddr.sin_addr.s_addr = ADDR_ANY; ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(50000); bind(hServerSock,(sockaddr *)&ServerAddr,sizeof(sockaddr_in)); listen(hServerSock,SOMAXCONN); } return TRUE ; SetWindowText(hEdit1,"클라이언트 접속을 기다리고 있습니다.");

case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_ACCEPT: { sockaddr_in ClientAddr; int nAddrLen = sizeof(ClientAddr); hClientSock = accept(hServerSock,(sockaddr *)&ClientAddr,&nAddrLen); if (hClientSock == INVALID_SOCKET) { int ErrorCode = WSAGetLastError(); char errMsg[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,ErrorCode,0,errMsg,1204,NULL); MessageBox(NULL,errMsg,"",MB_OK); } char temp[256]; wsprintf(temp,"%s 클라이언트 접속 요청",inet_ntoa(ClientAddr.sin_addr)); SetWindowText(hEdit1,temp); EnableWindow(hButton1,TRUE); return TRUE; } case IDC_BUTTON1: { char TransFileName[256]; if (GetFileName(TransFileName) == FALSE) { return TRUE; } char temp[256]; wsprintf(temp,"%s 파일을 전송합니다.",TransFileName); SetWindowText(hEdit1,temp); HANDLE hFile = CreateFile(TransFileName,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQU if (hFile == INVALID_HANDLE_VALUE) { DispErrorMessage(); return TRUE; }

} BY_HANDLE_FILE_INFORMATION fileinfo; GetFileInformationByHandle(hFile,&fileinfo); char FileName[256]; char FileExt[256]; _splitpath(TransFileName,NULL,NULL,FileName,FileExt); strcat(FileName,FileExt); TRANSMITSTRUCT transmitstruct; transmitstruct.nFileSize = fileinfo.nFileSizeLow; strcpy(transmitstruct.pFileName,FileName); TRANSMIT_FILE_BUFFERS TransBuf; ZeroMemory(&TransBuf,sizeof(TRANSMIT_FILE_BUFFERS)); char pTailMsg[32] = "End Of File"; TransBuf.Head = &transmitstruct; TransBuf.HeadLength = sizeof(transmitstruct); TransBuf.Tail = pTailMsg; TransBuf.TailLength = sizeof(pTailMsg); BOOL bTrans = TransmitFile(hClientSock,hFile,0,0,NULL,&TransBuf,0); if (bTrans == FALSE) { DispErrorMessage(); } CloseHandle(hFile); break ; } return FALSE ; SetWindowText(hEdit1,"파일 전송을 완료했습니다."); return TRUE; } case IDOK : case IDCANCEL : closesocket(hServerSock); closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; }

#include #include #include #include "resource.h" BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; WSACleanup(); return TRUE; } void DispErrorMessage() { DWORD ErrorCode = GetLastError(); char errMsg[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,ErrorCode,0,errMsg,1204,NULL); MessageBox(NULL,errMsg,"",MB_OK); } typedef struct Tansmitstruct { char pFileName[256]; int nFileSize; }TRANSMITSTRUCT;

BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hEdit1; static HWND hButton1,hProgress; static SOCKET hClientSock; switch (message) { case WM_INITDIALOG : { hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hButton1 = GetDlgItem(hDlg,IDC_BUTTON1); hProgress = GetDlgItem(hDlg,IDC_PROGRESS1); EnableWindow(hButton1,FALSE); hClientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); } return TRUE ; case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_CONNECT: { sockaddr_in ServerAddr; ZeroMemory(&ServerAddr,sizeof(sockaddr_in)); ServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(50000); connect(hClientSock,(sockaddr *)&ServerAddr,sizeof(ServerAddr)); SetWindowText(hEdit1,"서버에 접속되었습니다."); EnableWindow(hButton1,TRUE); return TRUE; }

case IDC_BUTTON1: { SetWindowText(hEdit1,"서버에서 파일을 수신 중입니다."); SendMessage(hProgress,PBM_SETRANGE32,0,0); SendMessage(hProgress,PBM_SETPOS,0,0); TRANSMITSTRUCT transstruct; int nTotalSize = sizeof(TRANSMITSTRUCT); int nTotalRecv = 0; do{ int nReceived = recv(hClientSock,(char *)(&transstruct+nTotalRecv),nTotalSize nTotalRecv += nReceived; }while(nTotalSize != nTotalRecv); SendMessage(hProgress,PBM_SETRANGE32,0,transstruct.nFileSize); SendMessage(hProgress,PBM_SETPOS,0,0); char temp[256]; wsprintf(temp,"%s(크기 : %d k)파일 수신 중 입니다.",transstruct.pFileName,transstruct.nFileSize); SetWindowText(hEdit1,temp); HANDLE hFile = CreateFile(transstruct.pFileName,GENERIC_WRITE,FILE_SHARE_READ,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_ if (hFile == INVALID_HANDLE_VALUE) { DispErrorMessage(); return TRUE; } BYTE pFileBuf[1024]; nTotalSize = transstruct.nFileSize; nTotalRecv = 0;

} do{ DWORD dwByteRead; if ( (nTotalSize-nTotalRecv) > sizeof(pFileBuf)) dwByteRead = sizeof(pFileBuf); else dwByteRead = nTotalSize-nTotalRecv; int nReceived = recv(hClientSock,(char *)&pFileBuf,dwByteRead,0); if (nReceived == SOCKET_ERROR) { DispErrorMessage(); CloseHandle(hFile); return TRUE; } nTotalRecv += nReceived; DWORD dwByteWritten = 0; WriteFile(hFile,pFileBuf,dwByteRead,&dwByteWritten,NULL); SendMessage(hProgress,PBM_SETPOS,nTotalRecv,0); }while(nTotalSize != nTotalRecv); CloseHandle(hFile); nTotalSize = 32; nTotalRecv = 0; do{ int nReceived = recv(hClientSock,(char *)&pFileBuf+nTotalRecv,nTotalSize nTotalRecv += nReceived; }while(nTotalSize != nTotalRecv); break ; } return FALSE ; SetWindowText(hEdit1,"파일 수신을 완료했습니다."); return TRUE; } case IDOK : case IDCANCEL : closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; }

20.

1 대 1 채팅

#include #include #include #include "resource.h" #define WM_SOCKTEVENT WM_USER+100 void DispErrorMessage() { DWORD ErrorCode = GetLastError(); char errMsg[1024]; FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,NULL,ErrorCode,0,errMsg,1204,NULL); MessageBox(NULL,errMsg,"",MB_OK); } BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam); HINSTANCE hInst; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow) { WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); hInst = hInstance; HMODULE hMod = LoadLibrary("RICHED32.DLL"); InitCommonControls(); DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1), NULL, DlgProc) ; FreeLibrary(hMod); WSACleanup(); return TRUE; }

BOOL CALLBACK DlgProc2 (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hIPCtrl; static HWND hRadio1,hRadio2; switch (message) { case WM_INITDIALOG : { hIPCtrl = GetDlgItem(hDlg,IDC_IPADDRESS1); hRadio1 = GetDlgItem(hDlg,IDC_RADIO1); hRadio2 = GetDlgItem(hDlg,IDC_RADIO2); SendMessage(hRadio1,BM_SETCHECK,TRUE,NULL); EnableWindow(hIPCtrl,FALSE); } return TRUE ; case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_RADIO1: EnableWindow(hIPCtrl,FALSE); return TRUE ; case IDC_RADIO2: EnableWindow(hIPCtrl,TRUE); return TRUE ; case IDOK : case IDCANCEL : if (SendMessage(hRadio1,BM_GETCHECK,NULL,NULL)) { EndDialog (hDlg, 0) ; } else { DWORD nAddress; int nIP = (int)SendMessage(hIPCtrl,IPM_GETADDRESS,0,(LPARAM)&nAddress); if (nIP != 4) MessageBox(hDlg,"IP주소를 모두 입력하세요",NULL,MB_OK); else EndDialog (hDlg, nAddress) ; } return TRUE ; } break ; } return FALSE ; }

BOOL CALLBACK DlgProc (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { static HWND hRichEdit1,hEdit1; static HWND hButton1; static SOCKET hClientSock; static SOCKET hServerSock; switch (message) { case WM_INITDIALOG : { hEdit1 = GetDlgItem(hDlg,IDC_EDIT1); hRichEdit1 = GetDlgItem(hDlg,IDC_RICHEDIT1); hButton1 = GetDlgItem(hDlg,IDC_BUTTON1); EnableWindow(hButton1,FALSE); UpdateWindow(hDlg); DWORD dwIP = DialogBox(hInst,MAKEINTRESOURCE(IDD_DIALOG2), NULL, DlgProc2) ; if (dwIP == 0) { hServerSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in ServerAddr; ZeroMemory(&ServerAddr,sizeof(sockaddr_in)); ServerAddr.sin_addr.s_addr = ADDR_ANY; ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(50000); bind(hServerSock,(sockaddr *)&ServerAddr,sizeof(sockaddr_in)); listen(hServerSock,SOMAXCONN); WSAAsyncSelect(hServerSock,hDlg,WM_SOCKTEVENT,FD_ACCEPT); SetWindowText(hDlg,"서버"); }

else { hClientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in ServerAddr; ZeroMemory(&ServerAddr,sizeof(sockaddr_in)); ServerAddr.sin_addr.s_addr = htonl(dwIP); ServerAddr.sin_family = AF_INET; ServerAddr.sin_port = htons(50000); connect(hClientSock,(sockaddr *)&ServerAddr,sizeof(ServerAddr)); WSAAsyncSelect(hClientSock,hDlg,WM_SOCKTEVENT,FD_READ|FD_CLOSE); SetWindowText(hDlg,"클라언트"); } EnableWindow(hButton1,TRUE); } return TRUE ; case WM_SOCKTEVENT: { int nEvent = LOWORD(lParam); int nError = HIWORD(lParam); switch(nEvent) { case FD_ACCEPT: { sockaddr_in ClientAddr; int nAddrLen = sizeof(ClientAddr); hClientSock = accept(hServerSock,(sockaddr *)&ClientAddr,&nAddrLen); closesocket(hServerSock); hServerSock = INVALID_SOCKET; WSAAsyncSelect(hClientSock,hDlg,WM_SOCKTEVENT,FD_READ|FD_CLOSE); } break; case FD_READ: { char temp[256]; int nReceived = recv(hClientSock,temp,256,NULL); SetWindowText(hRichEdit1,temp); } break;

} case FD_CLOSE: { closesocket(hClientSock); hClientSock = INVALID_SOCKET; MessageBox(hDlg,"상대방에서 연결을 종료했습니다.",NULL,MB_OK); } break; } } return TRUE; case WM_COMMAND : switch (LOWORD (wParam)) { case IDC_BUTTON1: { char temp[256]; GetWindowText(hEdit1,temp,256); send(hClientSock,temp,256,NULL); } return TRUE ; case IDOK : case IDCANCEL : closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ;