구현하기
Web Proxy #2 : 기본적인 Echo 서버 만들기
pwerty
2025. 5. 3. 22:00
2025.05.03 - [구현하기] - Tiny Web Server 개발 기록 #1
Tiny Web Server 개발 기록 #1
2025.05.02 - [분류 전체보기] - [CS:APP] 11 : 웹 서버 [CS:APP] 11 : 웹 서버모든 네트워크 애플리케이션은 클라이언트-서버 모델을 기반으로 한다.여기서 이야기하는 모델에 따르면, 애플리케이션은 한
hyeonistic.tistory.com
지난 글에서는 알아보았다. 자연어 식 코드를.. 그럼 이제 실제로 해보겠다.
헤더.zip
0.01MB
이걸 받는다. 그러고 같은 경로에 소스를 작성한다.
echo : client
#include "csapp.h"
int Open_clientfd(char *hostname, char *port);
int main(int argc, char **argv)
{
int clientfd;
char *host, *port, buf[MAXLINE];
rio_t rio;
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);
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);
exit(0);
}
int Open_clientfd(char *hostname, char *port)
{
int clientfd;
struct addrinfo hints, *listp, *p;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_NUMERICSERV;
hints.ai_flags |= AI_ADDRCONFIG;
Getaddrinfo(hostname, port, &hints, &listp);
for( p = listp; p; p = p->ai_next)
{
if((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1)
break;
Close(clientfd);
}
Freeaddrinfo(listp);
if (!p)
return -1;
else
return clientfd;
}
echo : server
#include "csapp.h"
void echo(int connfd);
int Open_listenfd(char *port);
void echo(int connfd)
{
size_t n;
char buf[MAXLINE];
rio_t rio;
Rio_readinitb(&rio, connfd);
while((n = Rio_readlineb(&rio, buf, MAXLINE)) != 0)
{
printf("server received %d byted\n", (int)n);
Rio_writen(connfd, buf, n);
}
}
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t clientlen;
struct sockaddr_storage clientaddr;
char client_hostname[MAXLINE], client_port[MAXLINE];
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 = Accept(listenfd, (SA *)&clientaddr, &clientlen);
Getnameinfo((SA *) &clientaddr, clientlen, client_hostname, MAXLINE, client_port, MAXLINE, 0);
echo(connfd);
Close(connfd);
}
}
int Open_listenfd(char *port)
{
struct addrinfo hints, *listp, *p;
int listenfd, optval = 1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
hints.ai_flags |= AI_NUMERICSERV;
Getaddrinfo(NULL, port, &hints, &listp);
for (p = listp; p; p->ai_next)
{
if ((listenfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue;
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (const void *)&optval, sizeof(int));
if(bind(listenfd, p->ai_addr, p->ai_addrlen) == 0)
break;
Close(listenfd);
}
Freeaddrinfo(listp);
if (!p)
return -1;
if (listen(listenfd, LISTENQ) < 0)
{
Close(listenfd);
return -1;
}
return listenfd;
}
Makefile
# Makefile for echoclient and echoserveri
CC = gcc
CFLAGS = -Wall -Wextra -g
LDFLAGS = -lpthread
# 디렉토리 및 파일
SRCDIR = .
TARGETS = echoclient echoserveri
all: $(TARGETS)
echoclient: $(SRCDIR)/echoclient.c $(SRCDIR)/csapp.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
echoserveri: $(SRCDIR)/echoserveri.c $(SRCDIR)/csapp.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
clean:
rm -f $(TARGETS)
Makefile을 작성해서 이 내용으로 기입한다.
그리고 make하고,
./[서버] <사용 할 포트 번호> | ./[클라] localhost <왼쪽에 적었던 포트번호>
이 두 명령어를 각기 다른 Terminal에서 실행한다. 그럼 끝!
다음엔 진짜 Tiny Server에 대해 논해보겠다.