본문 바로가기

프로그래밍/C++

[C++ / 소켓프로그래밍] 윈도우 TCP client 구현

급하게 만듬

아직 더 고쳐야 함


#include "stdio.h"

#include "winsock2.h"

#include <string>

#include <iostream>

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

 

#define DESIRED_WINSOCK_VERSION        0x0202

#define MINIMUM_WINSOCK_VERSION        0x0001

 

#define MAXMSGBUFSIZE 1024

#define MAXWAITBUFSIZE 4096


// 메세지 타입

#define ODSP_COMMAND 1

#define ODSP_REQUEST 2

#define ODSP_ACK 3

#define ODSP_ECHO 4

#define ODSP_END 5


// 메세지 헤더

struct ODSP_HDR

{

unsigned int msgType;

unsigned int msgLen;

};


using namespace std;


int main()

{

// 대기 버퍼에서 헤더를 분석할 순서 인지를 판별하기 위한 변수

bool isHeader = true;


// client 종료

bool isExit = false;


// 현재 대기 버퍼에 있는 데이터 길이

unsigned int curLen = 0;


// 보낸 메세지 길이

unsigned int sentMsgLen = 0;

//받은 메세지 길이

unsigned int receivedMsgLen = 0;


// 입력된 메세지를 스트링으로 받는다.

// 메세지의 길이 확인용

string Msg = "";


// 보낼 메세지 버퍼

char bufMsg[MAXMSGBUFSIZE] = {0, };


// 받은 메세지 대기 버퍼

char bufWait[MAXWAITBUFSIZE] = {0, };


// receive 버퍼

char bufRecv[MAXMSGBUFSIZE] = {0, };


// send 버퍼

char bufSend[MAXMSGBUFSIZE] = {0, };


// 받은 헤더 처리 버퍼

char bufHdr[MAXMSGBUFSIZE] = {0, };


// 받은 메세지 처리 버퍼

char bufRecvMsg[MAXMSGBUFSIZE] = {0, };


// 대기 버퍼 스왑용 버퍼

char bufTemp[MAXWAITBUFSIZE] = {0, };


// send 버퍼 인덱스 포인터

char *ptrSendBufIdx = 0;


// 대기 버퍼 인덱스 포인터

char *ptrRecvBufIdx = 0;


// data 정리용 포인터 선언

char *ptrDataSortingIdx = 0;


// 메세지 헤더 구조체 선언

ODSP_HDR hdr;

// receive 헤더 구조체 포인터 선언

ODSP_HDR recv_hdr;


// client 소켓 선언

    SOCKET clientSock;


WSADATA wsadata;


// 서버주소 구조체 변수 선언

    struct sockaddr_in server_addr;

 

    // 소켓을 초기화

    if(!WSAStartup(DESIRED_WINSOCK_VERSION, &wsadata))

{

       if(wsadata.wVersion < MINIMUM_WINSOCK_VERSION)

  {

          WSACleanup();

          exit(1);

       }

    }

 

    // client 소켓 생성

// AF_INET -> ipv4를 의미, PF를 접두사(예: PF_INET)로 쓰는 경우도 있으나 예전 방식

// SOCK_STREAM -> TCP를 의미, SOCK_DGRAM -> UDP 등

// 0 -> SOCK_STREAM으로 프로토콜이 이미 정의 되었음을 의미

clientSock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);


    if(clientSock == INVALID_SOCKET)

{

cout << endl << "socket error : " ;

       //printf("socket error : ");

       WSACleanup();

       exit(1);

    }

 

    memset(&server_addr, 0, sizeof(server_addr));


// 서버 주소 지정

// AF_INET -> ipv4

    server_addr.sin_family = AF_INET;

    server_addr.sin_addr.s_addr = inet_addr("192.168.1.182");

    server_addr.sin_port = htons(30000);


// 서버에 접속 요청 

// 서버는 listen 하고 있다가 접속요청을 받고 3-way handshake

    if(connect(clientSock, (LPSOCKADDR)&server_addr, sizeof(server_addr)) != 0)

{

cout << endl << "connect error : " ;

       //printf("connect error : ");

       exit(1);

    }


ptrRecvBufIdx = bufWait;


while(true)

