'API & MFC'에 해당되는 글 48건

  1. 2010.02.05 EventSelect(서버)
  2. 2010.02.05 EventSelect란?
  3. 2010.02.04 ASyncSelect 예제 1
  4. 2010.02.03 간단한 DLL 예제 1
  5. 2010.02.03 리스트뷰
  6. 2010.02.02 WM_USER And WM_APP
  7. 2010.02.02 레지스트리
  8. 2010.02.02 소켓통신의 라이브러리 사용 선택 시 고려사항
  9. 2010.01.28 o/s의 role
  10. 2010.01.25 소켓함수 예제(로그인서버)


#pragma comment(lib,"ws2_32")
#include <winsock2.h>
#include <iostream>

using namespace std;

struct App
{
 SOCKET sarr[WSA_MAXIMUM_WAIT_EVENTS];  //WSA_MAXIMUM_WAIT_EVENTS 는 64로 정의되어있다.
 HANDLE hEarr[WSA_MAXIMUM_WAIT_EVENTS];   //64는 한 소켓이 소유할 수 있는 이벤트 객체 핸들의 최대갯수
 HANDLE hFileArr[WSA_MAXIMUM_WAIT_EVENTS];
 int now; //신호상태인 이벤트객체의 갯수
};

App app;

void AcceptProc(int index);
void ReadProc(int index);
void CloseProc(int index);

void main()
{
 WSADATA wsadata;
 WSAStartup(MAKEWORD(2,2),&wsadata);

 SOCKET sock;
 sock = socket(AF_INET,SOCK_STREAM,0);

 SOCKADDR_IN servaddr={0,};

 servaddr.sin_family = AF_INET;
 servaddr.sin_addr.s_addr = inet_addr("192.168.34.103");
 servaddr.sin_port = htons(1100);

 int re = bind(sock,(SOCKADDR *)&servaddr,sizeof(servaddr));
 re = listen(sock,5);
 app.sarr[app.now]=sock; //셋팅된 sock을 app.sarr[app.now]에 넣어준다.
 
 
 app.hEarr[app.now] = WSACreateEvent();  //이벤트객체를 생성
 WSAEventSelect(app.sarr[app.now],app.hEarr[app.now],FD_ACCEPT); 
 //app.sarr[app.now] 에서 FD_ACCEPT가 발생하면 app.hEarr[app.now]를 신호상태로 바꿔준다.

 app.now++; //생성됐으니 카운트 증가

 WSANETWORKEVENTS ev; //이벤트의 유형정보와 오류정보로 채워질 WSANETWORKEVENTS 구조체 변수


 int index;
 while(1)
 {
  index = WSAWaitForMultipleEvents(app.now,app.hEarr,FALSE,WSA_INFINITE,FALSE);
  index -= WSA_WAIT_EVENT_0;

//FALSE 이면 이벤트 객체중에서 하나라도 신호상태이면 index를 반환해준다.
//TRUE 이면 전부 신호상태이어야 반환된다.
//2개 이상 신호상태일시 인덱스 번호가 낮은 것이 반환된다.


  WSAEnumNetworkEvents(app.sarr[index],app.hEarr[index],&ev);
//이벤트가 발생한 소켓과 신호상태인 이벤트객체핸들에서 발생한이벤트의 유형정보와 오류정보가 WSANETWORKEVENTS 구조체의 주소값으로 전달된다.

  switch(ev.lNetworkEvents)
  {
  case FD_ACCEPT:
   AcceptProc(index);
   break;
  case FD_READ:
   ReadProc(index);
   break;
  case FD_CLOSE:
   CloseProc(index);
   break;
  }  
 }
 WSACleanup();
}

void AcceptProc(int index)
{
 SOCKADDR_IN clientaddr;
 int len = sizeof(clientaddr);
 SOCKET sock = app.sarr[index];
 app.sarr[app.now] = accept(sock,(SOCKADDR *)&clientaddr,&len);
 app.hEarr[app.now] = WSACreateEvent();
 WSAEventSelect(app.sarr[app.now],app.hEarr[app.now],FD_READ|FD_CLOSE);
 app.now++;
}

