코딩/Network

[네트워크] TCP 서버-클라이언트 분석

나야, 웅이 2023. 4. 15. 17:55
728x90
반응형
SMALL

응용 프로그램 통신을 위해 결정해야 할 요소 (5가지)

프로토콜 : 통신 규약으로, 소켓을 생성할 때 결정

지역 IP 주소지역 포트 번호 : 서버 또는 클라이언트 자신의 주소

원격 IP 주소원격 포트 번호 : 서버 또는 클라이언트가 통신하는 상대의 주소

 


TCP 서버 소켓 호출 절차

1) socket() : 소켓 생성 및 사용 프로토콜 결정

2) bind() : 소켓의 지역 IP와 지역 포트 결정

3) listen() : 소켓의 상태를 LISTEN 상태로 변경

4) accept() : 클라이언트의 접속을 수용,

                    접속한 클라이언트와 통신할 수 있는 새로운 소켓 생성,

                    이 때 원격 IP와 원격 포트 번호가 결정

5) send() / recv() : 데이터 송수신

6) closesocket() : 소켓 닫기


bind()

▶소켓의 지역 IP주소와 지역 포트 번호를 소켓에 연결

성공 0, 실패 SOCKET_ERROR

[in] s

클라이언트 접속을 수용하는 소켓

 

addr

바인딩된 소켓에 할당할 서버의 주소 정보를 담고 있는 sockaddr 구조체에 대한 포인터

 

[in] namelen

소켓 주소 구조체 길이 sizeof()

//bind() 지역 IP주소와 지역 포트번호를 결정 (바인딩)
	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;	//	IPv4 결정
	serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);	//	INADDR_ANY 서버IP 여러개 쓸 수 있게 세팅
	serveraddr.sin_port = htons(SERVERPORT);	//	SERVERPORT 결정
	retval = bind(listen_sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
	
    //bind()에 오류가 발생하지 않으면 0을 반환
	if (retval == SOCKET_ERROR)
		err_quit("bind()");

 


listen()

▶소켓의 TCP 상태를 LISTEN 상태로 변경

성공 0, 실패 SOCKET_ERROR

[in] s

클라이언트 접속을 수용하는 소켓

 

[in] backlog

접속 가능한 클라이언트 개수

클라이언트 연결 정보는 연결 큐에 저장되는데, backlog는 연결 큐의 길이를 나타냄

	//listen() TCP를 Listening 상태로 변경
	retval = listen(listen_sock, SOMAXCONN);	//	SOMAXCONN 윈도우가 정한 상수
	if (retval == SOCKET_ERROR)
		err_quit("listen()");

accept()

▶클라이언트 접속을 수용하고, 접속한 클라이언트와 통신할 수 있는 새로운 소켓을 생성하여 리턴

성공 새로운 소켓, 실패 INVALID_SOCKET

[in] s

클라이언트 접속을 수용하는 소켓

 

[out] addr

접속한 클라이언트의 연결 정보

 

[in, out] addrlen

소켓 주소 구조체의 크기

//데이터 통신에 사용할 변수
	SOCKET client_sock;
	struct sockaddr_in clientaddr;
	int addrlen;
	char buf[BUFSIZE + 1];

	while (1) {
		// accept() 자신에게 접속한 클라이언트와 통신할 수 있는 새로운 소켓을 생성
		addrlen = sizeof(clientaddr);
		client_sock = accept(listen_sock, (struct sockaddr*)&clientaddr, &addrlen);
		if (client_sock == INVALID_SOCKET) 
		{
			err_display("accept()");
			break;
		}

TCP 클라이언트 소켓 호출 절차

1) socket() : 소켓 생성 및 사용 프로토콜 결정

2) connect() : 서버에 접속

3) send() / recv() : 데이터 송수신

4) closesocket() : 소켓 닫기


connect()

▶TCP 프로토콜 수준에서 서버와 논리적 연결을 설정

성공 0, 실패 SOCKET_ERROR

[in] s

클라이언트 접속을 수용하는 소켓

 

[in] name

접속한 클라이언트의 연결 정보

 

[in] namelen

소켓 주소 구조체의 크기

//connect()
	struct sockaddr_in serveraddr;
	memset(&serveraddr, 0, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	inet_pton(AF_INET, SERVERIP, &serveraddr.sin_addr);	//	클라이언트에서는 접속할 server IP를 알아야 함
	serveraddr.sin_port = htons(SERVERPORT);
	retval = connect(sock, (struct sockaddr*)&serveraddr, sizeof(serveraddr));
    
	if (retval == SOCKET_ERROR)
		err_quit("connect()");

 

 

 


 

 

TCP 데이터 전송 함수

▶기본이 되는 함수는 send(), recv() 함수

▶UDP에서 주로 사용하는 sendto(), recvform() 함수가 있음

▶윈도우 전용 함수로 WSASend*(), WSARecv*() 확장 함수가 있음

▶리눅스 전용 함수로 write(), read() 함수가 있음


 

소켓 데이터 구조체


send()

▶응용 프로그램의 데이터 전송을 위해 운영체제의 송싱 버퍼에 데이터를 복사하고 리턴

성공 보낸 바이트 수, 실패 SOCKET_ERROR

[in] s

통신할 대상과 연결된 소켓

 

[in] buf

보낼 데이터를 담고 있는 버퍼

 

[in] len

보낼 데이터의 크기

 

[in] flags

send()의 동작을 바꾸는 옵션, 거의 '0', 사용안함

//데이터 보내기
		retval = send(sock, buf, (int)strlen(buf), 0);
		if (retval == SOCKET_ERROR)
		{
			err_display("send()");
			break;
		}

 

 

 


 

 

recv()

▶운영체제의 수신 버퍼에 도착한 데이터를 응용 프로그램 버퍼에 복사하고 리턴

성공 받은 바이트 수 또는 0(연결 종료시), 실패 SOCKET_ERROR

[in] s

통신할 대상과 연결된 소켓

 

[out] buf

받은 데이터를 저장할 버퍼

 

[in] len

수신버퍼로부터 복사할 최대 데이터 크기 (byte), 응용 프로그램 버퍼 크기보다 작아야 함

 

[in] flag

recv()의 동작을 바꾸는 옵션

MSG_PEEK : 수신 버퍼의 데이터는 recv에 의하여 복사된 후 삭제 되는데, 이 옵션을 사용하면 삭제되지 않음

MSA_WAITALL : 수신 버퍼에 도착한 데이터의 크기가 len보다 작을 때, len의 크기가 될 때까지 기다림

                            수신할 데이터의 길이를 알고 있다면, 이 옵션을 선택하여 모두 수신할 때까지 대기 시킴

-> return 하는 경우

1. 사용자가 close 했을 때

2. len 만큼 데이터를 받았을 때

3. 오류났을 때

728x90
반응형
LIST