'API & MFC/네트워크프로그래밍'에 해당되는 글 9건

  1. 2010.02.09 우아한 종료
  2. 2010.02.05 EventSelect(클)
  3. 2010.02.05 EventSelect(서버)
  4. 2010.02.05 EventSelect란?
  5. 2010.02.04 ASyncSelect 예제 1
  6. 2010.02.02 소켓통신의 라이브러리 사용 선택 시 고려사항
  7. 2010.01.25 소켓함수 예제(로그인서버)
  8. 2010.01.18 소켓통신(함수정리) 1
  9. 2010.01.18 OSI 모델 And Ip계층

1. 소켓 연결 종료의 문제점(이는 TCP기반을 말한다.)

TCP 기반에서 closesocket()함수를 호출하게 되면 연결을 완전 종료한다는 의미이다. 여기에 한 가지 문제점이 있다.

 

만약 Host A Host B에게 메시지를 보내고 Host A closesocket 함수를 호출해 연결을 종료 했다면, Host B에서 Host A로 전송되고 있는 메시지가 있을 때, 그 메시지는 전송을 완료하지 못하고 중간에 소멸되고 말것이다. (여기서 closesocket함수는 출력 스트림과 입력 스트림을 모두 종료하는 기능을 한다.)

이 문제를 해결하기 위해 소켓 스트림의 일부만 종료(half close)하는 방법에 대해 알아볼 것이다.

 

다음은 half close를 하는 함수이다.

 

int shutdown(SOCKET s, int how);

s : half-close를 할 소켓의 핸들이다.

How : 종료모드를 인자로 전달한다.

 

다음에 how에 들어갈 종료모드들이다.

상수 값

모드

정의

0

SD_RECEIVE

입력 스트림 종료

1

SD_SEND

출력 스트림 종료

2

SD_BOTH

/ 출력 스트림 종료

 

다음과 같이 만약 출력 스트림만 종료를 하게 된다면, Host B에서 Host A로 전송중인 메시지는 입력 스트림이 아직 열려 있기 때문에 무사지 전송이 가능하게된다.

 

 

 

 

 

 

2. 출력 스트림의 종료의 필요성

메시지가 모두 무사히 전송되고 나서 closesocket를 이용해 종료하면 되지 출력 스트림의 종료가 왜 필요한 것인가?에 대해 알아보자.

 

출력 스트림을 종료하게 되면, 데이터 전송의 끝을 알려주는 EOF 메시지를 연결 되어 있는 호스트로 보내게 된다. 그리고 EOF 전송 시 상대 호스트의 데이터 수신함수(read, recv) 0을 반환한다.

 

출력 스트림을 종료하는 방법에는 shutdown 함수를 이용하여 종료 할 수도 있고, closesocket를 이용해도 입력 스트림과 함께 출력 스트림 또한 종료 되므로 EOF메시지가 전송된다.

 

다음 그림을 보면, 파일을 모두 보내고 EOF 메시지를 전송하고 있다. Clinet에서는 EOF메시지를 받고 파일이 모두 전송되었다는 것을 알아차리고 Thank you메시지를 보내게 된다. 만약 입력 스트림과 출력 스트림 모두 종료하게 된다면 Thank you 메시지는 받지 못할 것이다. 또한 EOF메시지를 보내지 않는다고 한다면, Client는 파일 전송이 언제 끝나는지도 모르는 채 파일이 전송을 계속 기다리게 되고, 한편 Server측에서는 파일을 다 전송하고 확인 메시지를 계속 기다리게 되어 server / client 모두 무한 대기 상태에 빠지게 된다.
 

 

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

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

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

#define YOURIP "192.168.34.103"
#define YOURPORT 1100


struct App
{
 SOCKET sarr[WSA_MAXIMUM_WAIT_EVENTS];
 HANDLE hEarr[WSA_MAXIMUM_WAIT_EVENTS];
 HANDLE hFileArr[WSA_MAXIMUM_WAIT_EVENTS];
 int now;
};