void ReadProc(int index)
{
 char buf[100];
 SOCKET sock = app.sarr[index];
 if(recv(sock,buf,100,0)<=0) //접속이 종료되었거나 에러가 나면 리턴
 {
  return;  
 }
 printf("%s\n", buf);
}

void CloseProc(int index)
{
 WSACloseEvent(app.hEarr[index]);
 closesocket(app.sarr[index]);

 app.now--;
 app.hEarr[index] = app.hEarr[app.now];
 app.sarr[index] = app.sarr[app.now];
}

'API & MFC > 네트워크프로그래밍' 카테고리의 다른 글

우아한 종료  (0) 2010.02.09
EventSelect(클)  (0) 2010.02.05
EventSelect란?  (0) 2010.02.05
ASyncSelect 예제  (1) 2010.02.04
소켓통신의 라이브러리 사용 선택 시 고려사항  (0) 2010.02.02
Posted by 아몰라

1.Event Select모델 이란 ?

 

 : WSAEventSelect() 함수가 핵심적인 역할을 하는데 WSAAscyncSelect와 다르게 윈도우 메세지 형태  대신 이벤트 객체를 통해서 네트워크 이벤트를 감지 하고 이벤트 객체를 관찰함으로써 스레드를 사용하지 않고도 여러 개의 소켓을 처리 가능한 네트워크 모델.

 

 

2. 동작 원리

  : 소켓과 이벤트 객체를 연결 소켓 에 대한 이벤트를 처리하는데 ,연결 이유는 발생한 이벤트를 이벤트 객체를 통해서 감지하기 위함인데 네트워크 이벤트가 발생할 때마다 이벤트 객체의 신호 상태를 통해 네트워크 이벤트 발생을 감지할 수 있다.

 

 

 

 

 

3. 입출력 절차

 

 

  WSACreateEvent() 함수를 이용하여 이벤트 객체를 생성한           .

WSAEventSelect() 함수를 이용하여 소켓에 이벤트 객체 연결 처리할 네트워크 연결

WSAWaitForMultipleEvents() 이벤트객체가 이벤트 발생유무를 확인 하기 위한 함수(신호 감지)

WSAEnumNetworkEvents() 함수를 호출하여 발생한 네트워크 이벤트 및 오류 를알아낸다

 

 

4.관련 함수 및 예제

 

1.    WSAEventSelect() 함수

 

 #include <winsock2.h>

int WSAEventSelect(SOCKET S, WSAEVENT hEventObject, long lNetworkEvents);

성공시 0, 실패시 SOCKET_ERROR 반환

SOCKET S   :   관찰대상인 소켓의 핸들 전달.

WSAEVENT hEventObject  :  이벤트 발생유무의 확인을 위한 이벤트객체 핸들

long lNetworkEvents : 감시하고자하는 이벤트의 종류 등록

 








S
에 전달된 핸들의 소켓에서 lNetworkEvents 에 전달된 이벤트중 하나가 발생하면, hEventObject에 전달된 핸들의 커널 오브젝트를 signaled(신호) 상태로 바꾸는 함수이다.

.

이벤트는 WSAAsyncSelect 모델 하고 같다.

 

 

 

 

2.    이벤트 객체 생성과 제거: WSACreateEvent(),WSACloseEvent()

 

WSAEVENT   WSACreateEvent ( ) ;

                                   성공: 이벤트 객체 핸들 리턴

                               실패: WSA_INVALID_EVENT 리턴

BOOL  WSACloseEvent (WSAEVENT hEvent) ;

                                       성공: TRUE, 실패: FALSE

 

 

 






예제 코드

 

void Doit(intindex)

{

   SOCKADDR_IN clientaddr;

   intlen = sizeof(clientaddr);

   SOCKETsock = sarr[index];

   sarr[cnt] = accept(sock,(SOCKADDR*)&clientaddr,&len);

   hEarr[cnt] = WSACreateEvent(); //이벤트 객체 생성

   WSAEventSelect(sarr[cnt],hEarr[cnt],FD_READ|FD_CLOSE);//소켓 ,객체 연결

   cnt++;

}

 

 

 











