본문 바로가기

프로그래밍/VC/VC.NET/Cs

소켓 프로그래밍. Socket Programming.

소켓 프로그래밍은 네트워킹 프로그래밍중 가장 기본적이다.

소켓. Socket이란 통신상의 endpoint.
이 소켓.Socket은 핸들.Handle같은 식별번호라 생각하면 된다.
프로그램은 이 소켓을 바인딩해서 사용하게 된다.

종류

Stream Socket Datagram Socket
TCP/IP Protocol UDP/IP Protocol
연결후 새로운 주소지정 필요없음 수신,발신 주소를 가짐.
별개의 경로를 가지고 목적지이동
순서보장 순서보장이 않됨
연결후 통신 연결 않됨
신뢰성보장 신뢰성보장않됨
송/수신시 확인필요

소켓프로그래밍에 필요한 MFC Class는 CAsyncSocket, CSocket.
Winsock은 Stream, Datagram Socket 모두 지원.
Stream 에선 SOCK_STREAM을 Datagram에선 SOCK_DGRAM을 이용해 구분.

주요 콜백 함수함수.

CAsyncSocket::OnReceive 소켓으로부터 데이터를 받기 위해서 호출
CAsyncSocket::OnSend 연결되 소켓으로 데이터 보내기 위해서 호출
CAsyncSocket::OnAccept 프레임워크에 의해 호출. Accept멤버함수의 호출로 인해 연결할수 있는 소켓을 확인
CAsyncSocket::OnConnect stream이나 datagram socket의 연결을 만들기 위한 멤버함수
CAsyncSocket::OnClose 프로세스에 의해 연결된 소켓이 끊어졌는지 확인.

CAsyncSocket::OnReceive

virtual void OnReceive(int nErrorCode);

nErrorCode : 소켓에서의 가장 최근 에러.

0 : 함수가 성공적으로 실행
WSAENETDOWN : 윈도우 소켓이 네트워크 서브시스템이 실패했다고 인지함. 연결실패.

Ex. http://msdn2.microsoft.com/ko-kr/library/wfttx1af(VS.80).aspx

void CMyAsyncSocket::OnReceive(int nErrorCode) 
{
  static int i=0;
   i++;
  TCHAR buff[4096];
  int nRead;
  nRead = Receive(buff, 4096);

  switch (nRead) {

    case 0:
      Close(); 
      break;

    case SOCKET_ERROR:
      if (GetLastError() != WSAEWOULDBLOCK) {
         AfxMessageBox ("Error occurred");
         Close();
      }
      break;

    default:
      buff[nRead] = 0; //terminate the string
      CString szTemp(buff);
      m_strRecv += szTemp; // m_strRecv is a CString declared
                                         // in CMyAsyncSocket
       if (szTemp.CompareNoCase("bye") == 0 ) ShutDown();  
   }

   CAsyncSocket::OnReceive(nErrorCode);

}

CAsyncSocket::OnSend

virtual void Onsend(int nErrorCode);
0 : 함수가 성공적으로 실행
WSAENETDOWN : 윈도우 소켓이 네트워크 서브시스템이 실패했다고 인지함. 연결실패.

Ex. http://msdn2.microsoft.com/ko-kr/library/s03275bd(VS.80).aspx

// CMyAsyncSocket is derived from CAsyncSocket and defines the
// following variables:
//    CString      m_sendBuffer;   //for async send
//    int      m_nBytesSent;
//    int      m_nBytesBufferSize;

void CMyAsyncSocket ::OnSend(int nErrorCode)
{
   while (m_nBytesSent < m_nBytesBufferSize)
   {
      int dwBytes;

      if ((dwBytes = Send((LPCTSTR)m_sendBuffer + m_nBytesSent,
         m_nBytesBufferSize - m_nBytesSent)) == SOCKET_ERROR)
      {
         if (GetLastError() == WSAEWOULDBLOCK) break;
         else
         {
            TCHAR szError[256];
            wsprintf(szError, "Server Socket failed to send: %d",
               GetLastError());
            Close();
            AfxMessageBox (szError);
         }
      }
      else
      {
         m_nBytesSent += dwBytes;
      }
   }
   if (m_nBytesSent == m_nBytesBufferSize)
      {
         m_nBytesSent = m_nBytesBufferSize = 0;
         m_sendBuffer = "";
      }
   CAsyncSocket::OnSend(nErrorCode);
}


 

