Socket Programming
소켓 프로그래밍은 네트워크를 통해 서로 다른 시스템에서 실행되는
두 프로세스 간의 통신을 설정하기 위해 컴퓨터 네트워킹에서 사용되는 기술입니다.
클라이언트-서버 아키텍처를 사용하여 프로세스 간에 데이터를 전송합니다.
소켓 프로그래밍 구조에는 다음 단계가 포함됩니다.
1. 소켓 만들기
소켓 프로그래밍의 첫 번째 단계는 네트워크 연결의 끝점을 나타내는 데이터 구조인 소켓을 만드는 것입니다.
소켓은 도메인, 유형 및 프로토콜의 세 가지 매개 변수를 사용하는 socket() 함수를 사용하여 만들 수 있습니다.
DWORD WINAPI TCPServer4(LPVOID arg)
{
int retval; // return value
SOCKET listenSocket = socket(AF_INET, SOCK_STREAM, 0);
if (listenSocket == INVALID_SOCKET) {
// err
}
domain 매개변수는 IPv4 또는 IPv6과 같은 주소 계열을 지정하고
type 매개변수는 TCP 또는 UDP와 같은 통신 프로토콜을 지정합니다.
프로토콜 매개변수는 일반적으로 운영 체제가 기본 프로토콜을 선택할 수 있도록 0으로 설정됩니다.
struct sockaddr_in serveraddr;
memset(&serveraddr, 0, sizeof(serveraddr)); // 0으로 초기화
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY); // 000으로 초기화
serveraddr.sin_port = htons(PORTNUM); // 서버포트 9000
2. 소켓 바인딩
소켓을 만든 후 다음 단계는 소켓을 특정 주소와 포트 번호에 바인딩하는 것입니다.
이는 socket() 함수에 의해 반환된 소켓 설명자와 주소 정보를 포함하는 sockaddr 구조를 취하는
bind() 함수를 사용하여 수행됩니다.
retval = bind(listenSocket, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
if (retval == SOCKET_ERROR) {
// err
}
3. 소켓 듣기
소켓이 서버 목적으로 사용되는 경우 다음 단계는 들어오는 연결을 수신하는 것입니다.
이것은 socket descriptor와 수락을 위해 대기할 수 있는 최대 연결 수를 지정하는
backlog 매개 변수를 사용하는 listen() 함수를 사용하여 수행됩니다.
retval = listen(listenSocket, SOMAXCONN);
if (retval == SOCKET_ERROR) {
// err
}
4. 연결 수락
클라이언트가 서버에 대한 연결을 요청하면 서버는 accept() 함수를 사용하여 연결을 수락합니다.
accept() 함수는 원래 소켓이 새 연결을 계속 수신 대기하는 동안 연결을 나타내는 새 소켓 설명자를 반환합니다.
SOCKET clientSocket;
struct sockaddr_in clientAddr;
int addrLength;
char buf[BUFFERSIZE + 1];
while (true)
{
addrLength = sizeof(clientAddr);
clientSocket = accept(listenSocket, (struct sockaddr*)&clientAddr, &addrLength);
if (clientSocket == INVALID_SOCKET) {
//err
break;
}
// Client Info 출력
printf("\nClient connection successful! \nIP Address : %s \nPort Number : %d\n",
inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
// inet_ntoa : (Ipv4) 인터넷 네트워크 주소를 인터넷
// 표준 점선 소수점 형식의 ASCII 문자열로 변환
// ntohs : u_short TCP/IP 네트워크 바이트 순서에서
// 호스트 바이트 순서(Intel 프로세서의 little-endian)로 변환
5. 소켓 연결
소켓이 클라이언트용으로 사용되는 경우 다음 단계는 소켓을 서버에 연결하는 것입니다.
이것은 소켓 설명자와 서버 주소를 포함하는 sockaddr 구조를 취하는
connect() 함수를 사용하여 수행됩니다.
6. 데이터 송수신
연결이 설정되면 send() 및 recv() 함수를 사용하여 프로세스 간에 데이터를 전송할 수 있습니다.
send() 함수는 송신자 프로세스에서 수신자 프로세스로 데이터를 보내는 데 사용되는 반면,
recv() 함수는 송신자 프로세스로부터 데이터를 받는 데 사용됩니다.
// 데이터 통신
while (true)
{
// receive
retval = recv(clientSocket, buf, BUFFERSIZE, 0);
if (retval == SOCKET_ERROR) {
// err
break;
}
else if (retval == 0)
break;
// 받은 데이터 출력
buf[retval] = '\0'; // 마지막에 null 넣어주기
printf("%s", buf);
}
7. 소켓 닫기
마지막으로 통신이 완료되면 close() 함수를 사용하여 소켓을 닫아야 합니다.
이렇게 하면 소켓에서 사용하는 리소스가 해제되고 연결이 종료됩니다.
closesocket(clientSocket);
printf("\nThe connection has been terminated! \nIP Address : %s,\nPort Number : %d\n",
inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
}
closesocket(listenSocket);
return 0;
함수 실행
int main(int argc, char *argv[])
{
// 윈속 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 1;
HANDLE hThread[2];
hThread[0] = CreateThread(NULL, 0, TCPServer4, NULL, 0, NULL);
hThread[1] = CreateThread(NULL, 0, TCPServer6, NULL, 0, NULL);
WaitForMultipleObjects(2, hThread, TRUE, INFINITE);
// 윈속 종료
WSACleanup();
return 0;
}
위 코드를 F5를 눌러 실행시키고
명령 프롬프트를 열어 위와 같이 입력하면
127.0.0.1은 loopback address이며
9000은 Server Port Number
*Telnet을 사용할 수 없다는 등의 메시지가 뜬다면
제어판 -> 프로그램 > 프로그램 및 기능 > Windows 기능 켜기/끄기 메뉴 누른 후 밑으로 스크롤 하여
코드에 문제가 없다면 위 처럼 연결이 되고
메시지도 정상적으로 전송되며
연결 종료 메시지도 정상적으로 뜸!
'네트워크 > Socket Progamming' 카테고리의 다른 글
C# Chating (0) | 2024.03.07 |
---|---|
C# 비동기 통신 (0) | 2024.03.03 |
Socket Programming의 기본 개념 (0) | 2024.02.28 |
비동기 연결 예제 (0) | 2024.02.28 |
오류 처리 (0) | 2023.05.07 |