{

// message type을 입력 받음

cout << endl << "1 - COMMAND" << endl;

cout << "2 - REQUEST" << endl;

cout << "3 - ACK" << endl;

cout << "4 - ECHO" << endl;

cout << "5 - END" << endl;

cout << "input message type : " ;


// 헤더구조체의 메세지 타입에 입력

cin >> hdr.msgType;

//cin.clear();

//cout.clear();

cout << "input message : " ;

//cin >> bufMsg;

cin.getline(bufMsg, 1024, '\n');

cin.clear();

getline(cin, Msg);

//Msg = bufMsg;

hdr.msgLen = Msg.length();

strcpy(bufMsg, Msg.c_str());

// 헤더와 메세지를 결합

ptrSendBufIdx = bufSend;

memcpy(ptrSendBufIdx, &hdr, sizeof(hdr));

ptrSendBufIdx = ptrSendBufIdx+sizeof(hdr);

memcpy(ptrSendBufIdx, bufMsg, hdr.msgLen);


// 메세지 전송

if(sentMsgLen = send(clientSock, bufSend, sizeof(hdr) + hdr.msgLen, 0) < 0)

{

cout << endl << "send error!!" << endl;

return 0;

}

if(hdr.msgType == ODSP_END)

{

break;

}


if(hdr.msgType == ODSP_COMMAND || hdr.msgType == ODSP_ECHO)

{

// 메세지 수신

while(true)

{

memset(bufRecv, 0, sizeof(bufRecv));


// 메세지 수신

receivedMsgLen = recv(clientSock, bufRecv, MAXMSGBUFSIZE, 0);


if(receivedMsgLen >= 0)

{

memcpy(ptrRecvBufIdx, bufRecv, receivedMsgLen);

curLen += receivedMsgLen;

ptrRecvBufIdx += receivedMsgLen;

receivedMsgLen = 0;


// 헤더를 분석할 순서

if(isHeader)

{

// 헤더 길이 이상의 data가 있는지 확인

//if(curLen >= sizeof(recv_hdr))

if(curLen >= sizeof(hdr))

{

memset(bufHdr, 0, sizeof(bufHdr));

//memcpy(bufHdr, bufWait, sizeof(recv_hdr));

memcpy(bufHdr, bufWait, sizeof(hdr));

//bufHdr[sizeof(recv_hdr)] = '\0';

bufHdr[sizeof(hdr)] = '\0';

memcpy(&recv_hdr, bufHdr, sizeof(recv_hdr));

//recv_hdr = (ODSP_HDR*)bufHdr;


// 버퍼의 data를 정리

ptrDataSortingIdx = bufWait + sizeof(recv_hdr);

memset(bufTemp, 0, sizeof(bufTemp));

memcpy(bufTemp, ptrDataSortingIdx, sizeof(bufWait) - sizeof(recv_hdr));

memset(bufWait, 0, sizeof(bufWait));

memcpy(bufWait, bufTemp, sizeof(bufTemp));


curLen -= sizeof(recv_hdr);

ptrRecvBufIdx -= sizeof(recv_hdr);

isHeader = false;

}

}


if(!isHeader)

{

// 분석된 헤더의 메세지 길이 정보를 통해 현재 버퍼에 메세지 길이 이상의 data가 있는지 확인

if(curLen >= recv_hdr.msgLen)

{

memset(bufRecvMsg, 0, sizeof(bufRecvMsg));

memcpy(bufRecvMsg, bufWait, recv_hdr.msgLen);

bufRecvMsg[recv_hdr.msgLen] = '\0';


// 버퍼의 data를 정리

ptrDataSortingIdx = bufWait + recv_hdr.msgLen;

memset(bufTemp, 0, sizeof(bufTemp));

memcpy(bufTemp, ptrDataSortingIdx, sizeof(bufWait) - recv_hdr.msgLen);

memset(bufWait, 0, sizeof(bufWait));

memcpy(bufWait, bufTemp, sizeof(bufTemp));


curLen -= recv_hdr.msgLen;

ptrRecvBufIdx -= recv_hdr.msgLen;

isHeader = true;


if(recv_hdr.msgType == ODSP_COMMAND)

{

cout << endl << "received command message" << endl;

cout << "message length is " << recv_hdr.msgLen << "byte" << endl;

cout << "receive message : " << bufRecvMsg << endl;

break;

}

else if(recv_hdr.msgType == ODSP_REQUEST)

{

cout << endl << "received request message" << endl;

cout << "message length is " << recv_hdr.msgLen << "byte" << endl;

cout << "receive message : " << bufRecvMsg << endl;

break;

}

else if(recv_hdr.msgType == ODSP_ACK)

{

cout << endl << "received ack message" << endl;

cout << "message length is " << recv_hdr.msgLen << "byte" << endl;

cout << "receive message : " << bufRecvMsg << endl;

break;

}

else if(recv_hdr.msgType == ODSP_ECHO)

{

cout << endl << "received echo message" << endl;

cout << "message length is " << recv_hdr.msgLen << "byte" << endl;

cout << "receive message : " << bufRecvMsg << endl;

break;

}

else if(recv_hdr.msgType == ODSP_END)

{

cout << endl << "received end message" << endl;

cout << "message length is " << recv_hdr.msgLen << "byte" << endl;

cout << "receive message : " << bufRecvMsg << endl;


isExit = true;

break;

}

else

{

cout << endl << "received unknown message" << endl;

cout << "exit client" << endl;

return 0;

}

}

}

}

else

{

break;

}

}

}

  }


    // 소켓을 닫음

closesocket(clientSock);

  

cout << "client exit" << endl;

    return 0;

}