3. 이벤트 객체의 신호 상태 감지하기 :
WSAWaitForMultipleEvents() 함수

 

DWORD WSAWaitForMultipleEvents (

   DWORD cEvents,

   const WSAEVENT* lphEvents,

   BOOL fWaitAll,

   DWORD dwTimeout,

   BOOL fAlertable

) ;

          

 

 

 





DWORD cEvents, :
이벤트 객체의 수 (하나의 소켓에 여러 개의이벤트 객체가능)

const WSAEVENT* lphEvents, : 이벤트 객체의 배열의 시작 주소(최대 64개가능)

BOOL fWaitAll,: 전체 신호 상태 / 단일 신호 상태에 따른 리턴시기를 구분

(TRUE 전달시 배열안의 이벤트 객체 가 전부 신호 상태이어야 리턴 가능)

(FALSE 전달시 배열안의 이벤트 객체가 하나라도 신호 상태이어도 리턴 가능)

DWORD dwTimeout,: 신호상태 감시할 시간 설정 (WSA_INFINITE : 무한대기)

BOOL fAlertable: 입출력 완료 시기

리턴 : 리턴값에서 WSA_WAIT_EVENT_0 인 상수를 빼면 이벤트 객체배열에서 이벤트가 발생한 이벤트핸들의 인덱스 값이 된다. 2개이상일경우 에는 인덱스가 작은 것부터 값을 얻는다.

 

 

 

 

 

4.구체적인 네트워크 이벤트 알아내기 :

int WSAEnumNetworkEvents (

   SOCKET s,

   WSAEVENT hEventObject,

   LPWSANETWORKEVENTS lpNetworkEvents

) ;                        성공: 0, 실패: SOCKET_ERROR

 

 







 

  

 SOCKET s, : 이벤트가 발생한 소켓의 핸들 전달
WSAEVENT hEventObject, :  소켓과 연결된, 신호상태인 이벤트 객체핸들  LPWSANETWORKEVENTS lpNetworkEvents : 발생한 이벤트의 유형정보와 오류정보로 채워질 WSANETWORKEVENTS 구조체 변수의 주소 값 전달

 

  

 

 

예제 코드 (WSAWaitForMultipleEvents 함수,WSAEnumNetworkEvents함수)

WSANETWORKEVENTSev;

intindex;

while(1){

   index = WSAWaitForMultipleEvents (cnt,hEarr,FALSE,WSA_INFINITE,FALSE);//이벤트유무확인

   index  = index – WSA_WAIT_EVENT_0;

   WSAEnumNetworkEvents(sarr[index],hEarr[index],&ev);//구체적인 이벤트 오류 알아내기

   switch(ev.lNetworkEvents){

   caseFD_ACCEPT:

       //do it..    break;

   caseFD_READ:

       //do it..    break;

   caseFD_CLOSE:

       //do it.     break;

 

 

'API & MFC > 네트워크프로그래밍' 카테고리의 다른 글

EventSelect(클)  (0) 2010.02.05
EventSelect(서버)  (0) 2010.02.05
ASyncSelect 예제  (1) 2010.02.04
소켓통신의 라이브러리 사용 선택 시 고려사항  (0) 2010.02.02
소켓함수 예제(로그인서버)  (0) 2010.01.25
Posted by 아몰라

쪽지보내기

#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);
  }
 }
}

 

 /중요/

 //send는 수신측이 recv를 하지 않는다 하더라도 수신버퍼가 꽉차지 않으면 수행이 완료 됩니다.
 //FD_READ는 수신 버퍼에 수신 데이터가 있게 되면 발생하는 것인데 동시 1개 이상 발행하지 않게 됩니다.
 //또한 FD_READ발생시 recv를 send한번에 보낸 만큼만 받게 되는데 이후 아직 수신한 데이터가 있으면 다시 FD_READ는 발생합니다.
 //결론적으로 송신측에서 수신측이 모든 recv를 수행하지 않은 시점(데이터는 다 보냈지만)에 closesocket을 하게 되며
 //이런 경우에 FD_CLOSE가 발생을 하면 수신 버퍼에 아직 recv하지 않은 것이 있는지 확인해야 한다.

 //ioctlsocket메소드에서 두번째 인자를 FIONREAD를 주고 세번째 인자에 ULONG타입이 변수의 주소를 주면
 //세번째 인자로 넘긴 주소에 아직 처리되지 않은 수신 버퍼에 있는 데이터의 사이즈를 알 수 있습니다.
 //이들에 대한 처리보다 closesocket이 먼저 이루어지면 안 되기 때문에 메시지 큐에 FD_CLOSE를 다시 발생 시켜줌으로써
 //(현재 상황은 수신할 데이터가 있기 때문에 FD_READ에 관련 메시지가 메시지 큐에 있는데 FD_CLOSE가 먼저 수행된 것)
 //먼저 FD_READ를 수행하게 되고 다시 남은 것이 있으면 당연히 FD_READ가 내부적으로 메시지 큐에 있게 될 것입니다.
 //물론 현재 상황은 다시 FD_CLOSE 가 먼저겠지요.
 //이를 반복하다보면 결국은 수신할 데이터가 없게 되고
 //closesocket을 정상적으로 수행할 수 있는 시기가 오게 되는 것입니다.

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를 해주지 않는다.
}