void connectProc(int index);
void writeProc(int index);
void CloseProc(int index);
void DeleteSocket(int index);
void InitEvent(SOCKET sock);
void SendData(int index);


extern App app;




#include "event.h"

using namespace std;

App app; 

 

void main()
{
 WSADATA wsadata;
 WSAStartup(MAKEWORD(2,2),&wsadata);
 
 SOCKET sock;
 sock = socket(AF_INET, SOCK_STREAM, 0);

 SOCKADDR_IN client = {0,};

 client.sin_addr.s_addr = inet_addr(YOURIP);
 client.sin_family = AF_INET;
 client.sin_port = htons(YOURPORT);
 
 
 InitEvent(sock);
 
 WSAEventSelect(app.sarr[app.now],app.hEarr[app.now],FD_CONNECT);
 connect(sock,(SOCKADDR *)&client,sizeof(client));

 app.now++;

 WSANETWORKEVENTS ev;
 int index;
  
  

 while(1)
 {
  index = WSAWaitForMultipleEvents(app.now,app.hEarr,FALSE,WSA_INFINITE,FALSE);
  index -=  WSA_WAIT_EVENT_0;
  WSAEnumNetworkEvents(app.sarr[index],app.hEarr[index],&ev);

  switch(ev.lNetworkEvents)
  {
  case FD_CONNECT:
   connectProc(index);
   break;
  case FD_WRITE:
   writeProc(index);
   break;
  case FD_CLOSE:
   CloseProc(index);
   break;
  } 
 }
 

 WSACleanup();
}


void connectProc(int index)
{
 SOCKET sock = app.sarr[index];
 DeleteSocket(index);
 
 InitEvent(sock);
  
 WSAEventSelect(app.sarr[app.now], app.hEarr[app.now],FD_WRITE);
 app.now++;
}


void writeProc(int index)
{
 if(app.sarr[index])
 {
  while(1)
  {
   SendData(index);
  }
 }

}


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


 DeleteSocket(index);
}

void DeleteSocket(int index)
{
 app.now--;
 app.hEarr[index] = app.hEarr[app.now];
 app.sarr[index] = app.sarr[app.now];
}


void InitEvent(SOCKET sock)
{
 app.sarr[app.now] = sock;
 app.hEarr[app.now] = WSACreateEvent();
}


void SendData(int index)
{
 char str[100];
 printf("아무거나 입력해봐:\n");
 scanf("%s",str);

 SOCKET sock = app.sarr[index];
 send(sock,str,100,0);
}

'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 아몰라


#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 아몰라

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

#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 아몰라

접속 기반 프로토콜(Connection Oriented Protocol)



SOCKET PASCAL FAR socket(int af, int type, int protocol);

참고주소 : http://msdn.microsoft.com/en-us/library/ms740506(VS.85).aspx

특정 전송 서비스 제공자로 바인드 될 소켓을 생성한다.

리턴 : 성공시 소켓의 핸들. 실패시 INVALID_SOCKET.

af : address family를 정한다.

 - AF_INET(IPv4), AF_IPX, AF_APPLET!ALK, AF_NETBIOS, AF_INET6(IPv6), AF_IRDA, AF_BTH

type : 새로운 소켓이 어떤 형태인지 정한다.

 - SOCK_STREAM : OOB data 전송 메카니즘을 가진 순서화된 신뢰성 있는 양방향, 접속 기반 바이트 스트림을 제공한다.

 - SOCK_DGRAM : 고정된 최대 크기의 신뢰성 없고 접속하지 않는 버퍼인 데이터그램을 제공한다.

 - SOCK_RAW : Layer 3 프로그래밍을 하고 싶을 때

   예시) ping(컴퓨터가 살았나 죽었나, round-trip), tracert

protocol : 사용될 프로토콜

 - IPPROTO_TCP, IPPROTO_UDP


