디자인패턴 정형화된 생각을 하지 말자.
GOF 디자인패턴 - 주관적인 생각
쪽지보내기
#pragma comment(lib,"Dll")
#include "Packet.h"
#include "resource.h"
#define WM_RECV (WM_APP+1)
#define WM_SEND (WM_APP+2)
#define MYIP "192.168.34.103"
#define MYPORT 1000
#define YOURIP "192.168.34.102"
#define YOURPORT 1000
char str[256];
BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam);
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
WSADATA wsadata;
WSAStartup(MAKEWORD(2,0),&wsadata);
DialogBox(hInstance, MAKEINTRESOURCE(IDD_DIALOG1), 0, DlgProc);
WSACleanup();
return 0;
}
BOOL OnInit(HWND hDlg);
BOOL OnCommand(HWND hDlg, WORD cid, WORD cmsg, HWND cWnd);
BOOL OnSend(HWND hDlg, SOCKET sock, WORD msg, WORD eid);
BOOL OnRecv(HWND hDlg, SOCKET sock, WORD msg, WORD eid);
void SendStart(HWND hDlg);
BOOL CALLBACK DlgProc(HWND hDlg, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
switch(iMessage)
{
case WM_INITDIALOG: return OnInit(hDlg);
case WM_COMMAND: return OnCommand(hDlg, LOWORD(wParam), HIWORD(wParam), (HWND)lParam);
case WM_SEND: return OnSend(hDlg, (SOCKET)wParam, LOWORD(lParam), HIWORD(lParam));
case WM_RECV: return OnRecv(hDlg, (SOCKET)wParam, LOWORD(lParam), HIWORD(lParam));
}
return FALSE;
}
BOOL OnInit(HWND hDlg)
{
SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
SOCKADDR_IN servaddr={0,};
servaddr.sin_addr.s_addr = inet_addr(MYIP);
servaddr.sin_port = htons(MYPORT);
servaddr.sin_family = PF_INET;
bind(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
listen(sock,5);
WSAAsyncSelect(sock,hDlg,WM_RECV,FD_ACCEPT|FD_CLOSE);
//sock에 accept준비가 되거나 closesocket을 해야 할 상태가 오면
//hDlg윈도우에 WM_RECV 메시지를 보내 주세요.
return TRUE;
}
BOOL OnCommand(HWND hDlg, WORD cid, WORD cmsg, HWND cWnd)
{
switch(cid)
{
case IDOK:
GetDlgItemText(hDlg, IDC_EDIT1, str , 256);
SendStart(hDlg);
break;
case IDCANCEL: EndDialog(hDlg, IDCANCEL);
break;
}
return TRUE;
}
void SendStart(HWND hDlg)
{
SOCKET sock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
SOCKADDR_IN servaddr={0,};
servaddr.sin_addr.s_addr = inet_addr(YOURIP);
servaddr.sin_port = htons(YOURPORT);
servaddr.sin_family = PF_INET;
WSAAsyncSelect(sock,hDlg,WM_SEND,FD_CONNECT);
connect(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
//WSAAsyncSelect 함수가 호출되고 나서, 접속요청 작업의 완료가 있었던 경우.
//connect 함수가 호출되고 난 후에 접속 작업이 완료되었을 때.
}
void OnConnect(HWND hDlg, SOCKET sock, WORD eid);
void OnWrite(HWND hDlg, SOCKET sock, WORD eid);
void OnClose2(HWND hDlg,SOCKET sock,WORD eid);
BOOL OnSend(HWND hDlg, SOCKET sock, WORD msg, WORD eid)
{
switch(msg)
{
case FD_CONNECT: OnConnect(hDlg, sock, eid); break;
case FD_WRITE: OnWrite(hDlg, sock, eid); break;
case FD_CLOSE: OnClose2(hDlg, sock, eid); break;
}
return TRUE;
}
void OnConnect(HWND hDlg, SOCKET sock, WORD eid)
{
WSAAsyncSelect(sock,hDlg,WM_SEND,FD_WRITE);
// connect 나 accept 함수가 호출되고 나서, 접속이 완료 되었을 때
}
void OnWrite(HWND hDlg, SOCKET sock, WORD eid)
{
int slen = strlen(str);
MsgHead msg(0);
int bodylen = sizeof(slen) + slen;
msg.SetBlen(bodylen);
Packet *pack = new Packet();
pack->Pack(&msg, sizeof(MsgHead));
pack->Pack(&slen, sizeof(int));
pack->Pack(str, slen);
pack->Send(sock);
WSAAsyncSelect(sock,hDlg,WM_SEND,FD_CLOSE);
}
void OnClose2(HWND hDlg,SOCKET sock,WORD eid)
{
DWORD nrecv;
if(ioctlsocket(sock,FIONREAD,&nrecv)==0)
{
if(nrecv)
{
PostMessage(hDlg,WM_SEND,sock,(eid>>16)|FD_CLOSE);
}
else
{
closesocket(sock);
}
}
}
void OnAccept(HWND hDlg, SOCKET sock, WORD eid);
void OnRead(HWND hDlg, SOCKET sock, WORD eid);
BOOL OnRecv(HWND hDlg, SOCKET sock, WORD msg, WORD eid)
{
switch(msg)
{
case FD_ACCEPT: OnAccept(hDlg, sock, eid); break;
case FD_READ: OnRead(hDlg, sock, eid); break;
case FD_CLOSE: OnClose2(hDlg, sock, eid); break;
}
return TRUE;
}
void OnAccept(HWND hDlg, SOCKET sock, WORD eid)
{
SOCKADDR_IN cliaddr = {0, };
int len = sizeof(cliaddr);
SOCKET dosock;
dosock = accept(sock, (SOCKADDR*)&cliaddr, &len);
WSAAsyncSelect(dosock, hDlg, WM_RECV, FD_READ|FD_CLOSE);
//Read
//WSAAsyncSelect 함수가 호출 되고나서, 수신할수 있는 데이터가 있을 때
//데이터가 로컬 호스트로 도착하고, FD_READ 가 아직 포스팅되지 않았을 때
//Close
Note : closesocket 함수를 호출하고 난 후에 FD_CLOSE 메시지는 포스팅 되지 않습니다.
}
void OnRead(HWND hDlg, SOCKET sock, WORD eid)
{
int len;
char r_str[256];
memset(r_str,0, 256);
MsgHead msg;
if(recv(sock,(char *)&msg,sizeof(MsgHead),0)<=0) //recv시 false 값에대한 예외처리
//안할경우 수신버퍼에 데이터가 남아있어서 OnRead가 또 실행될수있다.
{
return;
}
Packet *pack = new Packet(sock, msg.Getblen());
pack->UnPack(&len, sizeof(len));
pack->UnPack(r_str, len);
MessageBox(hDlg, r_str , "", MB_OK);
//WSAAsyncSelect(sock, hDlg, WM_RECV, FD_CLOSE); 받을 때는 Close를 해주지 않는다.
}
EventSelect(서버) (0) | 2010.02.05 |
---|---|
EventSelect란? (0) | 2010.02.05 |
소켓통신의 라이브러리 사용 선택 시 고려사항 (0) | 2010.02.02 |
소켓함수 예제(로그인서버) (0) | 2010.01.25 |
소켓통신(함수정리) (1) | 2010.01.18 |
사칙연산 예제
Dll 헤더파일
#ifndef __CAL_H
#define __CAL_H
#include <windows.h>
#ifdef DLLEXPORT
#define DLLTYPE __declspec(dllexport)
#define DLLTYPE2 extern "C" __declspec(dllexport)
#else
#define DLLTYPE __declspec(dllimport)
#define DLLTYPE2 extern "C" __declspec(dllimport)
#endif
class DLLTYPE Cal
{
public:
int Calplus(int Num1, int Num2);
int Cal::CalMinus(int Num1, int Num2);
int Cal::CalMul(int Num1, int Num2);
int Cal::CalDiv(int Num1, int Num2);
};
#endif __CAL_H
DLL CPP파일
#define DLLEXPORT
#include "Cal.h"
int Cal::Calplus(int Num1, int Num2)
{
return (Num1 + Num2);
}
int Cal::CalMinus(int Num1, int Num2)
{
return (Num1 - Num2);
}
int Cal::CalMul(int Num1, int Num2)
{
return (Num1 * Num2);
}
int Cal::CalDiv(int Num1, int Num2)
{
return (Num1 / Num2);
}
#define DLLEXPORT을 선언하였다. 헤더파일에도 정의되어있기때문에 조건문에서 export로 되어서 수출하게된다.
사용파일
#pragma comment(lib, "Dll연습")
#include "Cal.h"
#include <stdio.h>
void main()
{
Cal cal;
cal.Calplus(2,4);
printf("result = %d\n", cal.Calplus(2,4));
printf("result = %d\n", cal.CalMinus(2,4));
printf("result = %d\n", cal.CalMul(2,4));
printf("result = %d\n", cal.CalDiv(2,4));
}
여기서는 Cal.h 를 인클루드만해서 쓰게 됨으로 DLLEXPORT가 중복이 안되서 조건문에서 import로 빠지게된다.
즉, 사용하겠다는 뜻이다.
프로세스 (0) | 2010.02.10 |
---|---|
ATOM (0) | 2010.02.09 |
리스트뷰 (0) | 2010.02.03 |
WM_USER And WM_APP (0) | 2010.02.02 |
레지스트리 (0) | 2010.02.02 |
리스트뷰 - ListBox가 발전된 형태로 좀 더 깔끔하고 다양한 기능을 사용할 수 있다.
리스트뷰 함수정리
ListView_GetItemCount() : 등록된 항목의 개수
ListView_InsertItem() : 새 항목 등록
ListView_SetItem() : 항목의 정보를 변경(이미지 등)
ListView_SetItemText() : 항목의 문자열을 변경
ListView_DeleteItem() : 지정한 항목을 삭제
ListView_DeleteAllItems() : 전체 항목을 삭제
ListView_GetItemText() : 지정한 항목의 문자열을 얻어옴
ListView_GetNextItem() : 옵션에 해당하는 항목의 인덱스 반환
ListView_FindItem() : 제시한 조건과 일치하는 항목의 인덱스 반환
ListView_SetItemState() : 지정한 항목의 상태 변경(포커스 등)
LVCOLUMN 구조체 - LVCOLUMN 구조체에 헤더의 정보를 채운 뒤 LVM_INSERTCOLUMN 메시지 전송
LVITEM 구조체 - LVITEM 구조체에 항목의 정보를 채운 뒤 LVM_INSERTITEM 메시지 전송
#include <windows.h>
#include <commctrl.h>
#define IDC_LISTVIEW 150
#define LVIF_TEXT 151
LVCOLUMN COL; //열 구조체
LVITEM LI; //항목 구조체
HWND hList;
void OnInitCOL(HWND hWnd)
{
hList = CreateWindow(WC_LISTVIEW,NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT, 150,18,240,60,hWnd,(HMENU)IDC_LISTVIEW,0,0);
ListView_SetExtendedListViewStyle(hList,LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES);
//리스트뷰 스타일 초기화
COL.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
COL.fmt = LVCFMT_LEFT;
COL.cx=80;
COL.pszText="가";
COL.iSubItem=0;
ListView_InsertColumn(hList,0,&COL);
//첫번째 : 해당 리스트 핸들
//두번째 : 몇번째 열인지
//세번째 : 해당 열의 초기화상태
COL.cx=80;
COL.pszText="나";
COL.iSubItem=1;
ListView_InsertColumn(hList,1,&COL);
COL.cx=80;
COL.pszText="다";
COL.iSubItem=2;
ListView_InsertColumn(hList,2,&COL);
}
void OnInitITEM()
{
LI.mask = LVIF_TEXT;
LI.iItem = 1; //행 (전체 화면 - 캡션포함)
LI.iSubItem = 0; //열
LI.pszText = "1"; //문자열 값
ListView_InsertItem(hList, &LI);
//초기화된 항목구조체 정보를 토대로 해당리스트에 삽입
ListView_SetItemText(hList, 0, 1, "2");
//첫번째: 해당 리스트 핸들
//두번째 : 행 (캡션 미 포함)
//세번째 : 열
//네번째 : 값
ListView_SetItemText(hList, 0, 2, "3");
LI.iItem = 2;
LI.pszText = "4";
ListView_InsertItem(hList, &LI);
ListView_SetItemText(hList, 1, 1, "5");
ListView_SetItemText(hList, 1, 2, "6");
LI.iItem = 3;
LI.pszText = "7";
ListView_InsertItem(hList, &LI);
ListView_SetItemText(hList, 2, 1, "8");
ListView_SetItemText(hList, 2, 2, "9");
}
결과
ATOM (0) | 2010.02.09 |
---|---|
간단한 DLL 예제 (1) | 2010.02.03 |
WM_USER And WM_APP (0) | 2010.02.02 |
레지스트리 (0) | 2010.02.02 |
o/s의 role (0) | 2010.01.28 |
#define WM_MYMESSAGE WM_APP+1
이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다. WM_USER도 사용자 정의 메시지를 정의하는 용도로 사용되지만 표준 컨트롤중에 이미 WM_USER를 사용하는 컨트롤이 있으므로 중복될 위험성이 있다. 반면 WM_APP는 시스템이 전혀 이 영역을 사용하지 않고 있으므로 중복될 위험이 전혀 없으며 응용 프로그램간의 통신에 사용하기에 적합하다. 두 응용 프로그램의 약속에 의해 WM_APP+n 메시지를 정의하여 사용하면 된다.
WM_USER는 윈도우 클래스를 위한 사용자 정의 메시지이며 WM_APP는 응용 프로그램을 위한 사용자 정의 메시지라는 점이 다르다. 그러나 이 구분은 어디까지나 권장 사항일 뿐이지 강제 사항은 아니다. WM_USER를 응용 프로그램간의 통신에 사용하더라도 충돌이 없다는 확신만 있다면 가능하다. 다만 잠재적인 충돌 가능성이 있을 수 있다는 것을 고려할 때 바람직하지는 않다.
정리
간단한 DLL 예제 (1) | 2010.02.03 |
---|---|
리스트뷰 (0) | 2010.02.03 |
레지스트리 (0) | 2010.02.02 |
o/s의 role (0) | 2010.01.28 |
파일매핑예제 (0) | 2010.01.25 |
정보의 저장
¢ 프로그램은 실행 중에 사용자가 입력한 옵션 설정이나 프로그램 스스로 만들어낸 정보들을 다음 실행을 위해 그 정보를 저장 해두어야 한다.
¢ 이런 정보는 사용자의 정보가 아니라 프로그램 자신의 정보이다
¢ 프로그램의 설정 정보를 저장하는 방법에는 INI파일을 쓰는 방법과 레지스트리를 쓰는 방법이 있다.
레지스트리의 특징
¢ 윈도우의 환경설정에 대한 모든 정보가 저장되어 관리되고 있는 Windows의 핵심적인 데이터베이스이다.
¢ 다중 환경설정을 저장할 수 있다.
¢ INI 파일과 달리 크기가 64KB를 초과할 수 있다.
¢ INI 파일에 비해 속도가 빠르다.
¢ 백업 및 복구가 간단하다.
레지스트리의 구조
¢ 레지스트리는 디렉토리 구조와 유사한 계층적 구조로 구성
¢ 각각의 가지(레지스트리 편집기에서 폴더 아이콘으로 표시되는)는 키라고 부르며, 각각의 키는 하위키를 포함할 수 있으며, 각각의 키는 값을 포함할 수 있다.
¢ 이 값에 레지스트리에 저장되는 실제 정보가 저장됨
레지스트리 키 생성 함수
hKey : 새로 만들어지는 부모키 지정
- HKEY_CLASSES_ROOT : 응용 프로그램을 위한 OLE정보와 모든 파일유형 정보 저장
- HKEY_CURRENT_USER : 현재 로그인한 사용자를 위한 정보 저장
- HKEY_LOCAL_MACHINE : 컴퓨터에 설치된 하드웨어와 소프트웨어에 대한 모든 정보 저장
- HKEY_USERS : 컴퓨터를 사용하는 사용자 각각에 대한 속성을 저장
- HKEY_CURRENT_CONFIG : 현재 하드웨어의 설정을 저장
lpSubKey : 만들고자 하는 서브키를 지정하는 널 종료 문자열로 반드시 지정해야 함.
hKey 서브에 여기서 지정한 키가 생성됨.
Reserved : 예약된 인수, 0으로 지정
lpClass : 생성되는 키의 클래스를 지정하는 문자열
dwOptions : 생성하는 키의 옵션
- REG_OPTION_NON_VOLATILE : 레지스트리에 저장되는 정보는 파일에
영구 저장되므로 재부팅해도 정보 유지
samDesired : 보안속성
- KEY_ALL_ACCESS : 읽기, 쓰기 할 때 사용
- KEY_WRITE : 쓰기, KEY_READ : 읽기
lpSecurityAttribute : 생성된 키값이 상속될 것인가 지정하는 인수, NULL이면 상
속되지 않음
phkResult : 만들어지거나 열려진 키값이 대입되는 변수 포인터
여기에 HKEY구조체 변수를 대입
lpdwDisposition : 키가 새로 생성되었는지 기존의 키가 오픈된 것인지 리턴받기
위한 출력용 변수
열려진 키에 값을 저장하는 함수
hKey : 값을 저장하고자 하는 키 핸들(현재 열려진 키)
lpValueName : 값의 이름
Reserved : 이 인수는 사용하지 않음
dwType : 값의 데이터 타입을 지정 (대부분의 정보를 저장할 수 있다)
- REG_BINARY : 이진 데이터
- REG_SZ : 문자열
lpData : 저장하고자 하는 데이터의 포인터
cbData : 데이터의 크기
저장한 위치의 값을 읽어오는 함수
hKey : 값을 저장하고자 하는 키 핸들(현재 열려진 키)
lpValueName : 값의 이름
lpReserved : 이 인수는 사용하지 않음
lpType : 읽은 값의 타입을 대입받을 변수의 포인터
lpcbData : 실제 복사된 데이터의 크기를 리턴, 대입받을 변수의 크기를 대입
RegCreateKeyEx(), RegSetValueEx(), RegQueryValueEx() 이 함수들은 제대로 읽거나 저장
했다면 ERROR_SUCCESS(0)가 리턴 된다
열려진 레지스트리 키를 닫는 함수
레지스트리 키도 메모리를 소모하므로 사용하고 난 후에는 해제를 해야함
실습예제
#include <windows.h>
#include "resource.h"
BOOL CALLBACK DlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam);
#define CURRENT HKEY_CURRENT_USER
#define KEY "SoftWare\\Bit\\Test\\"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nShowcmd)
{
DialogBox(hInstance,MAKEINTRESOURCE(IDD_DIALOG1),0,DlgProc);
return 0;
}
BOOL CALLBACK DlgProc(HWND hDlg,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
TCHAR str[256];
HKEY key;
DWORD dwDisp;
DWORD Size; //불러올때 사이즈
switch(iMessage)
{
case WM_INITDIALOG: break;
case WM_COMMAND:
switch(LOWORD(wParam))
{
case IDOK: //저장하기
GetDlgItemText(hDlg, IDC_EDIT1, str, 256);
RegCreateKeyEx(CURRENT, KEY"Edit",0,NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE, 0,&key, &dwDisp);
RegSetValueEx(key, "STR", 0, REG_SZ, (LPBYTE)str, strlen(str)+1);
RegCloseKey(key);
break;
case IDOK2: //불러오기
RegCreateKeyEx(CURRENT, KEY"Edit",0,NULL, REG_OPTION_NON_VOLATILE,KEY_READ,0, &key, &dwDisp);
RegQueryValueEx(key, "STR", 0, NULL, (LPBYTE)str, &Size);
MessageBox(hDlg, str, "", MB_OK);
RegCloseKey(key);
break;
case IDCANCEL:
EndDialog(hDlg,IDCANCEL);
break;
}
return TRUE;
}
return FALSE;
}
리스트뷰 (0) | 2010.02.03 |
---|---|
WM_USER And WM_APP (0) | 2010.02.02 |
o/s의 role (0) | 2010.01.28 |
파일매핑예제 (0) | 2010.01.25 |
WNDCLASS 구조체 (0) | 2010.01.25 |
1. Listen Thread + n개의 Thread(1 Client를 위해 1개의 Thread)
- Personal Computer상에서 개인 용도의(중요도가 적은) Server를 운용할 때
- Client와 Server간의 흐름이 지속적일 때
*소켓 통신외에 다른 작업은 별도의 쓰레드에게 관리를 하자.
장점
Client 1개와의 통신에 대한 논리만 생각할 수 있게 해 준다.
단점
쓰레드의 생성과 소멸에 대한 비용이 많이 든다.
context/switching에 대한 비용이 많이 든다.
2. AsyncSelect
- 소켓 통신외에 다른 작업이 병행되어야 할 경우
- Client와 Server간의 흐름이 단발적일 때
- 해당 쓰레드에 메시지를 받을 수 있는 window가 존재할 때
*눈에 보이지 않는 빈껍데기 msessage window여도 상관 없음
장점
소켓 통신을 위한 별도의 쓰레드 자원을 사용하는 비용이 필요없다.
받은 패킷 종류에 따라 나누어서 해당 패킷에 대해서 작성을 해 나갈 수 있다.
단점
패킷 처리에 드는 비용이 많이 드는 경우에 비효율적이 될 수 있다.
받은 패킷 종류에 따라 나누어서 해당 패킷에 대해서 작성을 하지 않으면 비효율적이 될 수 있다.
다수의 CPU를 장착한 시스템에서 모든 CPU를 사용하지 않게 된다.
3. EventSelect
- 소켓 통신외에 다른 작업이 병행되어야 할 경우
- Client와 Server간의 흐름이 단발적일 때
- 해당 쓰레드에 메시지를 받을 수 있는 window가 존재하지 않을 때
장점
소켓 통신을 위한 별도의 쓰레드 자원을 사용하는 비용이 필요없다.
받은 패킷 종류에 따라 나누어서 해당 패킷에 대해서 작성을 해 나갈 수 있다.
단점
패킷 처리에 드는 비용이 많이 드는 경우에 비효율적이 될 수 있다.
어느 정도의 Polling이 따르게 된다.
받은 패킷 종류에 따라 나누어서 해당 패킷에 대해서 작성을 하지 않으면 비효율적이 될 수 있다.
다수의 CPU를 장착한 시스템에서 모든 CPU를 사용하지 않게 된다.
4. Overlapped I/O
- Personal Computer상에서 Server를 운용할 때
* 소켓 통신외에 다른 작업이 병행되어야 될 경우에는 세심한 주의가 필요하거나 다른 방법을 찾아보자.
장점
소켓 통신을 위한 별도의 쓰레드 자원을 사용하는 비용이 적게 든다.
비동기 소켓 통신이기 때문에 많은 client에 많은 패킷 흐름을 효율적으로 사용할 수 있다.
단점
다수의 CPU를 장착한 시스템에서 모든 CPU를 사용하지 않게 된다.
5. IOCP
- Server System에 O/S가 Windows O/S일 경우
- 다른 응용이 동작할 개연성이 매우 적을 경우
장점
다수의 CPU를 장착한 시스템에서 모든 CPU를 Full로 사용할 수 있다.
단점
CPU를 사용하는 다른 응용이 많을 경우 큰 이득이 없다.
EventSelect란? (0) | 2010.02.05 |
---|---|
ASyncSelect 예제 (1) | 2010.02.04 |
소켓함수 예제(로그인서버) (0) | 2010.01.25 |
소켓통신(함수정리) (1) | 2010.01.18 |
OSI 모델 And Ip계층 (0) | 2010.01.18 |
WM_USER And WM_APP (0) | 2010.02.02 |
---|---|
레지스트리 (0) | 2010.02.02 |
파일매핑예제 (0) | 2010.01.25 |
WNDCLASS 구조체 (0) | 2010.01.25 |
스레드의 함정 (0) | 2010.01.25 |
#pragma comment(lib , "dll.lib")
#include "Packet.h"
#include "Channel.h"
#include <stdio.h>
///////////////////////////////////////////////////////////////
typedef struct MemberInFo
{
char *Id;
char *Pass;
char *Name;
int Idlen;
int Passlen;
int Namelen;
int C_Port;
int SmsPort;
int FilePort;
LONG C_Ip;
}MemberInFo;
MemberInFo * member = new MemberInFo();
////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////
void Load(); //Log서버 초기화 후 대기
DWORD WINAPI Send(LPVOID temp); //Login 과 Logout에게 DB서버 정보 전송
void LoginReq(Packet * pack, MsgHead msg, SOCKET sock_Log, SOCKET sock_Db);
void LoginPack(SOCKET sock_Db); //로그인 팩
void LoginUnPack(Packet * pack); //로그인 언팩
void LogoutReq(Packet * pack, MsgHead msg, SOCKET sock_Db);
int SearchAck(SOCKET sock_Log); //DB로부터 값을 받아서 리턴
void SetState(); //아이디가 있을경우 State 서버로 회원포트정보 등 전송
void SendState(Packet *Pack); //State 서버 초기화
///////////////////////////////////////////////////////////////////
int main()
{
WSADATA wsaData;
WSAStartup(MAKEWORD(2,2), &wsaData);
AllocConsole();
freopen("conout$","wt",stdout);
while(1)
{
Load();
}
WSACleanup();
delete member;
return 0;
}
void Load()
{
DWORD ThreadID;
SOCKET sock_Log = OpenSocket(LOGSV_IP_ADDR, S_LOG);
SOCKADDR_IN clientaddr={0,};
int len = sizeof(clientaddr);
SOCKET dosock;
while(1)
{
printf("대기중\n");
dosock = accept(sock_Log,(SOCKADDR *)&clientaddr,&len);
CloseHandle(CreateThread(NULL,0,Send,(LPVOID)dosock,0,&ThreadID));
}
closesocket(dosock);
closesocket(sock_Log);
}
DWORD WINAPI Send(LPVOID temp)
{
SOCKET sock_Log = (SOCKET)temp;
MsgHead msg(sock_Log); // Msgid 와 Bodylen을 가져온다. 4 + 4
Packet * pack = new Packet(sock_Log, msg.Getblen()); // Bodylen 만큼 데이터를 가져온다
printf("%d", msg.GetMsgid());
int msgid = msg.GetMsgid();
SOCKET sock_Db = OpenSocket(DBM_IP_ADDR, S_DBM,0); //Db 와의 연결
switch(msgid)
{
case LOGIN: LoginReq(pack, msg, sock_Log, sock_Db); break;
case LOGOUT: LogoutReq(pack, msg, sock_Db); break;
default: break;
}
closesocket(sock_Log);
return 0 ;
}
void LoginReq(Packet * pack, MsgHead msg, SOCKET sock_Log, SOCKET sock_Db)
{
int Ack;
LoginUnPack(pack);
LoginPack(sock_Db);
if((Ack = SearchAck(sock_Db)))
{
send(sock_Log, (char*)&Ack, sizeof(int), 0);
SetState();
closesocket(sock_Log);
}
else
{
send(sock_Log, (char*)&Ack, sizeof(int), 0);
closesocket(sock_Log);
}
delete pack;
closesocket(sock_Db);
}
void LoginUnPack(Packet * pack)
{
pack->UnPack(&member->Idlen, sizeof(member->Idlen));
member->Id = new char[member->Idlen];
pack->UnPack(member->Id, member->Idlen);
pack->UnPack(&member->Passlen, sizeof(member->Passlen));
member->Pass = new char[member->Passlen];
pack->UnPack(member->Pass, member->Passlen);
pack->UnPack(&member->C_Ip, sizeof(member->C_Ip));
pack->UnPack(&member->C_Port, sizeof(member->C_Port));
pack->UnPack(&member->SmsPort, sizeof(member->SmsPort));
pack->UnPack(&member->FilePort, sizeof(member->FilePort));
printf("ID:%s, Pass:%s, IP:%d, C_Port:%d, SPort:%d, FPort:%d", member->Id, member->Pass, member->C_Ip, member->C_Port, member->SmsPort, member->FilePort);
}
void LoginPack(SOCKET sock_Db)
{
MsgHead msg2(LOGIN);
int bodysize = sizeof(member->Idlen) + member->Idlen + sizeof(member->Passlen) + member->Passlen;
msg2.SetBlen(bodysize);
Packet * pack2 = new Packet();
pack2->Pack(&msg2, sizeof(MsgHead));
pack2->Pack(&member->Idlen, sizeof(member->Idlen));
pack2->Pack(member->Id, member->Idlen);
pack2->Pack(&member->Passlen, sizeof(member->Passlen));
pack2->Pack(member->Pass, member->Passlen);
pack2->Send(sock_Db);
delete pack2;
}
void LogoutReq(Packet * pack, MsgHead msg, SOCKET sock_Db)
{
pack->RePack(&msg, sizeof(MsgHead));
pack->Send(sock_Db);
SendState(pack);
delete pack;
closesocket(sock_Db);
}
int SearchAck(SOCKET sock_Log) //db로부터 받은 True False 반환!
{
int re;
recv(sock_Log, (char*)&re, sizeof(int),0);
printf("\n%d", re);
return re;
}
void SetState()
{
MsgHead msg(LOGIN);
int bodysize = sizeof(member->Idlen) + member->Idlen + sizeof(member->C_Ip) + sizeof(member->C_Port) + sizeof(member->SmsPort) + sizeof(member->FilePort);
msg.SetBlen(bodysize);
Packet * pack = new Packet();
pack->Pack(&msg, sizeof(MsgHead));
pack->Pack(&member->Idlen, sizeof(member->Idlen));
pack->Pack(member->Id, member->Idlen);
pack->Pack(&member->C_Ip , sizeof(member->C_Ip));
pack->Pack(&member->C_Port, sizeof(member->C_Port));
pack->Pack(&member->SmsPort, sizeof(member->SmsPort));
pack->Pack(&member->FilePort, sizeof(member->FilePort));
printf("SetState : %d, %d\n",member->C_Ip,member->C_Port);
SendState(pack);
delete pack;
}
void SendState(Packet *Pack)
{
SOCKET sock_State = OpenSocket(STATESV_IP_ADDR, S_STATE,0); //스테이트 서버와 연결
Pack->Send(sock_State);
closesocket(sock_State);
}
EventSelect란? (0) | 2010.02.05 |
---|---|
ASyncSelect 예제 (1) | 2010.02.04 |
소켓통신의 라이브러리 사용 선택 시 고려사항 (0) | 2010.02.02 |
소켓통신(함수정리) (1) | 2010.01.18 |
OSI 모델 And Ip계층 (0) | 2010.01.18 |
- 파일 오픈 hF=CreateFile("test.txt")
- 파일 내용을 메모리에 올린다 hMapF=CreateFileMapping(hF)
- 메모리에 올려진 첫번째 주소를 얻는다. pF=MapViewOfFile(hMapF)
- 첫번째 주소로 메모리 내용을 조작한다.
- 중간중간에 변경된 내용을 강제로 디스크에 쓰게만든다. FlushViewOfFile(pF)
- 해제. UnmapViewOfFile(pF);
- 해제. CloseHandle(hMapF);
- 파일 닫기. CloseHandle(hF);
<예제>
#include <windows.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
HANDLE hF, hMapF;
DWORD fSize, i;
char *pF, *pFtmp;
hF=CreateFile("test.txt",GENERIC_READ|GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
fSize=GetFileSize(hF,NULL);
hMapF=CreateFileMapping(
hF, //file handle
NULL,
PAGE_READWRITE,
0, //file size
0, //file size
NULL); //map name
if(hMapF==NULL)
{
printf("CreateFileMapping() fail");
CloseHandle(hF);
return 1;
}
pF=MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,0);
pFtmp=pF;
for(i=0;i<fSize;i++)
{
*pFtmp=(*pFtmp+1);
pFtmp++;
}
//메모리 내용을 강제로 파일에 쓴다.
FlushViewOfFile(pF, 0);
UnmapViewOfFile(pF);
CloseHandle(hMapF);
CloseHandle(hF);
return 0;
}
Share Memory를 만드는 프로세스:
CreateFileMapping->MapViewOfFile->UnmapViewOfFile->CloseHandle
OpenFileMapping->MapViewOfFile->UnmapViewOfFile->CloseHandle
<예제>
<공유메모리를 만들고 공유메모리에 데이터를 써넣는 프로그램>
#include <windows.h>
#include <stdio.h>
#pragma pack(1)
typedef struct tag_SMTEST
{
char c;
int i;
short s;
} SMTEST;
int main(int argc, char *argv[])
{
HANDLE hMapF;
SMTEST *psm;
// JJBSMTEST라는 이름으로 공유메모리를 만든다.
hMapF=CreateFileMapping(
INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof(SMTEST),
"JJBSMTEST");
if(hMapF==NULL)
{
printf("CreateFileMapping() fail");
return 1;
}
psm=(SMTEST *)MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,sizeof(SMTEST));
//이후부터 psm 포인터만 읽으면 파일의 내용을 자유롭게 액세스할 수 있다.
// 파일이 프로세스의 주소 공간에 맵되어 있으므로 포인터를사용하면 연결된 파일의 원하는 부분을 읽을 수 있다.
psm->c='a';
psm->i=100;
psm->s=10;
//아래 프로그램을 실행할수있게 시간을 주자
Sleep(10000);
UnmapViewOfFile(psm);
CloseHandle(hMapF);
return 0;
}
<예제>
<공유메모리에 접근하여 데이터를 출력하는 프로그램.>
#include <windows.h>
#include <stdio.h>
#pragma pack(1)
typedef struct tag_SMTEST
{
char c;
int i;
short s;
} SMTEST;
int main(int argc, char *argv[])
{
HANDLE hMapF;
SMTEST *psm;
// JJBSMTEST라는 이름으로 공유메모리에 접근한다.
hMapF=OpenFileMapping(FILE_MAP_ALL_ACCESS, FALSE, "JJBSMTEST");
if(hMapF==NULL)
{
printf("OpenFileMapping() fail");
return 1;
}
psm=(SMTEST *)MapViewOfFile(hMapF,FILE_MAP_ALL_ACCESS,0,0,sizeof(SMTEST));
//공유메모리에 설정된 내용을 출력한다.
printf("c:%c i:%d, s:%d\n",psm->c,psm->i,psm->s);
UnmapViewOfFile(psm);
CloseHandle(hMapF);
return 0;
}
<예제> 파일을 메모리에 올려놓고 마음대로 불러다 쓴다.
typedef struct Member
{
char Id[256];
char name[256];
}Member;
Member * member;
Member mem[1000];
void Init()
{
int i=0;
for(i=0; i<1000; i++)
{
strcpy(mem[i].Id, "22");
strcpy(mem[i].name, "22");
}
}
void FileSet()
{
DWORD dwWritten;
hFile = CreateFile("c:\\jinyong.dat", GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
if(hFile!=INVALID_HANDLE_VALUE)
{
WriteFile(hFile, mem, sizeof(Member)*1000, &dwWritten, 0);
}
CloseHandle(hFile);
}
void Mapping()
{
HANDLE hFile2;
int i=0;
hFile2 = CreateFile("c:\\jinyong.dat", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
if(hFile2 != INVALID_HANDLE_VALUE)
{
hMap = CreateFileMapping(hFile2, NULL, PAGE_READWRITE, 0, 0, NULL);
member = (Member *)MapViewOfFile(hMap, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}
printf("%s\n",member[2].Id);
printf("%s\n",member[3].name);
}
레지스트리 (0) | 2010.02.02 |
---|---|
o/s의 role (0) | 2010.01.28 |
WNDCLASS 구조체 (0) | 2010.01.25 |
스레드의 함정 (0) | 2010.01.25 |
스레드 (0) | 2010.01.24 |