Posted by 아몰라

 


사칙연산 예제

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로 빠지게된다.
즉, 사용하겠다는 뜻이다.

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

프로세스  (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
Posted by 아몰라

리스트뷰 -  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 메시지 전송

Typedef struct_LVCOLUMN{
UINT mask;  :사용될 멤버 값 설정
int fmt;  :문자열의 정렬방법과 이미지 사용여부
int cx;  :헤더의 폭
LPTSTR pszText;  :보여질 문자열
int cchTextMax;  :문자열의 크기
int iSubItem;  :연결될 항목
#if(_WIN32_IE>=0x0300)  :IE의 버전(구 버전 이미지 사용불가)
int iImage;  :보여질 이미지
int iOrder;  :헤더의 순서
#endif
}LVCOLUMN,FAR*LPLVCOLUMN;



LVITEM 구조체 -  LVITEM 구조체에 항 정보를 채운 뒤 LVM_INSERTITEM  메시지 전송

Typedef struct_LVITEM{
UINT mask;  :사용될 멤버 값 설정
int iItem;  :항목의 Index설정
int iSubItem;  :항목의 Colum Index설정
UINT state;  :항목의 상태(focus, 선택 등)
UINT stateMask;  :상태를 설정
LPTSTR pszText;  :문자열(실제 내용)
int cchTextMax;  :문자열 길이
int iImage;  :왼쪽에 보여질 이미지의 인덱스
LPARAM lParam;  :항목의 추가 저장공간
#if(_WIN32_IE>=0x0300)  : IE의 버전(구 버전 들여쓰기 사용불가)
int iIndent;  :들여쓰기
#endif
}LVCOLUMN,FAR*LPLVCOLUMN;


 
LVFINDINFO 구조체 - LVFINDINFO 구조체에 검색할 정보를 채운 뒤 LVM_FINDITEM 메시지 전송

typedef struct tagLVFINDINFOW {
UINT flags;  :
검색 형태를 지정하는 옵션
LPCWSTR psz;  :검색할 문자열
LPARAM lParam;  :검색할 32bit Data
POINT pt;  :검색할 좌표값
UINT vkDirection;  :검색할 방향
} LVFINDINFOW, FAR* LPFINDINFOW;




#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");
}



결과



'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

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
Posted by 아몰라
윈도우 시스템은, 메시지구동 시스템으로 모든 이벤트는 메세지의 발생에 의해서 처리된다.


#define MY_USER 1000 
이렇게 선언할 경우 이미 1000이라는 값은 시스템이 내부적으로 예약해서 사용하는 상수일 수 있다.
그래서 이러한 현상을 막는 방법으로 WM_USER와 같은 사용자가 정의 할 수 있는 상수공간을 마련해두었다.


