TCP echo 서버 및 클라이언트 예제 스터디

18
TCP Echo Server & Client Basic example

Transcript of TCP echo 서버 및 클라이언트 예제 스터디

Page 1: TCP echo 서버 및 클라이언트 예제 스터디

TCP Echo Server & ClientBasic example

Page 2: TCP echo 서버 및 클라이언트 예제 스터디

Source

https://www.dropbox.com/s/t1t4kqvauypf121/TCPEcho.zip

Page 3: TCP echo 서버 및 클라이언트 예제 스터디

TCP Echo Client

1. Socket()을 이용하여 TCP Socket생성

2. connect()를 이용하여 서버와의 연결을 설정

3. send(), recv()를 이용하여 통신을 수행

4. close를 이용하여 통신 종료

Page 4: TCP echo 서버 및 클라이언트 예제 스터디

SOCKET 생성

WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)(sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)

winsock의 경우 사용 전에 초기화를 해주어야 함(유닉스에서는 없는 부분)MAKEWORD(2,0)은 winsock 2.0을 쓰겠다는 뜻.

IPPROTO_TCP라는 스트림 기반(SOCK_STREAM) 프로토콜을 이용하여IPv4(PF_INET)에서 작동하도록 만들어진 소켓이라는 뜻.

socket이라고 다 같은게 아니고 어떤 프로토콜을 사용할지 미리 설정하는 듯

TCP Echo Client

1. Socket()을 이용하여 TCP Socket생성

http://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx

Page 5: TCP echo 서버 및 클라이언트 예제 스터디

SERVER 주소 구조체 생성

struct sockaddr_in echoServAddr;memset(&echoServAddr, 0, sizeof(echoServAddr));

echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = inet_addr(servIP);echoServAddr.sin_port = htons(echoServPort);

주소 패밀리를 IPv4(AF_INET)로 지정하고, ip와 port번호를 설정( 유닉스에서는 inet_addr 대신 inet_pton 사용)

inet_addr로 문자열을 binary로 변환htons로 port번호도 변환한다.

TCP Echo Client

1. Socket()을 이용하여 TCP Socket생성

Page 6: TCP echo 서버 및 클라이언트 예제 스터디

연결 설정

connect(sock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr))

만들어둔 socket과 socket구조체를 이용하여 연결을 설정

sockaddr_in 구조체가 IPv4를 위한 형식이고connect에서는 범용적으로 사용할 수 있는 구조체인 sockaddr로 형변환 하여 사용한다.

TCP Echo Client

2. connect()를 이용하여 서버와의 연결을 설정

http://msdn.microsoft.com/en-us/library/windows/desktop/ms740496(v=vs.85).aspx

Page 7: TCP echo 서버 및 클라이언트 예제 스터디

echo문자열을 서버로 전송

echoStringLen = strlen(echoString);send(sock, echoString, echoStringLen, 0)

argv로 넘겨준 echoString과 echoStringLen을 이용하여 echo 문자열을 전송한다.

send는 전송한 byte수를 return하며 echoStringLen과 비교하여제대로 전송되었는지를 확인한다.

TCP Echo Client

3. send(), recv()를 이용하여 통신을 수행

Page 8: TCP echo 서버 및 클라이언트 예제 스터디

echo 서버의 응답 수신

totalBytesRcvd = 0;printf("Received: "); while (totalBytesRcvd < echoStringLen){

if ((bytesRcvd = recv(sock, echoBuffer, RCVBUFSIZE - 1, 0)) <= 0)DieWithError("recv() failed or connection closed prematurely");

totalBytesRcvd += bytesRcvd; echoBuffer[bytesRcvd] = '\0'; printf("%s", echoBuffer);

}

서버에서 보낸 메세지가 recv()가 받을 수 있는 크기보다 클 경우가 있으므로 while문을 돌면서반복해서 데이터를 수신한다.

recv()는 수신할 데이터가 있을 때까지 멈춰있는 block함수라 함

TCP Echo Client

3. send(), recv()를 이용하여 통신을 수행

Page 9: TCP echo 서버 및 클라이언트 예제 스터디

연결 종료

closesocket(sock);WSACleanup(); /* Cleanup Winsock */

socket을 close한다. winsock의 경우 WSACleanup()으로 윈도우 소켓도 닫는다.

TCP Echo Client

4. close를 이용하여 통신 종료

Page 10: TCP echo 서버 및 클라이언트 예제 스터디

TCP Echo Server

1. Socket()을 이용하여 TCP Socket생성

2. bind()를 통해 소켓에 포트 번호를 할당

3. listen()을 통해 해당 포트가 연결을 받아들이도록 시스템에 알림

4. 다음과 같은 일을 계속적으로 반복

1. accept()를 통해 각 클라이언트와 통신에 필요한 새로운 소켓을 획득

2. 새롭게 생성된 클라이언트 소켓에 send() recv()를 호출하여 통신을 수행

3. close()를 통해 클라이언트와 연결 종료

Page 11: TCP echo 서버 및 클라이언트 예제 스터디

SOCKET 생성

WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)(sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)

winsock의 경우 사용 전에 초기화를 해주어야 함(유닉스에서는 없는 부분)MAKEWORD(2,0)은 winsock 2.0을 쓰겠다는 뜻.