well-known port(0~1024) : 사람들이 자주 사용하는 포트. 21: ftp, 23: telnet, 25 : SMTP, 80 : web


Socket Address 구조체

참고주소 : http://msdn.microsoft.com/en-us/library/aa252969(VS.60).aspx

struct sockaddr_in{

    short            sin_family;

    unsigned short      sin_port;

    struct   in_addr      sin_addr;

    char               sin_zero[8];

};


sin_family : address family ( AF_INET이어야 한다. )

sin_port : 16비트 포트 번호. htons계열의 함수가 필요하다.

sin_addr : IP 주소. inet_addr함수나 htonl계열의 함수가 필요하다.

sin_zero : 사용되지 않음.


int pascal FAR bind(SOCKET s, struct sockaddr FAR *addr, int namelen);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737550(VS.85).aspx

소켓 핸들과 소켓 구조체를 연관시키고 시스템에게 묶어달라고(bind) 요청한다.

소켓과 지역(현재 컴퓨터) 주소를 연관시킨다.

리턴 : 성공시 0. 실패시 SOCKET_ERROR. 더 자세한 오류코드는 WSAGetLastError를 참고.

s : bind되지 않은 소켓을 나타내는 descriptor

name : sockaddr 구조체로부터 소켓을 지정할 주소

namelen : 바이트 단위. name 전달인자 값의 길이


int PASCAL FAR listen(SOCKET s, int backlog);

참고주소 : http://msdn.microsoft.com/en-us/library/ms739168(VS.85).aspx

포트를 감시모드로 바꾼다.

들어오는 접속에 대해 듣고 있는 상태의 소켓으로 만든다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 접속되지 않고 bind된 소켓을 나타내는 descriptor

backlog 

 - 기라디는 접속 큐의 최대 길이. (로스터에 올라간 사람 수. 최소 1이상)

 - SOMAXCONN이면 최대로 합리적인 값으로 backlog를 설정.


SOCKET PASCAL FAR accept(SOCKET s, struct sockaddr FAR *addr, int FAR *addrlen);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737526(VS.85).aspx

클라이언트가 올 때까지 blocking되었다가 클라이언트가 접속하면 요구를 받아준다.

소켓으로 들어오는 시도를 한 접속을 허가한다.

s : listen 함수에 의해 listen 상태인 소켓을 나타내는 descriptor

addr : 접속한 개체의 주소를 받는 버퍼의 포인터. 접속 peer 프로세스(클라이언트)의 주소를 리턴한다.

addrlen : addr 전달인자를 가리키는 구조체의 길이를 포함한다.


int pascal FAR connect(SOCKET s, struct sockaddr FAR *addr, int namelen);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737625(VS.85).aspx

특정 소켓으로 접속한다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 접속되지 않은 소켓을 나타내는 descriptor

name : 접속이 설정될 sockaddr 구조체의 포인터

namelen : name 전달인자가 가리키는 sockaddr 구조체의 길이(바이트 단위)


port to port connection

single server는 2개의 소켓을 가진다.

multi server는 n+1 개의 소켓을 가진다.


Blocked : 현실적으로 어느 코드 부분에 멈춰 있음

Blocking : 호출을 하면 정지할 가능성이 있는 코드. 오류나 결과가 나올 때까지 멈춰 있음.

예시) 윈도우즈 상에서 '응답 없음' 표시(잠재적으로 멈출 수 있는 코드 : 파일, 네트워크)


nonblocking : 호출하자마자 바로 리턴한다. 결과가 나올 때까지 반복 호출. 프로그램이 멈출 일이 없다.


asynchronous mode : 결과가 나올 때 시그널, 인터럽트, 메세지를 보내서 확인한다. 프로그램이 멈출 일이 없다. WSA계열 함수(Windows Socket Asynchronous)



 way handshake 방식을 통해 접속을 설정한다.

send() <-> recv()

socket은 패킷을 받아 buffer(수십K바이트)에 보관한다.


패킷단위

스트림단위

소켓단위(버퍼)