설명 - 이 메시지는 실제로 정의되어 있는 시스템 메시지가 아니며 사용자 정의 메시지의 시작 범위를 지정하는 상수값이다. 메시지는 정수값 하나로 표현되는데 윈도우즈는 메시지의 범위를 다음과 같이 정의하고 있다.



<범위 설명>

0~WM_USER-1
운영체제가 정의하는 시스템 메시지. WM_PAINT, WM_TIMER 등의 메시지들이 모두 이 범위에 속한다.

WM_USER~WM_APP-1
윈도우 클래스가 정의하는 사용자 정의 메시지
WM_APP~0xBFFF
응용 프로그램이 정의하는 사용자 정의 메시지

0xC000~0XFFFF
문자열로 등록되는 메시지

0x10000~ 이후의 사용을 위해 예약된 영역이며 현재는 사용되지 않는다.


WM_USER

WM_USER는 한 윈도우 클래스를 위한 고유의 메시지를 정의하기 위한 상수값이며 이 범위 이후부터 윈도우 클래스의 사용자 정의 메시지를 만들 수 있다. 이 값은 0x400으로 정의되어 있으며 보통 WM_USER+n으로 사용자 정의 메시지를 정의한다. 이때 n은 1보다 큰 정수이며 사용자 정의 메시지간의 구분을 위해 사용된다. 여러 개의 사용자 정의 메시지가 필요하다면 WM_USER+1, WM_USER+2, WM_USER+3,... 식으로 계속 n을 증가시켜 가며 메시지를 정의할 수 있다. 윈도우즈는 WM_USER이후 0x8000까지 사용자 정의 메시지 영역으로 정의하고 있으므로 n은 최대 0x7c00까지 가능하다. WM_USER+n을 곧바로 사용할 수도 있으며 자주 사용할 경우 다음과 같이 매크로를 정의하여 별도의 메시지를 만들 수 있다.

#define WM_MYMESSAGE WM_USER+1

이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다.

주의
- 표준 컨트롤 중 일부는 자신만의 사용자 정의 메시지를 정의하여 사용하고 있다. 따라서 WM_USER+n은 가급적이면 한 윈도우 클래스내에서만 정의하여 사용해야 하며 응용 프로그램간의 통신에는 사용하지 않는 것이 바람직하다.
- 표준 컨트롤을 서브클래싱했을 경우 함부로 WM_USER+n을 사용하면 표준 컨트롤 고유의 메시지와 충돌이 발생할 수 있다.



예제
 
다음 예제는 사용자 정의 메시지로 윈도우를 이동시킨다.

LRESULT CALLBACK WndProc(HWND hWnd,UINT iMessage,WPARAM wParam,LPARAM lParam)
{
        HDC hdc;
        PAINTSTRUCT ps;
        RECT wrt;
        TCHAR Mes[]="왼쪽 마우스 버튼을 누르면 이동합니다";

        switch(iMessage) {
        case WM_USER+1:
                GetWindowRect(hWnd,&wrt);
                wrt.left+=wParam;
                wrt.right+=wParam;
                wrt.top+=lParam;
                wrt.bottom+=lParam;
                MoveWindow(hWnd,wrt.left,wrt.top,wrt.right-wrt.left,wrt.bottom-wrt.top,TRUE);
                return 0;
        case WM_LBUTTONDOWN:
                SendMessage(hWnd,WM_USER+1,(WPARAM)-3,(LPARAM)5);
                return 0;
        case WM_PAINT:
                hdc=BeginPaint(hWnd, &ps);
                TextOut(hdc,10,10,Mes,lstrlen(Mes));
                EndPaint(hWnd, &ps);
                return 0;
        case WM_DESTROY:
                PostQuitMessage(0);
                return 0;
        }
        return(DefWindowProc(hWnd,iMessage,wParam,lParam));
}

