윈도우 클라이언트 코드 분석

강한친구·2022년 3월 12일
0

Server Studies

목록 보기
14/27

윈도우는 그게 없다

그게 뭘까?
바로 linux 라이브러리들이다.

꽤 주요한 라이브러리 몇개가 없어서, 윈도우에서는 다른걸 쓴다.

#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
#include <conio.h>

#pragma comment(lib, "ws2_32.lib")

int main() {
    char ip[] = "218.48.17.230";
    int port = 10000;
    int valread;
    char *hello = (char*)"message from Client";

    WSADATA wasData;
    SOCKET hSock;
    SOCKADDR_IN servAddr;

    char recvmsg[1024];

    WSAStartup(MAKEWORD(2, 2), &wasData);

    hSock = socket(AF_INET, SOCK_STREAM, 0);

    memset(&servAddr, 0, sizeof(servAddr));
    servAddr.sin_family = AF_INET;
    servAddr.sin_addr.s_addr = inet_addr(ip);
    servAddr.sin_port = htons(port);

    connect(hSock, (SOCKADDR*) &servAddr, sizeof(servAddr));

    send(hSock, hello, strlen(hello), 0);
    printf("Client Message sent\n");

    valread = recv(hSock, recvmsg, sizeof(recvmsg) - 1, 0);
    printf("%s\n", recvmsg);

    closesocket은 소켓을 닫는 함수이다. 
    (hSock);

    WSACleanup();
    getch();
    return 0;
}

헤더 분석

stdio, stdlib은 이미 분석했으니 넘어가고
winsock2라는 헤더를 분석해보자.

winsock.h

winsock이란 windows socket API(WSA) 라는 API이다. 인터넷 네트워크와 소켓 관련 함수들을 제공해준다. 뒤의 2는 숫자 2이다.

내부에는 accept, bind, connect, htons, listen 등 우리가 linux에서 사용했던 함수들이 그래도 들어있지만, read, wrtie가 없어서 이건 쓸수 없다.

선언부

	char ip[] = "218.48.17.230";
    int port = 10000;
    int valread;
    char *hello = (char*)"message from Client";

    WSADATA wasData;
    SOCKET hSock;
    SOCKADDR_IN servAddr;

    char recvmsg[1024];

WSADATA wasData

wsadata 구조체이다.

typedef struct WSAData {
  WORD           wVersion;
  WORD           wHighVersion;
#if ...
  unsigned short iMaxSockets;
#if ...
  unsigned short iMaxUdpDg;
#if ...
  char           *lpVendorInfo;
#if ...
  char           szDescription[WSADESCRIPTION_LEN + 1];
#if ...
  char           szSystemStatus[WSASYS_STATUS_LEN + 1];
#else
  char           szDescription[WSADESCRIPTION_LEN + 1];
#endif
#else
  char           szSystemStatus[WSASYS_STATUS_LEN + 1];
#endif
#else
  unsigned short iMaxSockets;
#endif
#else
  unsigned short iMaxUdpDg;
#endif
#else
  char           *lpVendorInfo;
#endif
} WSADATA;

내부 내용들은 다음과 같다.

wVersion

  • 윈도우 소켓 버전.

wHighVersion

  • 윈도우 소켓의 가장 높은 버전. 통상적으로 wVersion과 같다.

szDescription

  • 윈도우 소켓 DLL이 관련한 지위 또는 구성정보를 카피하는 NULL로 끝나는 아스키 문자열.

iMaxSockets

  • 하나의 프로세스가 열 수 있는 소켓의 최대 수.

iMaxUdpDg

  • 데이터그램 프로토콜의 최대 바이트 단위.

Socket hSock

소켓을 생성한다.

SOCKADDR_IN servAddr

앞에서 자주 본 그 구조체이다.

대충 알아봤으니, 이제 함수를 분석해보자.

WSAStartup

int WSAStartup(WORD wVersionRequested, LPWSADATA lpWSAData);

윈도우 소켓에서 특징적인 점은 위 함수로 시작한다는 점이다.
이 함수는 winsock 고나련 라이브러리를 초기화하고 데이터를 넣어줄때 쓰인다.

  • wVersionRequested : 프로그래머가 사용할 버전 전달
  • IpWSAData : WSADATA 구조 체 변수의 주소값 전달

wVersionRequest는 MAKEWORD라는 함수를 받는다.

MAKEWORD(1,2) // 주 버전 1 부 버전 2 0x0201
MAKEWORD(2,2)// 주 버전 2, 부 버전 2 0x0202

따라서 이 함수의 실 사용례는 다음과 같다.

    WSAStartup(MAKEWORD(2, 2), &wasData);

그 외의 함수

그 외의 처리는 linux client와 동일하다. memset으로 메모리를 초기화하여 addr 구조체를 채우고, connect 하고 send recv 한다. closesocket은 소켓을 닫는 함수이다.

WSACleanup

winsock 라이브러리를해체하는 함수이다.

실행

cmd에서 g++로 이걸 실행시키려 하면 네트워크 관련 각종 함수나 타입들을 정의할수 없다고 에러가 발생한다.

따라서 이를 방지하기 위해

#pragma comment(lib, "ws2_32.lib")

을 써주고 동시에 cmd에서 컴파일할때도

gcc -o client client.cpp -lws2_32

를 써서 컴파일 해주면 된다.

리눅스쪽은

g++ -o linux_server linux_server.cpp

실행

이렇게 서로 메세지를 주고받은것을 알 수 있다.

참고로 server는 어차피 둘다 linux에서 작동하도록 짜여진코드라서 어떤 코드를 써도 작동한다.

다음은

문제가 하나 있다. 채팅 프로그램을 만들려면 일단 cpp 멀티스레딩부터 익혀야한다...

다음주부터 spring 학습 및 실습도 들어가야하니 아마 실제로 채팅프로그램을 만드는건 더 오래걸릴지도 모르겠다.

0개의 댓글