// 서버
#include<WinSock2.h>
#include<mswsock.h>
#include<ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
// 전체적인 흐름
// winsock 초기화 -> socket 생성 -> 내 서버 주소 정의 -> bind
// -> listen -> accept
WSADATA wsaData;
int32 err;
err = ::WSAStartup(MAKEWORD(2, 2), &wsaData);
if (err != 0)
{
cout << "Winsock Initialize Failed\n" << err << " : error exists";
return 0;
}
// 상담을 받아주는 안내원( 회사의 공식 대표 번호)
// 말 그대로 처음 clinetsocket을 받아주는 소켓이라 보면됨
SOCKET listenSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket == INVALID_SOCKET)
{
err = ::WSAGetLastError();
cout << "Socket ErrorCode : " << err << endl;
return 0;
}
// 회사의 대표 주소지 설정
SOCKADDR_IN serverAddr;
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
// 니가 알아서 골라줘 네트워크 카드가 여러개일 경우 해결
serverAddr.sin_addr.s_addr = ::htonl(INADDR_ANY);
serverAddr.sin_port = ::htonl(7777);
// 안내원 폰 개통! 식당의 대표 번호
err = ::bind(listenSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
if (err == SOCKET_ERROR)
{
err = ::WSAGetLastError();
cout << "Bind ErrorCode : " << err << endl;
return 0;
}
// 영업 시작
// parameter
// 1. socket
// 2. backlog(대기열의 최대 한도)
err = ::listen(listenSocket, 15);
if (err == SOCKET_ERROR)
{
err = ::WSAGetLastError();
cout << "Listen ErrorCode : " << err << endl;
return 0;
}
//---------------
while (true)
{
SOCKADDR_IN clientAddr;
::memset(&clientAddr, 0, sizeof(clientAddr));
int32 addrLen = sizeof(clientAddr);
// accept 뒤의 두개 파라미터는 생략 가능
SOCKET clientSocket = ::accept(listenSocket, (SOCKADDR*)&clientAddr, &addrLen);
if (clientSocket == INVALID_SOCKET)
{
err = ::WSAGetLastError();
cout << "Accept ErrorCode : " << err << endl;
return 0;
}
}
//---------------
return 0;
}
// 클라이언트
#include "pch.h"
#include <CorePch.h>
#include <WinSock2.h>
#include <mswsock.h>
#include <ws2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
int main()
{
// 전체적인 흐름
// wsastartup(초기화) -> socket 준비 -> socket addr 준비 -> connect -> wsacleanup()
WSADATA wsData;
// winsock을 사용할 준비가 되었다(ws2_32 라이브러리 초기화)
// parameter
// 1. winsock 버전
// 2. winsock 관련 정보가 wsData에 채워짐
// 성공시 return 값이 0임
int err = ::WSAStartup(MAKEWORD(2, 2), &wsData);
if (err != 0)
{
cout << "WSAStartUp initialize failed\n" << err << " : error exists";
return 0;
}
// 전화를 걸 전화기 생성 ( 이 socket을 이용해 데이터 전송 )
// parameter
// 1. 주소체계(IPv4 / IPv6) -> 네트워크 주소 할당의 문제로 새로운 주소 체계 편입
// AF_INET(IPv4 주소 체계)
// AF_INET(IPv6 주소 체계)
// 2. socket type (TCP / UDP)
// SOCK_STREAM(TCP활용) / SOCK_DGRAM(UDP활용)
// 신뢰성 / 비신뢰성(패킷 소실의 위험성이 있음)
// 왠만하면 TCP 사용
// 3. protocol은 0으로 입력(default값)
// return : descriptor를 return 함
SOCKET clientSocket = ::socket(AF_INET, SOCK_STREAM, 0);
if (clientSocket == INVALID_SOCKET)
{
int32 errCode = ::WSAGetLastError();
cout << "Socket ErrorCode : " << errCode << endl;
return 0;
}
// 식당 번호 입력
SOCKADDR_IN serverAddr; // IPv4 용
// SOCKADDR_IN6 IPv6용
::memset(&serverAddr, 0, sizeof(serverAddr));
// IPv4용이기때문에 항상 AF_INET을 설정해야함
serverAddr.sin_family = AF_INET;
// 주소체계는 1바이트씩 끊어서 사용 2^8 -> 256까지
// inet_addr은 너무 구식
// serverAddr.sin_addr.S_un.S_addr = ::inet_addr("192.168.123.100");
// 127.0.0.1 루프백 주소(내 자신의 컴퓨터 ip)
// 나중에는 DNS를 활용
::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
// 포트 번호 연결할 목적지는? ( IP주소 + Port )-> IP아파트 Port 동
// 일부 번호는 예약 되어있기 때문에 port는 이왕이면 10000번대를 넘어서 등록하면 좋다
// htons
// host to network short
// network to host short
// Little-Endian vs Big-Endian
// ex) 0x12345678 4바이트 정수
// [0x78][0x56][0x34][0x12] <- little
// [0x12][0x34][0x56][0x78] <- big
// 요즘 대부분은 리틀엔디안 사용(intel corp.)
// network에서는 빅엔디안을 사용함
serverAddr.sin_port = ::htons(7777);
// 그 주소로 전화를 걸기!
// parameter
// 1. socket
// 2. socketaddr
// -> 전화를 걸 대상 ( type casting 하는 이유는 주소 체계가 다 다르기 때문에 공통되게 만들어줌)
err = ::connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr));
if (err == SOCKET_ERROR)
{
int32 errCode = ::WSAGetLastError();
cout << "Connect ErrCode : " << errCode << endl;
return 0;
}
// 연결 성공 ! 이제부터 데이터 송수신 가능!
cout << "Connected To Server!" << endl;
while (true)
{
// TODO
}
// 소켓 리소스 반환
::closesocket(clientSocket);
// winsock 해제
::WSACleanup();
}