#include<stdio.h>#include<winsock2.h>#include<windows.h>#pragma comment(lib, "ws2_32")//#define _WINSOCK_DEPRECATED_NO_WARNINGS#define BUFSIZE 1024intmain(){
/* WSAStartup 함수의 인자로 들어가는 변수입니다. */
WSADATA wsaData;
/* socket 함수의 반환값을 저장할 UINT_PTR 변수입니다. */
SOCKET client;
/* SOCKADDR_IN https://docs.microsoft.com/ko-kr/windows/win32/api/winsock/ns-winsock-sockaddr_in
* 소켓의 주소를 담는 기본 구조체 역할을 합니다.
* 선택한 프로토콜에 따라 구조가 달라지며, 네트워크 바이트 순서대로 표현됩니다.
* 2바이트의 family 부분과 14바이트의 data부분으로 나눠집니다.
*/
SOCKADDR_IN server_addr;
/* 보낼 문자열과 받은 문자열을 저장할 변수입니다. */char buffer[BUFSIZE];
int size;
/* WSAStartup https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsastartup
* WSACleanup 함수와 같이 사용되며 소켓 프로그램의 시작을 나타냅니다.
*
* 첫번째 인자에는 winsock 버전을 넣습니다.
* 상위 2바이트에는 주 버전 번호, 하위 2바이트에는 부 버전 번호를 넣습니다.
* 2.2버전을 사용할려면 0x0202 또는 MAKEWORD(2,2)를 사용하면 됩니다.
*
* 두번째 인자에는 WSADATA 구조체의 포인터를 넣습니다.
* 이 포인터는 윈도우 소켓 구현에 대한 세부정보를 받는 WSADATA 타입 구조체의 포인터입니다.
*
* 성공하면 0을 반환하고, 실패하면 나열된 오류 코드중 하나를 반환합니다.
* 오류코드를 반환하기 때문에 WSAGetLastError 함수의 호출은 필요하지 않으며, 사용하면 안됩니다.
*/WSAStartup(0x0202, &wsaData);
/* socket https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-socket
* 소켓을 만듭니다.
*
* 첫번째 인자에서는 주소 계열을 지정해줍니다.
* AF_* 상수와 PF_* 상수의 값이 동일하기 때문에 원하는 상수를 쓰면 됩니다.
*
* 두번째 인자에서는 소켓의 유형을 지정해줍니다.
*
* 세번째 인자에서는 소켓의 프로토콜을 지정해줍니다.
* 값을 0으로 지정하면 프로토콜을 지정하지 않고 서버가 사용할 프로토콜을 선택합니다.
*
* 오류가 발생하지 않으면 새 소켓을 참조하는 descriptor 를 반환합니다.
* 그렇지 않으면 INVALID_SOCKET 값이 반환되고 WSAGetLastError를 호출하여 오류코드를 반환받을 수 있습니다.
*/
client = socket(AF_INET, SOCK_STREAM, 0);
if (client == INVALID_SOCKET) { //에러 핸들링printf("socket error, error code : %d", WSAGetLastError());
system("pause");
return1;
}
printf("socket descriptor : %d\n", client);
// server_addr 변수를 0으로 초기화 해줍니다.memset(&server_addr, 0, sizeof(server_addr));
// 주소 체계를 AF_INET(IPv4)로 지정합니다.
server_addr.sin_family = AF_INET;
// 주소를 152.70.238.188로 지정합니다.
server_addr.sin_addr.S_un.S_addr = inet_addr("152.70.238.188");
/* 포트를 3000으로 지정해주는데,
* htons 함수는 2바이트 데이터를 네트워크 바이트 정렬 방식으로 변경합니다.
*/
server_addr.sin_port = htons(3000);
/* connect https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-connect
* SOCKET 변수와 주소 변수를 받아서 소켓을 연결합니다.
*
* 첫번째 인자는 연결되지 않은 소켓의 descriptor을 넣습니다.
* 두번째 인자는 SOCKADDR_IN 변수를 sockaddr 구조체의 포인터로 변경하여 넣어줍니다.
* 세번째 인자는 sockaddr 구조체의 크기를 넣어줍니다.
*
* 오류가 발생하지 않으면 0을 반환하고, 아니면 SOCKET_ERROR를 반환합니다.
* socket 함수와 같이 WSAGetLastError 를 통해서 오류코드를 반환받을 수 있습니다.
* 비 블로킹 소켓(비동기)을 사용하면 SOCKET_ERROR를 반환하고,
* WSAGetLastError에서 WSAEWOULDBLOCK를 반환합니다.
*/int con = connect(client, (struct sockaddr*)&server_addr, sizeof(server_addr));
if (con == SOCKET_ERROR) {
printf("connect error, error code : %d\n", WSAGetLastError());
system("pause");
return1;
}
// 연결이 성공됨을 출력합니다.printf("----------------------connect success----------------------\n\n");
// buffer를 비웁니다.memset(buffer, 0, BUFSIZE);
// buffer에 "10215" 문자열을 복사합니다.strcpy(buffer, "10215");
// 소켓에 전송합니다./* send https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-send
* 연결된 소켓에 데이터를 전송합니다.
*
* 첫번째 인자엔 연결된 소켓의 descriptor가 들어갑니다.
* 두번째 인자엔 전송할 데이터를 포함하는 버퍼의 포인터가 들어갑니다.
* 세번째 인자엔 버퍼의 크기가 들어갑니다.
* 네번째 인자엔 플래그가 들어갑니다.
*
* MSG_DONTROUTE, MSG_OOB 가 비트연산자를 통해 들어갑니다.(0은 지정 안함)
* 오류가 없으면 전송된 총 바이트 수를 반환하고, 그렇지 않으면 SOCKET_ERROR 값이 반환됩니다.
* WSAGetLastError를 통해 오류코드를 반환받을 수 있습니다.
*/
size = send(client, buffer, BUFSIZE, 0);
if (size == SOCKET_ERROR){
printf("send error, error code : %d\n", WSAGetLastError());
system("pause");
return1;
}
// 전송한 메세지를 출력합니다.printf("sent message: \"%s\"\n", buffer);
// 버퍼를 0으로 비웁니다.memset(buffer, 0, BUFSIZE);
/* recv https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-recv
* 연결된 소켓에서 데이터를 수신합니다.
*
* 첫번째 인자엔 연결된 소켓의 descriptor가 들어갑니다.
* 두번째 인자엔 수신할 데이터를 받을 버퍼의 포인터가 들어갑니다.
* 세번째 인자엔 버퍼의 크기가 들어갑니다.
* 네번째 인자엔 플래그가 들어갑니다.
*
* MSG_PEEK, MSG_OOB, MSG_WAITALL가 비트연산자를 통해 들어갑니다.(0은 지정 안함)
* 오류가 없으면 수신된 총 바이트 수를 반환하고, 그렇지 않으면 SOCKET_ERROR 값이 반환됩니다.
* WSAGetLastError를 통해 오류코드를 반환받을 수 있습니다.
*/
size = recv(client, buffer, BUFSIZE, 0);
if (size == SOCKET_ERROR){
printf("receive error, error code : %d\n", WSAGetLastError());
system("pause");
return1;
}
// 수신한 메세지를 출력합니다.printf("received message: \"%s\"\n", buffer);
/* WSACleanup https://docs.microsoft.com/en-us/windows/win32/api/winsock/nf-winsock-wsacleanup
* WSAStartup 함수와 같이 사용되며 소켓 프로그램의 끝을 나타냅니다.
*
* 작업에 성공하면 0을 반환하고, 그렇지 않으면 SOCKET_ERROR 값을 반환합니다.
* WSAGetLastError를 통해 오류코드를 반환받을 수 있습니다.
*/if (WSACleanup() == SOCKET_ERROR){
printf("socket terminate error, error code : %d\n", WSAGetLastError());
}
system("pause");
}
client는 주석에서 설명을 거의 다 해놨기 때문에, server 부분만 약간 설명을 하겠습니다.