IPPROTO_TCP라는 스트림 기반(SOCK_STREAM) 프로토콜을 이용하여IPv4(PF_INET)에서 작동하도록 만들어진 소켓이라는 뜻.

socket이라고 다 같은게 아니고 어떤 프로토콜을 사용할지 미리 설정하는 듯

TCP Echo Server

1. Socket()을 이용하여 TCP Socket생성 ( client와 동일함 )

http://msdn.microsoft.com/en-us/library/windows/desktop/ms740506(v=vs.85).aspx

Page 12: TCP echo 서버 및 클라이언트 예제 스터디

SERVER 주소 구조체 생성

struct sockaddr_in echoServAddr;memset(&echoServAddr, 0, sizeof(echoServAddr));

echoServAddr.sin_family = AF_INET; echoServAddr.sin_addr.s_addr = htonl(INADDR_ANY);echoServAddr.sin_port = htons(echoServPort);

IPv4를 사용htons로 port번호 변환

와일드 카드 주소(INADDR_ANY)로 설정.시스템에는 하나 이상의 IP주소가 있을 수 있는데 와일드 카드 주소로 설정하면사용할 IP주소를 알아서 찾아준다고 하는 것 같음.

찾아보니 서버로 연결된 어떤 IP로 들어오든 (포트만 맞다면) 연결해준다는 얘기

TCP Echo Server

1. Socket()을 이용하여 TCP Socket생성

http://zerobell.tistory.com/5

Page 13: TCP echo 서버 및 클라이언트 예제 스터디

SOCKET을 지정한 IP주소 및 포트에 바인딩

bind(servSock, (struct sockaddr *) &echoServAddr, sizeof(echoServAddr))

client는 connect()하기 위해 서버의 주소가 있어야 하고server는 bind()하기 위해 자신의 주소가 필요함

위에서 지정한 주소 구조체(자신의 IP주소와 port에 대한 정보가 담긴)를 이용하여socket과 bind()함

TCP Echo Server

2. bind()를 통해 소켓에 포트 번호를 할당

http://msdn.microsoft.com/en-us/library/windows/desktop/ms737550(v=vs.85).aspx

Page 14: TCP echo 서버 및 클라이언트 예제 스터디

SOCKET을 연결에 대한 대기상태로 전환

listen(servSock, MAXPENDING)

listen()을 해주어야 연결 요청을 받을 수 있음listen() 상태가 아닌 서버로의 (client의) connect()호출은 실패하게 된다.

TCP Echo Server

3. listen()을 통해 해당 포트가 연결을 받아들이도록 시스템에 알림

Page 15: TCP echo 서버 및 클라이언트 예제 스터디

accept()를 통해 각 클라이언트와 통신에 필요한 새로운 소켓을 획득

clntLen = sizeof(echoClntAddr);clntSock = accept(servSock, (struct sockaddr *) &echoClntAddr, &clntLen

printf("Handling client %s\n", inet_ntoa(echoClntAddr.sin_addr));

listen() 상태에서 client의 접속이 감지되면 server에서는 아까 만들어둔 소켓으로 직접 통신을 하는 것이 아니라, accept()를 이용하여 다른 소켓을 생성한다.

accept()는 새로운 소켓의 식별자를 반환한다. (새로 생성된 소켓은 클라이언트의 소켓과 연결된 소켓임)

inet_ntoa() 는 client에서 사용한 inet_addr로 변환한 binary IP주소를 dotted_quad형식의 문자열로 다시 변환한다.(정보를 print하기위해 사용하는 것 같음..)

TCP Echo Server

4. 다음과 같은 일을 계속적으로 반복

Page 16: TCP echo 서버 및 클라이언트 예제 스터디

새롭게 생성된 클라이언트 소켓에 send() recv()를 호출하여 통신을 수행

char echoBuffer[RCVBUFSIZE];int recvMsgSize;

recvMsgSize = recv(clntSock, echoBuffer, RCVBUFSIZE, 0)send(clntSock, echoBuffer, recvMsgSize, 0)

client로부터 메세지를 받아서 그대로 다시 돌려주는 부분

위 에코 부분에 대한 함수 HandleTCPClient()라는 함수로 따로 분리되어있는데서버 코드에서 응용 부분에 대한 자세한 내용을 분리시키는 것이 좋은 습관이라고 함.

TCP Echo Server

4. 다음과 같은 일을 계속적으로 반복

http://msdn.microsoft.com/en-us/library/windows/desktop/ms740121(v=vs.85).aspxhttp://msdn.microsoft.com/en-us/library/windows/desktop/ms740149(v=vs.85).aspx

Page 17: TCP echo 서버 및 클라이언트 예제 스터디

close()를 통해 클라이언트와 연결 종료

closesocket(sock);

socket을 close한다.

여기서는 WSACleanup()이 없음.. 루프가 안 끝나서 그런가

TCP Echo Server

4. 다음과 같은 일을 계속적으로 반복

Page 18: TCP echo 서버 및 클라이언트 예제 스터디

Client

TCP SOCKET

TCP PORT

IP

socket()

send()recv()

Server

TCP SOCKET

TCP PORT

IP

socket()

send()recv()

connect()

bind()

listen()

TCP SOCKET

accept()

Conclusion