send buffer : send() 함수는 보낼 내용을 send buffer에 담는 역할을 한다. 프로그래머가 신경 쓸 필요가 없다.

receive buffer : recv() 함수는 receive buffer에 있는 받을 내용을 가지고(읽어) 온다.


send buffer가 꽉 차있다면 send(), write() 함수는 기다려야 한다. (blocking)

receive buffer가 비어 있는데 recv(), read() 함수는 기다려야 한다. (blocking)


int send(__in  SOCKET s, __in  const char *buf, __in  int len, __in  int flags);

참고주소 : http://msdn.microsoft.com/en-us/library/ms740149(VS.85).aspx

접속된 소켓에 데이터를 보낸다.

리턴 

성공시 len 전달인자에서 보내질 요청된 수보다 작을 가능성이 있는 보내진 바이트 수.

실패시 SOCKET_ERROR

s : 접속된 소켓을 나타내는 descriptor

buf : 보낼 데이터를 포함한 버퍼의 포인터

len : buf가 가리키는 데이터의 길이(바이트 단위)

flags : 호출하는 방법을 정의하는 집합.


int recv(__in   SOCKET s, __out  char *buf, __in   int len, __in   int flags);

참고주소 : http://msdn.microsoft.com/en-us/library/ms740121(VS.85).aspx

접속된 소켓이나 바인드된 비접속 소켓으로부터 데이터를 받는다.

리턴 : 성공시 받은 바이트 수 실패시 SOCKET_ERROR

s : 접속된 소켓을 나타내는 descriptor

buf : 들어올 데이터를 받을 버퍼 포인터

len : buf가 가리키는 데이터의 길이(바이트 단위)

flags : 함수에 행동에 영향을 줄 집합


비동기 소켓방식

버퍼의 상태를 확인해 주는 함수를 이용한다.

 


윈도우즈 비동기 소켓 방식

WSAAsyncSelect(소켓 핸들, 윈도우 핸들, 윈도우즈 user-defined message, 소켓 이벤트)

소켓 이벤트(4)가 발생하면 윈도우즈 user defined message(3)를 윈도우 핸들(2)에 보낸다.

소켓 하나에 user defined message는 하나만 등록 가능하다.

※ 취소하는 경우 : e = WSAAsyncSelect(socket, hWnd, 0, 0); 


int WSAAsyncSelect(__in  SOCKET s, __in  HWND hWnd, __in  unsigned int wMsg, __in  long lEvent);

참고주소 : http://msdn.microsoft.com/en-us/library/ms741540(VS.85).aspx

소켓에 대한 네트워크 이벤트의 윈도우 기반 알림(notification)을 요청한다.

s : 이벤트 알림(notification)이 요구되는 소켓을 나타내는 descriptor

hWnd : 네트워크 이벤트가 발생할 때 메세지를 받게 될 윈도우 핸들.

wMsg : 네트워크 이벤트가 발생할 때 받게될 (사용자 정의) 메세지.

lEvent : 응용 프로그램이 관심있는 네트워크 이벤트의 조합을 나타내는 비트마스크


소켓 이벤트(lEvent)

FD_READ : receive 버퍼에 무엇인가 들어왔다.

FD_WRITE : send 버퍼에 쓸 수 있다.

FD_OOB : FD_READ의 특수한 형태.

FD_ACCEPT : 접속 요구가 들어왔다.

FD_CONNECT : 접속이 되었다. 서버와 연결에 성공하였음.

FD_CLOSE : 상대방과 socket 연결이 끊어짐.


윈도우 프로시저를 호출할 때 전달되는 인자

wParam : 소켓 식별자

LOWORD(lParam) : 발생한 이벤트 종류. WSAGETSELECTEVENT(lParam)와 같은 뜻

HIWORD(lParam) : 에러 상태. WSAGETSELECTERROR(lParam)와 같은 뜻


closesocket() : 유닉스는 소켓 닫는 함수를 close()를 쓰지만 윈도우즈는 closesocket을 사용한다.