이 예제에서 WM_USER+1은 윈도우를 이동하라는 뜻이며 wParam은 수평 이동 거리, lParam은 수직 이동 거리로 정의하였다. WM_USER+1을 받으면 이 인수들이 지정하는 거리만큼 윈도우를 이동시킨다.

WM_APP

#define WM_MYMESSAGE WM_APP+1

이렇게 매크로를 정의해 놓고 이후부터 WM_MYMESSAGE라는 명칭을 대신 사용하면 된다. WM_USER도 사용자 정의 메시지를 정의하는 용도로 사용되지만 표준 컨트롤중에 이미 WM_USER를 사용하는 컨트롤이 있으므로 중복될 위험성이 있다. 반면 WM_APP는 시스템이 전혀 이 영역을 사용하지 않고 있으므로 중복될 위험이 전혀 없으며 응용 프로그램간의 통신에 사용하기에 적합하다. 두 응용 프로그램의 약속에 의해 WM_APP+n 메시지를 정의하여 사용하면 된다.

WM_USER는 윈도우 클래스를 위한 사용자 정의 메시지이며 WM_APP는 응용 프로그램을 위한 사용자 정의 메시지라는 점이 다르다. 그러나 이 구분은 어디까지나 권장 사항일 뿐이지 강제 사항은 아니다. WM_USER를 응용 프로그램간의 통신에 사용하더라도 충돌이 없다는 확신만 있다면 가능하다. 다만 잠재적인 충돌 가능성이 있을 수 있다는 것을 고려할 때 바람직하지는 않다.

정리

이런 상황을 고려해 보자. MyApp에서 Con1이라는 커스텀 컨트롤을 사용하는데 이 컨트롤은 자신에게 변화가 있을 때 WM_USER+1이라는 통지 메시지를 부모 윈도우로 보내도록 되어 있다. 이런 상황에서 MyApp가 자신의 고유 용도로 WM_USER+1을 다시 정의한다면 메시지간의 충돌이 발생하게 된다. 이런 상황을 방지하기 위해 운영체제는 WM_USER를 내부적인 용도로 WM_APP를 응용 프로그램간의 통신에 사용하도록 권장하는 것이다. 하지만 WM_APP도 여전히 충돌이 발생할 가능성이 있으므로 좀 더 안전한 방법으로 메시지를 정의하고자 한다면 RegisterWindowMessage 함수로 문자열 메시지를 등록하여 사용하는 것이 좋다.


 

리턴값의 의미는 정해져 있다. 응용 프로그램이 의미를 정해서 사용할 수 있다. 이 메시지로 어떤 질문을 하고자할 때는 리턴값을 정의하며 그렇지 않을 경우는 통상 리턴값을 사용하지 않는다.



출처 http://www.winapi.co.kr/reference/Message/WM_USER.htm


'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

간단한 DLL 예제  (1) 2010.02.03
리스트뷰  (0) 2010.02.03
레지스트리  (0) 2010.02.02
o/s의 role  (0) 2010.01.28
파일매핑예제  (0) 2010.01.25
Posted by 아몰라

정보의 저장

¢  프로그램은 실행 중에 사용자가 입력한 옵션 설정이나 프로그램 스스로 만들어낸 정보들을 다음 실행을 위해 그 정보를 저장 해두어야 한다.

¢  이런 정보는 사용자의 정보가 아니라 프로그램 자신의 정보이다

¢  프로그램의 설정 정보를 저장하는 방법에는 INI파일을 쓰는 방법과 레지스트리를 쓰는 방법이 있다.



레지스트리의 특징

¢  윈도우의 환경설정에 대한 모든 정보가 저장되어 관리되고 있는 Windows의 핵심적인 데이터베이스이다.

¢  다중 환경설정을 저장할 수 있다.

¢  INI 파일과 달리 크기가 64KB를 초과할 수 있다.

¢  INI 파일에 비해 속도가 빠르다.

¢  백업 및 복구가 간단하다.

 

레지스트리의 구조

 

¢  레지스트리는 디렉토리 구조와 유사한 계층적 구조로 구성

