반응형
//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));
}반응형
"이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다."