int closesocket(__in  SOCKET s);

참고주소 : http://msdn.microsoft.com/en-us/library/ms737582.aspx

현재 존재하는 소켓을 닫는다.

리턴 : 성공시 0, 실패시 SOCKET_ERROR

s : 닫을 소켓을 나타내는 descriptor



출처 http://blog.daum.net/sdr1982/

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

EventSelect란?  (0) 2010.02.05
ASyncSelect 예제  (1) 2010.02.04
소켓통신의 라이브러리 사용 선택 시 고려사항  (0) 2010.02.02
소켓함수 예제(로그인서버)  (0) 2010.01.25
OSI 모델 And Ip계층  (0) 2010.01.18
Posted by 아몰라

응용계층

프리젠테이션계층

세션계층 - 컴퓨터내의  응용에게 보내준다.

전송계층 - 어떠한 방식으로 보낼건지 (TCP, UDP)
네트워크계층 - 누가누구한테 보내는지 

데이터링크계층 - 디바이스드라이버 (운영체제에서 디바이스에게...)

물리계층 - 패킷은 회선을 이용한다



1.  Layer - Based 통신 모델    - 계층적 구조

- Layer N 

   (N-1)계층에서 제공하는 서비스를 사용

   동일 계층의 instance와의 통신

 

- Protocols

    동일 계층간에 통신을 위해 미리 정해놓은 규약

 - Service

    계층 N이 (N+1)계층에게 제공하는 기능

    Service Interface라고도 불린다.

 - Instance

   한 개의 계층이 제공하는 통신 프로토콜과 서비스를 구현한 것

 

 

통신 흐름

 

 2. ISO/OSI Reference Model

-특징

   시스템 간의 통신을 위한 추상화 모델을 제시

   개방형 통신 시스템을 위해 표준안 개발 체제 제공 

   통신 시스템의 기능을 논리적으로 분해하는 측면에서 중요하게 인식하고 있다.

   복잡성 때문에 실질적으로 구현하는 입장에서 보면 실패한 모델

 

- Physical Layer (물리 계층)

   구조화되어 있지 않은 비트 시퀀스를 물리적인 신호로 변환하여 매체를 통해 전송하는 계층

 

- Data Link Layer (데이터 링크 계층)

   송신부에서는 데이터를 프레임으로 만들어 전송한다.

   수신부에서는 과부하가 걸리지 않도록 데이터의 흐름을 조정한다. 

   에러 검출 및 재 전송을 한다.

   Protocol : SLIP, PPP, HDLS,...

 

- Network Layer (네트워크 계층)

  통신망에서 System간의 연결성을 제공한다.

   Routing, Fragmenting을 담당한다.

   Protocol : IP, ICMP, IGMP,...

 

- Transport Layer (전송 계층)

   Application간의 데이터 전송 제공

   데이터의 정확성과 순서를 안전하게 하기 위해 존재한다. 

   Protocol: TCP, UDP,...

 

- Session Layer (세션 계층)

   전송 계층을 통한 구조화된 메시지 교환을 핸들링한다.

 

- Presentation Layer (프리젠테이션 계층)

  터미널 시스템 사이의 데이터 흐름을 제어한다.

  통신하고 있는 컴퓨터 시스템들에 의존적이지 않은(독립적인) 데이터 전달을 규정한다.

  예: ASCII vs Unicode , Big endian vs Little endian

 

- Application Layer (응용 계층) 

  

3. TCP/IP Reference Model

 

- Interface Layer

   네트워크 아답터들과 그들의 드라이버들을 다룬다.

 

- Internet layer

   IP

   ICMP - 제어 및 에러 정보 전송

   IGMP - 통신 그룹 관리

 

- Transfer layer

   터미널 시스템의 용용들 간의 전송담당

   TCP - 연결지향, 신뢰성,STREAM

   UDP - 비 연결지향, 가벼운 스택, DGRAM

             복잡한(무거운) TCP에 비해 선호하는 경우가 늘고 있다.(멀티미디어와 같은 전송에서)

 