¢  각각의 가지(레지스트리 편집기에서 폴더 아이콘으로 표시되는)는 키라고 부르며, 각각의 키는 하위키를  포함할 수 있으며, 각각의 키는 값을 포함할 수 있다.

¢  이 값에 레지스트리에 저장되는 실제 정보가 저장됨



함수정리

레지스트리 키 생성 함수

LONG RegCreateKeyEx(HKEY hKey, LPCTSTR lpSubKey, DWORD Reserved,                                   LPTSTR lpClass, DWORD dwOptions, REGSAM Desired, LPSECURITY_ATTRIBUTES lpSecurity, PHKEY hkResult, LPDWORD lpdwDisposition);


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 : 키가 새로 생성되었는지 기존의 키가 오픈된 것인지 리턴받기

                         위한 출력용 변수


열려진 키에 값을 저장하는 함수

LONG RegSetValueEx(HKEY hKey, LPCTSTR lpValueName, DWORD Reserved,  DWORD dwType, CONST BYTE *lpData, DWORD cbData);


hKey :
값을 저장하고자 하는 키 핸들(현재 열려진 키)

lpValueName : 값의 이름

Reserved : 이 인수는 사용하지 않음

dwType : 값의 데이터 타입을 지정 (대부분의 정보를 저장할 수 있다)

    - REG_BINARY : 이진 데이터

    - REG_SZ : 문자열

lpData : 저장하고자 하는 데이터의 포인터

cbData : 데이터의 크기


저장한 위치의 값을 읽어오는 함수

LONG RegQueryValueEx(HKEY hKey, LPTSTR lpValueName, LPDWORD lpReserved,                          LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData);


hKey :
값을 저장하고자 하는 키 핸들(현재 열려진 키)

lpValueName : 값의 이름

lpReserved : 이 인수는 사용하지 않음

lpType : 읽은 값의 타입을 대입받을 변수의 포인터

lpcbData : 실제 복사된 데이터의 크기를 리턴, 대입받을 변수의 크기를 대입

RegCreateKeyEx(), RegSetValueEx(), RegQueryValueEx() 이 함수들은 제대로 읽거나 저장

                                                                   했다면 ERROR_SUCCESS(0)가 리턴 된다



열려진 레지스트리 키를 닫는 함수


 

LONG RegCloseKey(HKEY hKey);

레지스트리 키도 메모리를 소모하므로 사용하고 난 후에는 해제를 해야함



실습예제

#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;
}

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

리스트뷰  (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
Posted by 아몰라

Blocking Model

퍼스널 컴퓨터에서 클라이언트가 접속해서 지속해서 데이터르 주고 받을때


Non-Blocking Model

AsyncSelec(윈도우), EventSelect  (콘솔,백그라운드)

퍼스널 컴퓨터에서 동작 시키고자 할 때 해당되는 소켓을 가지고 실질적으로 패킷을 주고 받는게

지속적으로 주고 받는게 아니라 단편적으로 데이터를 주고 받을 때

Overlapped I/O

이벤트 셀렉트처럼 사용  할 수 있다. 폴링에 관한 비용이 들지 않는다.


다수의 CPU를 가지고 있을 때 CPU를 최대한 사용 할 수 있다.
Contex Switching 발생이 하지 않는다.



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를 사용하는 다른 응용이 많을 경우 큰 이득이 없다.




출처 http://cafe.daum.net/sbehclub

'API & MFC > 네트워크프로그래밍' 카테고리의 다른 글

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
Posted by 아몰라
1. 스케줄러

2. MMU 메모리 매핑 유닛

3. Interrupt 관리  - 하드웨어 관리

App > Shell > O/S > Kernel

O/S(Kernel) - 컴퓨터 시스템의 핵이다.


4. NetWork

'API & MFC > API & 시스템프로그래밍' 카테고리의 다른 글

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
Posted by 아몰라

#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);
}

'API & MFC > 네트워크프로그래밍' 카테고리의 다른 글

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
Posted by 아몰라
이전버튼 1 2 3 4 5 이전버튼