windows socket프로그래밍
예전에 한번 windows운영체제에서 tcp로 채팅하는 간단한 프로그래밍을 짜봤었는데, 오랜만에 다시 하려하니 다까먹어서 글 한번 남기려고 쓴다.
윈속 프로그래밍을 할 때는 반드시 WSAStartup()함수를 호출해서, 프로그램에서 요구하는 윈도우 소켓의 버전을 알리고, 해당 버전을 지원하는 라이브러리의 초기화 작업을 진행해야 한다.
그리고 윈속관련 함수의 호출이 불필요하거나 프로그램이 종료되기 직전에 WSACleanup()함수를 호출하여, 할당된 윈속 라이브러리를 윈도우 운영체제에 반환을 해야한다.
아직 왜 라이브러리를 운영체제에 반환을 해야하는지는 이해가지 않는다.
서버
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
void Error(char* m);
int main()
{
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) Error("WSAStartup() error");
SOCKET hServSock, hClntSock;
SOCKADDR_IN servAddr, clntAddr;
int szClntAddr;
char message[30] = "this is message";
hServSock = socket(PF_INET, SOCK_STREAM, 0);
if (hServSock == INVALID_SOCKET) Error("socket() error");
memset(&servAddr, 0, sizeof(servAddr));
servAddr.sin_family = AF_INET;
servAddr.sin_addr.s_addr = htonl(INADDR_ANY);
servAddr.sin_port = htons(atoi("9876"));
if (bind(hServSock, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) Error("bind() error");
if (listen(hServSock, 5) == SOCKET_ERROR) Error("listen() error");
szClntAddr = sizeof(clntAddr);
hClntSock = accept(hServSock, (SOCKADDR*)&clntAddr, &szClntAddr);
if (hClntSock == INVALID_SOCKET) Error("accept() error");
send(hClntSock, message, sizeof(message), 0);
closesocket(hClntSock);
closesocket(hServSock);
WSACleanup();
return 0;
}
void Error(char* m)
{
printf("%s \n", m);
exit(1);
}
위의 코드에서 Error같은 것을 빼고 이해하기 쉽게 한번 코드를 다시 정리해보자.
처음 WSAStartup()으로 윈속 라이브러리를 초기화한다.
socket()함수로 소켓을 생성한다.
bind()함수로 소켓의 ip주소와 port번호를 할당한다.
listen()함수로 소켓이 클라이언트 포르그램의 연결 요청을 받아들일 수 있는 상태가 되게 한다.
accept()함수로 클라이언트 프로그램의 연결 요청을 수락한다.
클라이언트
#include <iostream>
#include <WinSock2.h>
#pragma comment(lib, "ws2_32.lib")
void Error(char* m)
{
printf("%s \n", m);
exit(1);
}
int main()
{
WSADATA wsadata;
if (WSAStartup(MAKEWORD(2, 2), &wsadata) != 0) Error("WSAStartup() error");
SOCKET hSocket;
SOCKADDR_IN servAddr;
char message[30];
int strLen;
hSocket = socket(PF_INET, SOCK_STREAM, 0);
if (hSocket == INVALID_SOCKET) Error("socket() 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(atoi("9876"));
if (connect(hSocket, (SOCKADDR*)&servAddr, sizeof(servAddr)) == SOCKET_ERROR) Error("connect() error");
strLen = recv(hSocket, message, sizeof(message) - 1, 0);
if (strLen == -1) Error("recv() error");
printf("Message: %s", message);
closesocket(hSocket);
WSACleanup();
return 0;
}
클라이언트도 간략화 해보자.
WSAStartup()함수로 윈속 라이브러리를 초기화한다.
socket()함수로 소켓을 생성한다.
connect()함수는 소켓을 기반으로 연결요청을 할 때 호출한다.
-20.11.26추가
DWORD recvTimeout = 5000; // 5초.
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&recvTimeout, sizeof(recvTimeout));
recv함수를 사용하면 무기한 대기에 들어간다. 이를 일정시간만 대기시키고싶다면 위 함수를 이용하자.