CAsyncSocket::OnAccept

virtual void OnAccept(int nErrorCode);

nErrorCode : 소켓에서의 가장 최근 에러.
0 : 함수가 성공적으로 실행
WSAENETDOWN : 윈도우 소켓이 네트워크 서브시스템이 실패했다고 인지함. 연결실패.


CAsyncSocket::OnConnect

virtual void OnConnect(int nErrorCode);

nErrorCode : 소켓에서의 가장 최근 에러.

0 : 함수가 성공적으로 실행
WSAEADDRINUSE : 특별한 주소가 사용중임
WSAEADDRNOTAVAIL : 특별한 주소가 로컬머신에서 사용불가능
WSAEAFNOSUPPORT : 소켓에서 특별한 대역의 주소에서 사용 불가능
WSAECONNREFUSED : 연결시도가 강제로 거절됨
WSAEDESTRADDRREQ : 목적지 주소 요청
WSAEFAULT : lpSockAddrLen 아규먼트가 틀림.
WSAEINVAL : 소켓이 이미 주소로 바운드됨
WSAEISCONN : 소켓이 이미 연결됨
WSAEMFILE : 더이상 파일 설명자가 불가능
WSAENETUNREACH : 이번에 호스트로부터 도달할수없음.
WSAENOBUFS : 버퍼의 사용불가능. 소켓이 연결않됨.
WSAENOTCONN : 소켓이 연결 않됨
WSAENOTSOCK : 설명자가 소켓이 아니고 파일임.
WSAETIMEDOUT : 연결을 못하고, 타임아웃됨.

Ex. http://msdn2.microsoft.com/ko-kr/library/xfaaxdxe(VS.80).aspx

void CMyAsyncSocket::OnConnect(int nErrorCode)   // CMyAsyncSocket is
                                                // derived from CAsyncSocket
{
   if (0 != nErrorCode)
   {
      switch( nErrorCode )
      {
         case WSAEADDRINUSE:
            AfxMessageBox("The specified address is already in use.\n");
            break;
         case WSAEADDRNOTAVAIL:
            AfxMessageBox("The specified address is not available from
               the local machine.\n");
            break;
         case WSAEAFNOSUPPORT:
            AfxMessageBox("Addresses in the specified family cannot be
               used with this socket.\n");
            break;
         case WSAECONNREFUSED:
            AfxMessageBox("The attempt to connect was forcefully
               rejected.\n");
            break;
         case WSAEDESTADDRREQ:
            AfxMessageBox("A destination address is required.\n");
            break;
         case WSAEFAULT:
            AfxMessageBox("The lpSockAddrLen argument is incorrect.\n");
            break;
         case WSAEINVAL:
            AfxMessageBox("The socket is already bound to an
               address.\n");
            break;
         case WSAEISCONN:
            AfxMessageBox("The socket is already connected.\n");
            break;
         case WSAEMFILE:
            AfxMessageBox("No more file descriptors are available.\n");
            break;
         case WSAENETUNREACH:
            AfxMessageBox("The network cannot be reached from this host
               at this time.\n");
            break;
         case WSAENOBUFS:
            AfxMessageBox("No buffer space is available. The socket
               cannot be connected.\n");
            break;
         case WSAENOTCONN:
            AfxMessageBox("The socket is not connected.\n");
            break;
         case WSAENOTSOCK:
            AfxMessageBox("The descriptor is a file, not a socket.\n");
            break;
         case WSAETIMEDOUT:
            AfxMessageBox("The attempt to connect timed out without
               establishing a connection. \n");
            break;
         default:
            TCHAR szError[256];
            wsprintf(szError, "OnConnect error: %d", nErrorCode);
            AfxMessageBox(szError);
            break;
      }
      AfxMessageBox("Please close the application");
   }
   CAsyncSocket::OnConnect(nErrorCode);
}


CAsyncSocket::OnClose

virtual void OnClose(int nErrorCode);

nErrorCode : 소켓에서의 가장 최근 에러.

0 : 함수가 성공적으로 실행
WSAENETDOWN : 윈도우 소켓이 네트워크 서브시스템이 실패했다고 인지함.
WSAECONNRESET : 연결이 원격에서 리셋되어짐.
WSAECONNABORTED : 연결이 타임아웃이나 다른 실패로 정지.