네트워크/Socket Progamming

Socket Programming

우대비 2023. 5. 7. 20:46
반응형

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 기능 켜기/끄기 메뉴 누른 후 밑으로 스크롤 하여 

텔넷 클라이언트 체크

 

 

코드에 문제가 없다면 위 처럼 연결이 되고

 

메시지도 정상적으로 전송되며

 

연결 종료 메시지도 정상적으로 뜸!

반응형
LIST

'네트워크 > 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