1) 핸드폰 준비
== 소켓 준비
2) 식당 번호로 문의
== 서버 주소로 connect
3) 식당 안내원이 대리인에 연결, 식당 측과 대화 가능
== 소켓을 통해 서버와 패킷 송수신 가능
1) 식당 안내원 고용
== Linstner 소켓 준비
2) 안내원의 준비 과정 (식당 번호 배정)
== Bind(서버 주소/Port를 소켓에 연동)
3) 영엽 시작
== Listen
4) 안내
== Accept
5) 안내원이 대리인에 연결, 손님과 대화 가능
== 클라이언트 세션을 통해 패킷 송수신
#include "pch.h"
// 윈도우즈 버전의 소켓 라이브러리
#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
#include <thread>
// 정적 라이브러리 링크
#pragma comment(lib, "ws2_32.lib")
int main() {
// WinSock 라이브러리(ws2_32.lib) 초기화
WSAData wsData;
if (::WSAStartup(MAKEWORD(2, 2), &wsData) != 0) {
// 초기화 실패
return 0;
}
// 1. 핸드폰 준비 == 소켓 생성
//::socket(); // (주소체계, 소켓 타입, 프로토콜)
// 프로토콜의 경우 0으로 전달하면 알아서 프로토콜을 정해줌
// TCP/IP 프로토콜 군으로 셋팅될 것
SOCKET clientSock = ::socket(AF_INET, SOCK_STREAM, 0);
if (clientSock == INVALID_SOCKET) {
// 소켓 생성 실패시 에러 메시지 출력
int32 errCode = ::WSAGetLastError();
cout << "Socket Err Code: " << errCode << endl;
return 0;
}
// 2. 식당 번호로 문의하기 전 준비 단계 == 서버 주소 준비
SOCKADDR_IN serverAddr;
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
// (구버전)
//serverAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 루프백 주소(스스로의 컴퓨터에 패킷 전달)
// "127.0.0.1" => 4바이트 정수 // 실제로는 서버 주소를 전달해야함.
// (신버전)
::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
serverAddr.sin_port = ::htons(7777);
// host to network 변환, 호스트에서 네트워크 방식 엔디안으로 변환
// well-known 포트 번호는 쓰지 않도록..
// 3. 식당 번호로 문의 == connect
if (::connect(clientSock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
int32 errCode = ::WSAGetLastError();
cout << "Connect Err Code: " << errCode << endl;
return 0;
}
// 4. 로그
cout << "DONE" << endl;
// 소켓 리소스 반환
::closesocket(clientSock);
// 윈속 종료
::WSACleanup();
}
#include "pch.h"
// 윈도우즈 버전의 소켓 라이브러리
#include <WinSock2.h>
#include <MSWSock.h>
#include <WS2tcpip.h>
// 정적 라이브러리 링크
#pragma comment(lib, "ws2_32.lib")
int main() {
// WinSock 라이브러리(ws2_32.lib) 초기화
WSAData wsData;
if (::WSAStartup(MAKEWORD(2, 2), &wsData) != 0) {
// 초기화 실패
return 0;
}
// 1. 핸드폰 준비 == 소켓 생성
//::socket(); // (주소체계, 소켓 타입, 프로토콜)
// 프로토콜의 경우 0으로 전달하면 알아서 프로토콜을 정해줌
// TCP/IP 프로토콜 군으로 셋팅될 것
SOCKET listenSock = ::socket(AF_INET, SOCK_STREAM, 0);
if (listenSock == INVALID_SOCKET) {
// 소켓 생성 실패시 에러 메시지 출력
int32 errCode = ::WSAGetLastError();
cout << "Socket Err Code: " << errCode << endl;
return 0;
}
// 2. 식당 번호를 바탕으로 통신 준비 == 서버 주소를 바탕으로 셋팅
SOCKADDR_IN serverAddr;
::memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin_family = AF_INET;
::inet_pton(AF_INET, "127.0.0.1", &serverAddr.sin_addr);
serverAddr.sin_port = ::htons(7777);
// bind
if (::bind(listenSock, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
int32 errCode = ::WSAGetLastError();
cout << "Bind Err Code: " << errCode << endl;
return 0;
}
// 3. 영업 시작 == listen
if (::listen(listenSock, 10) == SOCKET_ERROR) {
// 백로깅(10): 대기열의 최대 한도
int32 errCode = ::WSAGetLastError();
cout << "Listen Err Code: " << errCode << endl;
return 0;
}
// 4. 전화 연결 -> 안내 == accept
while (true) {
SOCKADDR_IN clientAddr;;
::memset(&clientAddr, 0, sizeof(clientAddr));
int32 clientAddrLen = sizeof(clientAddr);
// 안내원 -> 대리인 전화기로 연결 토스
// 클라이언트와 연결된 소켓이란 의미로 "clientSock"
SOCKET clientSock = ::accept(listenSock, (SOCKADDR*)&clientAddr, &clientAddrLen);
if (clientSock == INVALID_SOCKET) {
int32 errCode = ::WSAGetLastError();
cout << "Accept Err Code: " << errCode << endl;
return 0;
}
// 손님 입장
char ipAddr[16];
::inet_ntop(AF_INET, &clientAddr.sin_addr, ipAddr, sizeof(ipAddr));
cout << "Client Connect IP: " << ipAddr << endl;
// 소켓 리소스 반환
::closesocket(listenSock);
// 윈속 종료
::WSACleanup();
}
int main() {
...
...
// 4. 로그
cout << "DONE" << endl;
while (true) {
this_thread::sleep_for(1s);
char sendBuffer[100] = "Hello World!";
int32 retCode = ::send(clientSock, sendBuffer, sizeof(sendBuffer), 0);
if (retCode == SOCKET_ERROR) {
int32 errCode = ::WSAGetLastError();
cout << "Send Err Code: " << errCode << endl;
return 0;
}
cout << "SEND DONE" << endl;
char recvBuffer[1000];
int32 retDataSize = ::recv(clientSock, recvBuffer, sizeof(recvBuffer), 0);
if (retDataSize == 0) {
cout << "FINISH" << endl;
break;
}
cout << "Recv Data: " << recvBuffer << endl;
cout << "Recv Data Len: " << retDataSize << endl;
}
*/
// 소켓 리소스 반환
::closesocket(clientSock);
// 윈속 종료
::WSACleanup();
}
int main() {
...
...
// 4. 전화 연결 -> 안내 == accept
while (true) {
...
...
// 손님 입장
char ipAddr[16];
::inet_ntop(AF_INET, &clientAddr.sin_addr, ipAddr, sizeof(ipAddr));
cout << "Client Connect IP: " << ipAddr << endl;
while (true) {
char recvBuffer[1000];
int32 retDataSize = ::recv(clientSock, recvBuffer, sizeof(recvBuffer), 0);
if (retDataSize == 0) {
cout << "FINISH" << endl;
break;
}
cout << "Recv Data: " << recvBuffer << endl;
cout << "Recv Data Len: " << retDataSize << endl;
char ackBuffer[] = "ACK";
int32 retCode = ::send(clientSock, ackBuffer, sizeof(ackBuffer), 0);
if (retCode == SOCKET_ERROR) {
int32 errCode = ::WSAGetLastError();
cout << "Send Err Code: " << errCode << endl;
return 0;
}
}
}
// 소켓 리소스 반환
::closesocket(listenSock);
// 윈속 종료
::WSACleanup();
}