응용 프로그램 통신을 위해 결정해야 할 요소 (5가지)
▶프로토콜 : 통신 규약으로, 소켓을 생성할 때 결정
▶지역 IP 주소와 지역 포트 번호 : 서버 또는 클라이언트 자신의 주소
▶원격 IP 주소와 원격 포트 번호 : 서버 또는 클라이언트가 통신하는 상대의 주소
TCP 서버 소켓 호출 절차
1) socket() : 소켓 생성 및 사용 프로토콜 결정
2) bind() : 소켓의 지역 IP와 지역 포트 결정
3) listen() : 소켓의 상태를 LISTEN 상태로 변경
4) accept() : 클라이언트의 접속을 수용,
접속한 클라이언트와 통신할 수 있는 새로운 소켓 생성,
이 때 원격 IP와 원격 포트 번호가 결정됨
5) send() / recv() : 데이터 송수신
6) closesocket() : 소켓 닫기
bind()
▶소켓의 지역 IP주소와 지역 포트 번호를 소켓에 연결
[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 상태로 변경
[in] s
클라이언트 접속을 수용하는 소켓
[in] backlog
접속 가능한 클라이언트 개수
클라이언트 연결 정보는 연결 큐에 저장되는데, backlog는 연결 큐의 길이를 나타냄
//listen() TCP를 Listening 상태로 변경
retval = listen(listen_sock, SOMAXCONN); // SOMAXCONN 윈도우가 정한 상수
if (retval == SOCKET_ERROR)
err_quit("listen()");
accept()
▶클라이언트 접속을 수용하고, 접속한 클라이언트와 통신할 수 있는 새로운 소켓을 생성하여 리턴
[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 프로토콜 수준에서 서버와 논리적 연결을 설정
[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()
▶응용 프로그램의 데이터 전송을 위해 운영체제의 송싱 버퍼에 데이터를 복사하고 리턴
[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()
▶운영체제의 수신 버퍼에 도착한 데이터를 응용 프로그램 버퍼에 복사하고 리턴
[in] s
통신할 대상과 연결된 소켓
[out] buf
받은 데이터를 저장할 버퍼
[in] len
수신버퍼로부터 복사할 최대 데이터 크기 (byte), 응용 프로그램 버퍼 크기보다 작아야 함
[in] flag
recv()의 동작을 바꾸는 옵션
MSG_PEEK : 수신 버퍼의 데이터는 recv에 의하여 복사된 후 삭제 되는데, 이 옵션을 사용하면 삭제되지 않음
MSA_WAITALL : 수신 버퍼에 도착한 데이터의 크기가 len보다 작을 때, len의 크기가 될 때까지 기다림
수신할 데이터의 길이를 알고 있다면, 이 옵션을 선택하여 모두 수신할 때까지 대기 시킴
-> return 하는 경우
1. 사용자가 close 했을 때
2. len 만큼 데이터를 받았을 때
3. 오류났을 때
'코딩 > Network' 카테고리의 다른 글
[네트워크] 멀티스레드 (0) | 2023.04.15 |
---|---|
[네트워크] 데이터 전송, 고정 길이, 가변 길이 (0) | 2023.04.15 |
[네트워크] TCP 서버-클라이언트 (0) | 2023.04.15 |
[네트워크] DNS와 도메인, IP 주소 변환 함수 (0) | 2023.04.15 |
[네트워크] IP 주소 변환 함수 (0) | 2023.04.14 |