cd ~/workspace/KRAFTON-JUNGLE-W8-Web-Server/webproxy-lab
mkdir echo
cd echo
webproxy-lab/echo/ํด๋ ์์์ ์์ฝ ์๋ฒ ์ฝ๋๋ฅผ ์์ฑ
ํด๋๋ช
์ด๋ ๊ฒฝ๋ก๋ ๊ฐ์ธ๋ง๋ค ๋ค๋ฅผ ์ ์์.
์ค์ํ๊ฑด echo๋ผ๋ ํด๋๋ฅผ ๋ฐ๋ก ๋ง๋๋๊ฒ ๊น๋ํ๋ค๋ ๊ฒ๊ณผ
csapp.c๋ csapp.h๋ฅผ ๋ณต์ฌํด์์ผ ํ๋ค๋ ๊ฒ
touch echoserveri.c echoclient.c echo.c
ํ์ํ 3๊ฐ C ํ์ผ์ ๋ง๋ ๋ค:
echoserveri.c: ์๋ฒechoclient.c: ํด๋ผ์ด์ธํธecho.c: ๋ฉ์์ง ๋๋๋ ค์ฃผ๋ ํจ์
cp ../csapp.c ../csapp.h .
rio_t,Rio_readlineb()๋ฑ์ robust I/O ๊ธฐ๋ฅ์ ์ฌ์ฉํ๊ธฐ ์ํด ํ์
#include "csapp.h" // robust I/O ํจ์์ ๊ด๋ จ ๊ตฌ์กฐ์ฒด๋ฅผ ํฌํจํ ํค๋ ํ์ผ ํฌํจ
// ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ๋ ์์ผ ํ์ผ ๋์คํฌ๋ฆฝํฐ(connfd)๋ฅผ ์ธ์๋ก ๋ฐ์
void echo(int connfd) {
size_t n; // ์ฝ์ ๋ฐ์ดํธ ์๋ฅผ ์ ์ฅํ ๋ณ์
char buf[MAXLINE]; // ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ฌ ๋ฒํผ (ํ ์ค ์ต๋ MAXLINE ํฌ๊ธฐ)
rio_t rio; // robust I/O์ฉ ๋ฒํผ ๊ตฌ์กฐ์ฒด
// connfd(ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ๋ ์์ผ)๋ฅผ ๊ธฐ๋ฐ์ผ๋ก rio ๊ตฌ์กฐ์ฒด ์ด๊ธฐํ
Rio_readinitb(&rio, connfd);
// ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ํ ์ค์ฉ ๋ฐ์ดํฐ๋ฅผ ๊ณ์ ์ฝ์ด๋ค์ด๋ ๋ฐ๋ณต๋ฌธ
while ((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0) {
// ์ฝ์ ๋ฐ์ดํธ ์๋ฅผ ์๋ฒ ๋ก๊ทธ๋ก ์ถ๋ ฅ
printf("server received %zu bytes\n", n);
// ์ฝ์ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ๋ค์ ํด๋ผ์ด์ธํธ์๊ฒ ๋๋ ค๋ณด๋ (Echo!)
Rio_writen(connfd, buf, n);
}
}
๐ echoserver ๋ค์ ๋ถ๋ i๋ ๋ฌด์จ ๋ป?
i๋ iterative์ ์ฝ์๋ก,
ํ ๋ฒ์ ํ๋์ ํด๋ผ์ด์ธํธ๋ง ์ฒ๋ฆฌํ๋ ๋ฐ๋ณตํ ์๋ฒ(iterative server)์์ ์๋ฏธ
#include "csapp.h" // robust I/O ํจ์์ ๋คํธ์ํฌ ํจ์ ๋ํผ๊ฐ ํฌํจ๋ ํค๋ ํ์ผ
int main(int argc, char **argv) {
int listenfd, connfd; // ์๋ฒ ๋ฆฌ์จ์ฉ ์์ผ๊ณผ ํด๋ผ์ด์ธํธ ์ฐ๊ฒฐ์ฉ ์์ผ
socklen_t clientlen; // ํด๋ผ์ด์ธํธ ์ฃผ์ ๊ตฌ์กฐ์ฒด์ ํฌ๊ธฐ
struct sockaddr_storage clientaddr; // ํด๋ผ์ด์ธํธ ์ฃผ์ ์ ๋ณด๋ฅผ ์ ์ฅํ ๊ตฌ์กฐ์ฒด
char client_hostname[MAXLINE]; // ํด๋ผ์ด์ธํธ์ ํธ์คํธ ์ด๋ฆ ๋ฌธ์์ด
char client_port[MAXLINE]; // ํด๋ผ์ด์ธํธ์ ํฌํธ ๋ฒํธ ๋ฌธ์์ด
// ๋ช
๋ น์ค ์ธ์๊ฐ 2๊ฐ๊ฐ ์๋๋ฉด ์ฌ์ฉ๋ฒ ์ถ๋ ฅ ํ ์ข
๋ฃ
if (argc != 2) {
fprintf(stderr, "usage: %s <port>\n", argv[0]); // ์คํ ๋ฐฉ๋ฒ ์๋ด
exit(0);
}
// ํฌํธ ๋ฒํธ๋ฅผ ์ธ์๋ก ๋ฐ์ ์๋ฒ ๋ฆฌ์จ ์์ผ ์ด๊ธฐ
listenfd = Open_listenfd(argv[1]);
while (1) { // ๋ฐ๋ณตํ ์๋ฒ: ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๊ฒฐ ์ฌ ๋๋ง๋ค ๋ฐ๋ณต
clientlen = sizeof(struct sockaddr_storage); // ์ฃผ์ ๊ตฌ์กฐ์ฒด ํฌ๊ธฐ ์ด๊ธฐํ
// ํด๋ผ์ด์ธํธ์ ์ฐ๊ฒฐ ์์ฒญ ์๋ฝ โ ์๋ก์ด ์์ผ connfd ์์ฑ
connfd = Accept(listenfd, (SA *)&clientaddr, &clientlen);
// ํด๋ผ์ด์ธํธ ์ฃผ์๋ฅผ ์ฌ๋์ด ์ฝ์ ์ ์๋ ํธ์คํธ/ํฌํธ ๋ฌธ์์ด๋ก ๋ณํ
Getnameinfo((SA *)&clientaddr, clientlen,
client_hostname, MAXLINE,
client_port, MAXLINE, 0);
// ์ ์ํ ํด๋ผ์ด์ธํธ์ ์ ๋ณด ์ถ๋ ฅ
printf("connected to (%s, %s)\n", client_hostname, client_port);
// ์ฐ๊ฒฐ๋ ์์ผ์ echo ์ฒ๋ฆฌ ํจ์๋ก ๋๊ฒจ ์๋ต ์ฒ๋ฆฌ
echo(connfd);
// ํด๋ผ์ด์ธํธ์์ ์ฐ๊ฒฐ ์ข
๋ฃ
Close(connfd);
}
}
#include "csapp.h" // robust I/O ํจ์๋ค๊ณผ ๋คํธ์ํฌ ๋ํผ ํจ์๋ค์ด ์ ์๋ ํค๋
int main(int argc, char **argv) {
int clientfd; // ์๋ฒ์ ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ ์์ผ ํ์ผ ๋์คํฌ๋ฆฝํฐ
char *host, *port; // ๋ช
๋ น์ค ์ธ์๋ก ๋ฐ์ ํธ์คํธ ์ด๋ฆ๊ณผ ํฌํธ ๋ฒํธ
char buf[MAXLINE]; // ๋ฉ์์ง๋ฅผ ์ ์ฅํ ๋ฒํผ
rio_t rio; // robust I/O์ฉ ์
๋ ฅ ๋ฒํผ ๊ตฌ์กฐ์ฒด
// ์ธ์ ๊ฐ์ ์ฒดํฌ: ์คํ ํ์ผ๋ช
+ host + port โ ์ด 3๊ฐ์ฌ์ผ ํจ
if (argc != 3) {
fprintf(stderr, "usage: %s <host> <port>\n", argv[0]); // ์ฌ์ฉ๋ฒ ์๋ด
exit(0);
}
// ๋ช
๋ น์ค ์ธ์์์ ํธ์คํธ์ ํฌํธ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ด
host = argv[1];
port = argv[2];
// ์๋ฒ์ ์ฐ๊ฒฐํ๋ ์์ผ์ ์์ฑํ๊ณ , ์ฐ๊ฒฐ ์๋
clientfd = Open_clientfd(host, port);
// robust I/O๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด rio ๊ตฌ์กฐ์ฒด๋ฅผ ์ด๊ธฐํ
Rio_readinitb(&rio, clientfd);
// ์ฌ์ฉ์๋ก๋ถํฐ ํ ์ค์ฉ ์
๋ ฅ์ ๋ฐ๊ณ ์๋ฒ์ ํต์ ํ๋ ๋ฐ๋ณต ๋ฃจํ
while (Fgets(buf, MAXLINE, stdin) != NULL) {
// ์
๋ ฅํ ๋ด์ฉ์ ์๋ฒ๋ก ์ ์ก
Rio_writen(clientfd, buf, strlen(buf));
// ์๋ฒ๋ก๋ถํฐ ์๋ต์ ์ค ๋จ์๋ก ์์
Rio_readlineb(&rio, buf, MAXLINE);
// ๋ฐ์ ์๋ต์ ํ๋ฉด์ ์ถ๋ ฅ
Fputs(buf, stdout);
}
// ์๋ฒ์์ ์ฐ๊ฒฐ ์ข
๋ฃ
Close(clientfd);
return 0;
}
echo์๋ฒ๋ฅผ ์ํ Makefile์ ์๋ ๊ฒฝ๋ก์ ์์ฑํด์ผํจ:
~/workspace/KRAFTON-JUNGLE-W8-Web-Server/webproxy-lab/echo/
KRAFTON-JUNGLE-W8-Web-Server/
โโโ webproxy-lab/
โโโ echo/
โโโ echo.c
โโโ echoserveri.c
โโโ echoclient.c
โโโ csapp.c
โโโ csapp.h
โโโ Makefile โ
โ ์ฌ๊ธฐ์ Makefile๋ง๋์ธ
cd ~/workspace/KRAFTON-JUNGLE-W8-Web-Server/webproxy-lab/echo
touch Makefile
nano Makefile # ๋๋ vim, code, etc.
๊ทธ๋ฆฌ๊ณ ๊ทธ ์์ ๋ค์ ๋ด์ฉ์ ๋ถ์ฌ ๋ฃ์ผ๋ฉด ๋จ:
CC = gcc # ์ฌ์ฉํ ์ปดํ์ผ๋ฌ๋ gcc
CFLAGS = -Wall -O2 # ์ปดํ์ผ ์ ๋ชจ๋ ๊ฒฝ๊ณ ์ถ๋ ฅ(-Wall) + ์ต์ ํ(-O2) ์ต์
์ฌ์ฉ
OBJS = csapp.o echo.o # ๊ณตํต์ผ๋ก ์ฌ์ฉํ ๊ฐ์ฒด ํ์ผ ๋ชฉ๋ก (์๋ฒ์ ํด๋ผ์ด์ธํธ ๋ชจ๋ ์ฌ์ฉํจ)
all: echoserveri echoclient # make๋ง ์
๋ ฅํ์ ๋ ๊ธฐ๋ณธ์ผ๋ก ๋น๋ํ ๋์
echoserveri: echoserveri.o $(OBJS) # echoserveri๋ฅผ ๋ง๋ค๊ธฐ ์ํด ํ์ํ ํ์ผ๋ค
$(CC) $(CFLAGS) -o $@ $^ -pthread # gcc -Wall -O2 -o echoserveri echoserveri.o csapp.o echo.o -pthread
echoclient: echoclient.o $(OBJS) # echoclient๋ฅผ ๋ง๋ค๊ธฐ ์ํด ํ์ํ ํ์ผ๋ค
$(CC) $(CFLAGS) -o $@ $^ -pthread # gcc -Wall -O2 -o echoclient echoclient.o csapp.o echo.o -pthread
clean: # make clean ์
๋ ฅ ์ ์คํ๋จ (๋น๋๋ ํ์ผ๋ค์ ์ญ์ )
rm -f *.o echoserveri echoclient # ๊ฐ์ฒด ํ์ผ๊ณผ ์คํํ์ผ๋ค์ ๋ชจ๋ ์ญ์
| ํญ๋ชฉ | ๋ด์ฉ |
|---|---|
| Makefile ์์น | webproxy-lab/echo/ ํด๋ ์ |
| ์ฉ๋ | echo ์๋ฒ/ํด๋ผ์ด์ธํธ ์๋ ์ปดํ์ผ |
| ์ฃผ์ | ๋ฐ๋์ ์์คํ์ผ๋ค๊ณผ ๊ฐ์ ๋๋ ํ ๋ฆฌ์ ์์ด์ผ ํจ |
-pthread๋ csapp์์ ์ฌ์ฉํ๋ ์ฐ๋ ๋ ๊ด๋ จ ํจ์ ๋๋ฌธ์ ๋ฐ๋์ ํ์
make
์คํ ํ์ผ ๋ ๊ฐ๊ฐ ์๊น:
echoserveri (์๋ฒ)echoclient (ํด๋ผ์ด์ธํธ)๐ฅ๏ธ ํฐ๋ฏธ๋ 1 (์๋ฒ ์คํ)
./echoserveri 8000
๐ป ํฐ๋ฏธ๋ 2 (ํด๋ผ์ด์ธํธ ์คํ)
./echoclient localhost 8000
์ ๋ ฅํ ๋ฌธ์ฅ์ด ๊ทธ๋๋ก ๋์์ค๋ฉด ์ฑ๊ณต
์:
hello
hello
๊ฐ๋๋ค๋ผ
๊ฐ๋๋ค๋ผ
connected to (localhost, 33454)
server received 6 bytes
server received 13 bytes
์์ฝ ์๋ฒ๋ฅผ ์คํํด๋๊ณ , ํด๋ผ์ด์ธํธ๋ฅผ ์๋์ฒ๋ผ ์คํํ์ ๋:
./echoclient localhost 8000
์๋ฒ ์ชฝ์ ์ด๋ ๊ฒ ์ถ๋ ฅ๋๋ค.
connected to (localhost, 43298)
๐คจ 8000 ํฌํธ๋ก ์ฐ๊ฒฐํ๋๋ฐโฆ 43298์ ๋ญ์ง? ์ ์ด์ํ ๋ฒํธ๊ฐ ์ฐํ๋ ๊ฑธ๊น?
ํด๋ผ์ด์ธํธ๊ฐ ์๋ฒ์ ์ฐ๊ฒฐํ ๋,
์๋ฒ์ ํฌํธ ๋ฒํธ๋ ๋ด๊ฐ ์ง์ ์ง์ ํ์ง๋ง,
ํด๋ผ์ด์ธํธ๊ฐ ์ฐ๋ ํฌํธ๋ ์ด์์ฒด์ ๊ฐ ์๋์ผ๋ก ์ ํด์ค.
์ด๊ฑธ ephemeral port (์์ ํฌํธ)๋ผ๊ณ ํจ.
ํด๋ผ์ด์ธํธ: 127.0.0.1:43298 โ ์๋ฒ: 127.0.0.1:8000
listen(8000))connect())์ด์์ฒด์ ๊ฐ ํ์ฌ ์ฌ์ฉ ์ค์ด์ง ์์ ํฌํธ ๋ฒํธ๋ฅผ ์๋์ผ๋ก ํ๋ ํ ๋นํด์ค๋ค.
์ด ๋ฒ์๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค์๊ณผ ๊ฐ๋ค:
| OS | ephemeral port ๋ฒ์ |
|---|---|
| Linux | 32768 ~ 60999 |
| macOS | 49152 ~ 65535 |
cat /proc/sys/net/ipv4/ip_local_port_range
์์ ์ถ๋ ฅ:
32768 60999
โ ์ด ๋ฒ์ ์์์ ํด๋ผ์ด์ธํธ ํฌํธ๊ฐ ์๋ ์ ํ๋๋ค.
| ๊ฐ๋ | ์ค๋ช |
|---|---|
| ์๋ฒ ํฌํธ | ๊ฐ๋ฐ์๊ฐ ์ง์ ํจ (์: 8000) |
| ํด๋ผ์ด์ธํธ ํฌํธ | OS๊ฐ ์๋์ผ๋ก ํ ๋นํจ (์: 43298) |
| ์ ํ์ํ๊ฐ? | ์ฌ๋ฌ ํด๋ผ์ด์ธํธ๊ฐ ๋์์ ์ ์ํ ์ ์๋๋ก ์ถ๋ฐ์ง๋ฅผ ๋ค๋ฅด๊ฒ ์ ์งํด์ผ ํจ |
| ์ด๊ฑธ ๋ญ๋ผ๊ณ ๋ถ๋ฅด๋? | ephemeral port (์์ ํฌํธ) |
./echoclient localhost 8000โ
"์๋ฒ์ 8000๋ฒ ํฌํธ๋ก ์ฐ๊ฒฐํ๊ฒ ๋ค"๋ ๋ป์ด์ง,
"๋ด ํด๋ผ์ด์ธํธ ํฌํธ๋ 8000์ ์ฐ๊ฒ ๋ค"๋ ๋ป์ ์๋๋ค!
์ด์์ฒด์ ๊ฐ ์๋์ผ๋ก ์ ๊ฒน์น๋ ์์ ํฌํธ ํ๋๋ฅผ ๊ณจ๋ผ์ ์ฐ๊ฒฐํด์ค๋ค.
๊ทธ๊ฒ ๋ฐ๋ก 43298, 39924, 55446 ๊ฐ์ ์ซ์๋ค.
์์ฝ ์๋ฒ ๋ก๊ทธ์ ์ด๋ฐ ๋ฉ์์ง๊ฐ ๋ฌ๋ค.
server received 6 bytes
ํ์ง๋ง ๋๋ hello๋ผ๋ ์ํ๋ฒณ 5๊ธ์๋ง ์
๋ ฅํ๋๋ฐโฆ
โ ์ 6๋ฐ์ดํธ๊ฐ ๋๋ ๊ฑธ๊น?
\n ๋๋ฌธํฐ๋ฏธ๋์์ ๋ฌธ์์ด์ ์
๋ ฅํ ๋ค Enter๋ฅผ ๋๋ฅด๋ฉด,
์ปดํจํฐ๋ ๋ฌธ์์ด ๋์ ์ค๋ฐ๊ฟ ๋ฌธ์(Newline), ์ฆ \n์ ์๋์ผ๋ก ๋ถ์ธ๋ค.
๊ทธ๋์ ์ค์ ๋ก ์๋ฒ์ ์ ๋ฌ๋ ๋ฌธ์์ด์ ์ด๋ ๊ฒ ์๊ฒผ๋ค:
"hello\n"
| ๋ฌธ์ | ๋ฐ์ดํธ ์ (UTF-8 ๊ธฐ์ค) |
|---|---|
h | 1 |
e | 1 |
l | 1 |
l | 1 |
o | 1 |
\n (์ค๋ฐ๊ฟ) | 1 |
| ํฉ๊ณ | 6๋ฐ์ดํธ โ |
echo -n "hello" | wc -c # ์ถ๋ ฅ: 5
echo -n "hello\n" | wc -c # ์ถ๋ ฅ: 6
๐ -n ์ต์
์ echo ๋ช
๋ น์ด ์๋์ผ๋ก ์ค๋ฐ๊ฟ์ ๋ฃ์ง ์๋๋ก ๋ฐฉ์งํ๋ ์ต์
.
\n๋ ํจ๊ป ์๋ฒ๋ก ๋ณด๋ด๊ณ ์์๋ ๊ฒ!์ฆ,
5๊ธ์ + \n = 6๋ฐ์ดํธ๊ฐ ์๋ฒ์ ์ ์ก๋ ๊ฒ์ด๋ค.
| ๋จ๊ณ | ํ ์ผ |
|---|---|
| ๐ ๋๋ ํ ๋ฆฌ | echo/ ํด๋ ์์ฑ |
| ๐ ํ์ผ ์์ฑ | echoserveri.c, echoclient.c, echo.c |
| ๐ฆ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | csapp.c, csapp.h ๋ณต์ฌ |
| ๐ Makefile | ์ปดํ์ผ ์๋ํ |
| ๐จ make | ์ปดํ์ผ ์ฑ๊ณต |
| ๐ ์คํ | ์๋ฒ/ํด๋ผ์ด์ธํธ ํ ์คํธ ์๋ฃ |
socket() โ connect() โ read()/write() ํ๋ฆ์ผ๋ก ๊ตฌ์ฑ๋๋คlisten()ํ๊ณ , ํด๋ผ์ด์ธํธ๋ connect()ํ๋คrio_t๋ฅผ ์ฐ๋ฉด ๋คํธ์ํฌ ์ฝ๊ธฐ๊ฐ ๋ robust ํด์ง๋คMakefile๊ณผ -pthread ์ค์ ์ ์ค์์ฑ
ubuntu