소켓(Socket)
  버클리 유닉스 에서 사용한 네트워크 프로그래밍 인터페이스, 이것을 윈도우에서 사용할 수 있도록 한 것을 윈도우 소켓(줄여서 윈속)이라 부름.
  윈도우 95버전부터 API에 정식으로 포함하여 제공되었고, 현재는 WinSock2 버전까지 나옴.
윈속(Windows Socket, Winsock)
  DLL를 통해 기능이 제공됨(WS2_32.DLL)
  윈도우의 메세지 구동방식으로 동작하므로, 이를 위한 확장 함수 존재
  유닉스 소켓과 소스 코드 수준에서 호환성이 높으므로 기존 프로그램을 포팅하기 쉽다.
  OS별 윈속 버전은 다음과 같다.
  윈도우 95 - 1.1
  윈도우 98/Me, 윈도우 NT/2000/XP/2003 - 2.2
  윈도우 CE - 1.1
#include "stdafx.h"
#include <winsock2.h> // w2_32.lib 링크 단계 추가 필수
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 512 // 클라이언트에서 받을 데이터 버퍼 사이즈
// 네트워크 관련 함수 오류 후 종료
void err_quit(char* msg)
{
   LPVOID lpMsgBuf;
   FormatMessage(
         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
         NULL, WSAGetLastError(),
         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
         (LPTSTR)&lpMsgBuf, 0, NULL);
   MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
   LocalFree(lpMsgBuf);
   exit(-1);
}
// 네트워크 관련 함수 오류 출력
void err_display(char* msg)
{
   LPVOID lpMsgBuf;
   FormatMessage(
         FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
         NULL, WSAGetLastError(),
         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
         (LPTSTR)&lpMsgBuf, 0, NULL);
   printf("[%s] %s", msg, (LPCTSTR)lpMsgBuf);
   LocalFree(lpMsgBuf);
}
int _tmain(int argc, _TCHAR* argv[])
{
   int retValue;
// 윈속 초기화
   WSADATA wsa;
   if(WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
        return -1;
// 소켓 생성
   SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);
   if(listenSocket == INVALID_SOCKET)
       err_quit("socket()");
// 위에서 생성한 소켓을 서버로서 만들기 위한 준비 단계 및 설정
   SOCKADDR_IN serverAddr;
   memset(&serverAddr, 0, sizeof(serverAddr));
   serverAddr.sin_family = AF_INET;
   serverAddr.sin_port = htons(5001);
   serverAddr.sin_addr.s_addr = htonl(INADDR_ANY);
   retValue = bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
   if(retValue == SOCKET_ERROR)
       err_quit("bind()");
// 접속하기 위한 소켓 대기자수 설정
   retValue = listen(listenSocket, SOMAXCONN);
   if(retValue == SOCKET_ERROR)
       err_quit("listen()");
   SOCKET clientSocket;
   SOCKADDR_IN clientAddr;
   int nAddrLength;
   char recvBuffer[BUFFER_SIZE + 1]; // 기존 버퍼 사이즈에 +1 중요함. 문자열에 있어서 널문자 한 칸은 필수임
   while(1)
   {
       // 클라이언트 접속을 대기한다.
       nAddrLength = sizeof(clientAddr);
       clientSocket = accept(listenSocket, (SOCKADDR*)&clientAddr, &nAddrLength);
       if(clientSocket == INVALID_SOCKET)
       {
           err_display("accept()");
           continue;
       }
       printf("\n[TCP 서버] 클라이언트 접속 : IP 주소 = %s, 포트 번호 = %d\n",
          inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
       // 클라이언트와 데이터 통신 루프 
       while(1)
       {
          // 클라이언트에서 데이터를 읽는다.
          retValue = recv(clientSocket, recvBuffer, BUFFER_SIZE, 0);
          if(retValue == SOCKET_ERROR)
          {
               err_display("recv()");
               break;
          }
          else if(retValue == 0)
          {
               // 접속 종료
               break;
          }
          else
          {
               // 받은 데이터를 출력한다.
               recvBuffer[retValue] = '\0';
               printf("%s", recvBuffer);
          }
       }
// 클라이언트 접속 종료 후 생성된 소켓을 반환한다.
closesocket(clientSocket);
       printf("\n[TCP 서버] 클라이언트 접속 종료 : IP 주소 = %s, 포트 번호 = %d\n",
          inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
}
// 생성한 서버 소켓을 반환한다.
closesocket(listenSocket);
// 윈속을 종료한다.
WSACleanup();
   return 0;
}
[출처] 소켓이란? 네트워크에 대한 첫 경험 (정문수 개인 카페) |작성자 유빈아빠
 
댓글 없음:
댓글 쓰기