- Application layer

   응용 프로그램과 관련된 모든 태스크들의 계층(ISO/OSI 모델의 5~7 계층)

   Telnet, FTP, SMTP, DNS, HTTP

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


라우터 - 3계층까지만 이용

세대별 통신

1G - 아날로그 통신(PSTN망)

2G - 디지털 통신

3G- 개인단말

4G- 차세대통신


Circuit Switching망( 독점)  = Packet Flooding망

Packet Flooding - 전체 망에 뿌려지면서 해당 대상까지 간다.

패킷이 어떠한 망을 사용하는지



IP 프로토콜 

   RFC 791에 정의되어 있는 모든 IP 기반 네트워크에 사용되는 데이터 트래픽에 대한 기본 서비스를 제공 

   데이터그램 기반으로 만들어졌다. 

   전화망의 circuit-switching방식과 달리 packet-switching방식을 사용한다. 

   - 롤

    데이터 전송 계층의 차이를 감추고 상이한 네트워크 기술(LAN, SLIP, PP, 모뎀, ISDN 등)에 대한 일관된 표현을 제공한다. 

   IP Address family를 통해 Uniform address scheme를 제공

   큰 데이터 패킷은 fragmentation하여 작은 패킷 크기로 전송

   (통신에 거치는 모든 네트워크 기술들의 MTU중 최소 MTU에 맞춰서 fragmentation한다.)

 

 

통신 기술 

 

 

IPv4 스택 

 

 

Version

   현재는 v4(0x800)와 v6(0x86DD)만 정의되어 있다.

 

IHL

   패킷 헤더의 길이

   옵션을 사용하면 패킷 헤더의 길이는 5옥텟(1옥텟은 4바이트)를 넘을 수 있다.  최대 15옥텟(60바이트) 

 

Codepoint

    ToS라고 불렀었던 것을 RFC2474에서 Differentiated Services Codepoint라고 이름을 변경하였다.

    IP에 사용되는 forwarding behavior를 나타낸다.

 

Total Length

   패킷 전체의 길이, 최대 64K

   RFC791에 의하면 576바이트인 데이터 패킷을 처리할 수 있어야 한다고 명시(길이가 더 큰 패킷도 처리할 수 있다.) 

 

Fragment ID - 상위에서 날라온 데이터의 구분자 역할을 한다.

    원래 하나였던 패킷을 fragmenation을 했을 때 모든 fragments는 동일한 fragment id를 갖는다.

 

Flags

    DF : 데이터그램이 fragment되지 말아야 함을 나타낸다.

    MF: fragment가 되었음을 나타냄, 마지막 fragment에는 표시되지 않는다.

 

Fragment Offset

    Fragment의 일련번호

    수신부에서 원래의 데이터그램으로 재구성하기 위해 필요하다.

 

TTL -  Keep Alive   에 해당 되는 부분

   IP 패킷의 수명을 제한하기 위하여 사용

   패킷이 라우터를 거칠 때마다 1감소되며 0이되면 패킷은 제거된다.

   라우터에서 버퍼링을 위해 1이상 감소시키는 경우도 있다. 

 

Protocol

    전송 계층의 구분

    TCP(6), UDP(17), IGMP(2)

 

Checksum

   IP 패킷 허더 필드들에 대한 checksum

   라우터를 거쳐가면서 TTL이 감소하기 때문에 매번 다시 계산된다.

   Checksum필드를 제외한 부분을 16비트 단위로 1의 보수의 합을 계산한 값이다.

   유효한 패킷인지 확인하기 위한 용도로 있는 필드이다.


 Sorce address - 192.168.34.442 송신자아이피  



 Destination address - 192.168.34.442 수신자아이피


여기에서는 옵션과 ICMP, IGMP등을 다루지 않으니 각자가 확인하여 학습하길 바란다.   

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

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