소켓 통신에 사용되는 기본 API는 char*를 보내고 받는다. 하지만 많은 경우에 구조체를 보내야 할 경우가 있다.
각설하고, 이를 하는 방법에 대해 알아보자.
1. 프로젝트를 만들자. (콘솔)
2. ws2_32.lib를 추가한다.
헤더파일 winsock2.h 를 추가한다.
ws2_32.lib라이브러리를 링크시켜야 한다.
ws2_32.lib 라이브러리를 링크시키는 방법 ( 현재 Visual Studio 2008을 쓰고 있음 )
프로젝트 -> 속성 -> 구성 속성 -> 링커 -> 입력 -> 추가 종속성
ws2_32.lib
3. 아래 코드를 이용해서 두 프로젝트를 만든다.
- main.cpp를 아래 코드로 바꾸면 된다.
4. 실제 수행 화면
서버 코드
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
void ErrorHandling(char* message);
struct socketStruct {
int nrData;
double data[100];
};
int _tmain(int argc, _TCHAR* argv[])
{
int portNum = 1234;
// 보낼 데이터를 초기화한다.
socketStruct txData, TermData;
txData.nrData = 3;
for(int i = 0; i<txData.nrData; i++)
{
txData.data[i] = i*10;
}
TermData.nrData = 0;
WSADATA wsaData;
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAddr, clntAddr;
int szClntAddr;
char message[]="Hello World!";
if(WSAStartup(MAKEWORD(2, 2), &wsaData)!=0)
ErrorHandling("WSAStartup() error!");
hServSock=socket(PF_INET, SOCK_STREAM, 0);
if(hServSock==INVALID_SOCKET)
ErrorHandling("socket() error");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family=AF_INET;
servAddr.sin_addr.s_addr=htonl(INADDR_ANY);
servAddr.sin_port = htons(portNum);
if(bind(hServSock, (SOCKADDR*) &servAddr, sizeof(servAddr))==SOCKET_ERROR)
ErrorHandling("bind() error");
if(listen(hServSock, 5)==SOCKET_ERROR)
ErrorHandling("listen() error");
szClntAddr=sizeof(clntAddr);
// 아래 함수에서 holding하고 있는다.
printf("[Server] Holding at accept \n");
hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr);
if(hClntSock==INVALID_SOCKET)
ErrorHandling("accept() error");
// 보내는 부분이다.
int maxCnt = 5;
while(1)
{
send(hClntSock, (char*)&txData, sizeof(txData), 0);
Sleep(100);
if(maxCnt-- < 0)
{
break;
}
}
send(hClntSock, (char*)&TermData, sizeof(TermData), 0);
// 소켓 종료
printf("Closing Socket \n");
closesocket(hClntSock);
closesocket(hServSock);
WSACleanup();
return 0;
}
void ErrorHandling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
클라이언트 코드
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
void ErrorHandling(char* message);
struct socketStruct {
int nrData;
double data[100];
};
int _tmain(int argc, _TCHAR* argv[])
{
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;
// char*를 받은 후에 원하는 형태로 type cast를 한다.
char message[500];
socketStruct* RxData;
int strLen;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0)
ErrorHandling("WSAStartup() errer!");
hSocket=socket(PF_INET, SOCK_STREAM, 0);
if(hSocket==INVALID_SOCKET)
ErrorHandling("hSocketet() error!");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family=AF_INET;
servAddr.sin_addr.s_addr=inet_addr("127.0.0.1");
servAddr.sin_port=htons(1234);
if(connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr))==SOCKET_ERROR)
ErrorHandling("connect() error!");
while(1)
{
Sleep(10);
strLen = recv(hSocket, message, sizeof(message)-1, 0);
if(strLen == 0)
{
continue;
}
// 받은 것을 형 변환으로 원하는 값으로 바꾼다.
message[strLen] = '\0';
RxData = (socketStruct*)message;
if(strLen == -1)
ErrorHandling("read() error!");
int nrData = RxData->nrData;
// 받은 데이터의 nrData = 0이면 종료한다.
if(nrData == 0)
break;
for(int i = 0; i < nrData; i++)
printf("Message from server:[%d] %.1f \n", i, RxData->data[i]);
}
// 소켓 종료
printf("Closing Socket \n");
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}
Vicon 클라이언트
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <winsock2.h>
void ErrorHandling(char* message);
struct socketStruct {
int nrData;
double data[3];
};
int _tmain(int argc, _TCHAR* argv[])
{
char* IPaddr = "192.168.0.5";
int portNum = 1234;
WSADATA wsaData;
SOCKET hSocket;
SOCKADDR_IN servAddr;
// char*를 받은 후에 원하는 형태로 type cast를 한다.
// char message[100];
socketStruct* RxData;
int strLen;
if(WSAStartup(MAKEWORD(2, 2), &wsaData) !=0)
ErrorHandling("WSAStartup() errer!");
hSocket=socket(PF_INET, SOCK_STREAM, 0);
if(hSocket==INVALID_SOCKET)
ErrorHandling("hSocketet() error!");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family=AF_INET;
servAddr.sin_addr.s_addr=inet_addr(IPaddr);
servAddr.sin_port=htons(portNum);
if(connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr))==SOCKET_ERROR)
ErrorHandling("connect() error!");
while(1)
{
Sleep(50);
char message[100];
strLen = recv(hSocket, message, sizeof(message)-1, 0);
if(strLen == 0)
{
continue;
}
// 받은 것을 형 변환으로 원하는 값으로 바꾼다.
message[strLen] = '\0';
RxData = (socketStruct*)message;
if(strLen == -1)
ErrorHandling("read() error!");
int nrData = RxData->nrData;
// 받은 데이터의 nrData = 0이면 종료한다.
if(nrData == 0)
break;
// 데이터를 읽어온다.
double x = RxData->data[0];
double y = RxData->data[1];
double z = RxData->data[2];
printf("Message from server:%.1f %.1f %.1f \n", x, y, z);
}
// 소켓 종료
printf("Closing Socket \n");
closesocket(hSocket);
WSACleanup();
return 0;
}
void ErrorHandling(char* message)
{
fputs(message, stderr);
fputc('\n', stderr);
exit(1);
}