1 / 41

16.

16. DLL. 1. DLL (Dynamic Link Library). 동적 연결 라이브러리 (DLL) : Microsoft Windows 의 가장 중요한 구조적 요소 중 하나이다 . 라이브러리의 기초 DLL 은 직접 실행될 수 없다 . 메시지를 받지 않는다 . 프로그램에서 호출되는 함수들을 가진 별도의 파일이다 . 프로그램이 라이브러리 내의 함수들 중 하나를 호출할 때만 동작한다 . 확장자가 DLL 이면 자동으로 로드 된다 . DLL 의 목적 다수의 서로 다른 프로그램들에 의해 사용될 수 있는

fonda
Download Presentation

16.

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 16. DLL

  2. 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 • 동적 연결 라이브러리가 프로세스의 주소 공간으로 매핑되어 있음을 나타낸다. • 프로세스가 수행되는 동안 오직 한번의 호출된다.

  3. 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)();

  4. 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; }

  5. 17. 소켓의 기초

  6. 서버 클라이언트 (원격 소켓) 1. 연결 시도 2. 소켓 생성 클라이언트 (로컬 소켓) 3. 연결 및 데이터 송수신 1. 서버 소켓 • 소켓이 작업하는 방식 • 1. 연결의 기다리는 소켓 : 서버 소켓 • 2. 연결을 시도하는 소켓 : 클라이언트 소켓 • 서버 소켓 • 연결을 시도하는 클라이언트 소켓과의 연결을 구축한다. • 서버 소켓은 데이터의 흐름에 대해서는 신경 쓰지 않는다. 오직 연결만 처리한다. • 데이터의 흐름은 같은 프로그램 내의 다른 소켓이 담당하게 된다.

  7. 1. 서버 소켓 • 1. 서버 소켓이 존재하는 상태에서 원격 소켓이 연결을 시도 • 2. 서버 소켓은 패킷 송수신을 담당할 로컬 소켓을 생성 • 3. 로컬 소켓과 연결을 시도한 원격 소켓을 연결 • 4. 서버 로컬 소켓과 원격 소켓 간의 데이터 송수신 • 연결을 시도하는 소켓은 무조건 큐에 들어간다. • 큐에 들어가서 자신이 처리될 순서를 기다린다. • 서버 소켓은 큐에 들어 있는 원격 소켓을 하나씩 처리한다.

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

  9. #include <winsock2.h> #include <windows.h> #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);

  10. 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; }

  11. 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 ; } break ; } return FALSE ; }

  12. 1. 서버 소켓 • accept 함수 • 클라이언트 소켓이 연결을 시도할 때까지 블로킹상태에 빠지기 때문에 프로그램이 죽은 것처럼 보인다. • 첫 번째 인자 : 대기 모드에 들어가 있는 소켓의 핸들. 반드시 listen 함수 호출에서 성공한 핸들이어야 한다. • 두 번째 인자 : 연결을 시도한 클라이언트 소켓의 번호를 받을 sockaddr_in 구조체의 주소 • 세 번째 인자 : 두 번째 인자로 들어가는 구조체의 크기 • 원격지에서 연결을 시도한 소켓과 연결을 담당한다. • 두 번째 인자를 통하여 넘어온 IP를 확인하여 연결을 허락할지 끊어야 할지를 결정한다. • 연결을 끊을 때는 closesocket함수를 이용하낟. • 리턴 값 : 원격지 소켓과의 데이터 송수신을 처리할 소켓의 핸들을 반환한다. (accept함수 내부에서 생성) • 실패하면 INVALID_SOCKET 이 리턴된다. • accept함수가 성공하면 프로그램에는 소켓이 두 개가 존재하게 된다.

  13. 2. 클라이언트(원격) 소켓 • 원격 소켓 • 원격 소켓의 역할은 서버 소켓에 연결을 시도하는 것이다. • 원격 소켓이 서버에 연결하기 위해서는 반드시, 서버의 주소와 포트 번호를 알고 있어야 한다. • 클라이언트 프로그램이 종료되면, 원격 소켓은 자동으로 종료된다. • 소켓은 종료할 때, 자신과 연결된 상대 소켓에게 종료되었다고 알려 준다.

  14. 소켓 생성 : socket() 1회 실행 서버에 연결 : connect () 실패 연결 ? 성공 예 작업 완료? 데이터 송수신 send(),receive() 종료 : closesocket() 무한 반복 2. 클라이언트(원격) 소켓 • 클라이언트(원격) 소켓 흐름도

  15. #include <winsock2.h> #include <windows.h> #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); hClientSock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); } return TRUE ;

  16. 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); 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 ; } break ; } return FALSE ; }

  17. 3. TCP • UDP • 연결이 존재하지 않는다. • 최선형 (best effort) 프로토콜로 최선을 다해서 데이터가 도착하도록 노력은 하지만, 도착하지 않아도 책임은 지지 않는다. • 도착하지 않았을 때의 책임은 각각의 프로그램에서 담당한다. • 연결이 존재하지 않기 때문에 각각의 패킷은 서로 연관성이 없어야 한다. • 전송 패킷은 반드시 한 번에 전송되어야 한다. • TCP의 경우는 여러 번에 걸쳐 전송될 수도 있다. • TCP • TCP프로토콜은 가상으로 연결된 상태이다. • 한 번에 전송한 패킷이 한번에 전송될 수도 있고 여러 번에 걸쳐서 전송될 수도 있다.

  18. 3. TCP • 여러 번에 걸쳐서 전송된 패킷이 한번에 전송될 수도 있다. • 연결이 된 이후부터 연결을 닫을 때까지 전송한 데이터가 모두 하나의 데이터이다. • TCP에서는 어디서부터 어디까지가 의미 있는 하나의 패킷인지 확인하는 작업이 필수적이다. • 전송 측과 수신 측 모두 두 개의 버퍼를 사용한다. • 애플리케이션 버퍼, 전송 또는 수신을 위한 소켓 라이브러리 버퍼 • send 함수를 호출했다고 해서 패킷이 실제로 상대 소켓으로 전달되었다고 가정해서는 안 된다. • send함수는 소켓 라이브러리의 버퍼로 데이터를 옮겨놓는 순간 반환된다. • 만약에 소켓 라이브러리 버퍼가 꽉 차면 블로킹 상태가 된다. • 상대 소켓으로 데이터를 전송하고 나서 버퍼에 여유가 생겨서 send함수가 모든 데이터를 이동하면, 그때 블로킹이 풀린다. • TCP 프로토콜에서 연결이 구축되어 있는 동안 전송되는 패킷은 모두 연속되어 있다. 패킷을 처리할 때는, 각각의 패킷 길이만큼 잘라서 처리해야 한다.

  19. 패킷 전체 길이 (4byte) 식별자 (4byte) 헤더 24 LOGIN 회원ID (8byte) PassWord (8byte) 로그인 80 FILE_REQUEST 회원ID (8byte) 파일의 HashKey (64byte) 파일요청 파일길이+8 FILE_TRANSFER 파일내용 가변길이 파일 전송 4. 패킷 • 패킷은 크게 두 부분으로 나뉜다. ( 헤더와 데이터 ) • 헤더에는 반드시 전체 패킷의 크기가 들어가야 한다. • 한 패킷을 잘라 오기 위하여 • 패킷 헤더는 일반적으로 어떠한 패킷이던지 동일한 길이로 구성한다.

  20. 18. 소켓 초기화

  21. 1. WSAStartup함수 • 윈도우 소켓을 초기화한다. • Ws2_32.dll함수를 응용 프로그램의 영역으로 로드한다. WSADATA wsaData; WSAStartup(MAKEWORD(2,2), &wsaData); • WSADATA구조체 변수는 WSAStartup함수가 반환하는 윈도우 소켓의 세부 정보를 가져 온다. • 첫 번째 인자에는 소켓 라이브러리의 버전을 저장한다. • 하위 바이트에는 메이저 버전 : 2 • 상위 바이트에는 마이너 버전 : 2 • MAKEWORD(하위, 상위) • MAKEWORD(3,5) : 이 코드는 윈도우 버전 3.5를 의미한다.

  22. 2. WSACleanup함수 • 윈도우 소켓을 종료하는 함수이다. • Ws2_32.dll을 사용하지 못하게 한다. WSACleanup();

  23. 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자료형을 호스트 바이트 순서로 변환한다.

  24. 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주소로 변환

  25. 19. 파일 전송

  26. 1. TransmitFile함수 BOOLTransmitFile( SOCKEThSocket, HANDLEhFile, DWORDnNumberOfBytesToWrite, DWORDnNumberOfBytesPerSend, LPOVERLAPPEDlpOverlapped, LPTRANSMIT_FILE_BUFFERSlpTransmitBuffers, DWORDdwFlags ); • hSocket : 파일을 보낼 소켓의 핸들 • hFile : 전송할 파일의 핸들 • nNumberOfBytesToWrite : 전송할 양으로 파일 전체를 전송할 때는 0을 사용한다. • nNumberOfBytesPerSend : 한 번에 전송할 패킷의 크기. 패킷의 크기를 시스템에 맡길 경우, 0을 사용한다. • lpOverlapped : 중첩 입출력 구조체로 비동기 작업을 수행할 수 있도록 한다. • lpTransmitBuffers : 파일을 전송하기 전에 전송할 헤더와 전송 후에 전송할 테일을 가리키는 구조체 포인터이다.

  27. #include <winsock2.h> #include <windows.h> #include "resource.h" #include <commctrl.h> #include <Mswsock.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); } 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); }

  28. 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); SetWindowText(hEdit1,"클라이언트 접속을 기다리고 있습니다."); } return TRUE ;

  29. 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_SEQUENTIAL_SCAN,NULL); if (hFile == INVALID_HANDLE_VALUE) { DispErrorMessage(); return TRUE; }

  30. 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); SetWindowText(hEdit1,"파일 전송을 완료했습니다."); return TRUE; } case IDOK : case IDCANCEL : closesocket(hServerSock); closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ; }

  31. #include <winsock2.h> #include <windows.h> #include <commctrl.h> #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;

  32. 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; }

  33. 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,0); 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_FLAG_SEQUENTIAL_SCAN,NULL); if (hFile == INVALID_HANDLE_VALUE) { DispErrorMessage(); return TRUE; } BYTE pFileBuf[1024]; nTotalSize = transstruct.nFileSize; nTotalRecv = 0;

  34. 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,0); nTotalRecv += nReceived; }while(nTotalSize != nTotalRecv); SetWindowText(hEdit1,"파일 수신을 완료했습니다."); return TRUE; } case IDOK : case IDCANCEL : closesocket(hClientSock); EndDialog (hDlg, 0) ; return TRUE ; } break ; } return FALSE ; }

  35. 20. 1 대 1 채팅

  36. #include <winsock2.h> #include <windows.h> #include <commctrl.h> #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; }

  37. 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 ; }

  38. 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,"서버"); }

  39. 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;

  40. 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 ; }

More Related