KraftonJungle2기/Today I Learned
[TIL] CSAPP 11장 공부2 - 예제 echo 서버
SooooooooS
2023. 5. 20. 22:37
728x90
1. 상위 수준의 도움 함수
1. open_clientfd()
클라이언트는 이 함수를 호출하여 서버와 연결을 설정한다.
2. open_listenfd()
서버는 이 함수를 호출해서 연결 요청을 받을 준비가 된 듣기 식별자 생성
▶ setsockopt() : 소켓 세부 사항 설정
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);
- sock : 소켓 파일 디스크립터
- level : 프로토콜 레벨 전달
- SOL_SOCKET : 일반
- IPPROTO_IP : IP - IPv4
- IPPROTO_TCP : TCP
- optname : 변경할 옵션의 이름
- SO_REUSEADDR : 이미 사용중인 주소나 포트에 대해서도 바인드 허용
- optval : 확인 결과의 저장을 위한 버퍼 주소 값 전달
- optlen : optval 로 전달된 주소 값의 버퍼 크기
- https://jhnyang.tistory.com/entry/네트워크소켓-프로그래밍-setsockopt
▶ open_listenfd()
2. echo 서버 만들기
1. 에코 서버란?
클라이언트가 전송해주는 데이터를 그대로 되돌려 전송해 주는 기능을 가진 서버
몇 바이트 송수신할 것인지 예상할 수 있다 → 전송한만큼 바이트를 되돌려 받는다.
< 참고 > https://developer-jun.tistory.com/17
2. client
클라이언트 역할을 할 서버 파일
인자로 호스트 주소와 포트 번호가 주어져야 한다.
#include "../csapp.h"
int main(int argc, char **argv) {
int clientfd; //client file descriptor
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); //rio 구조체 초기화 -> 읽기 작업을 위한 버퍼 및 상태정보 저장
while (Fgets(buf, MAXLINE, stdin) != NULL) { //EOF를 만나면 종료
Rio_writen(clientfd, buf, strlen(buf)); //입력받은 문자열 서버로 전송
Rio_readlineb(&rio, buf, MAXLINE); //rio 구조체를 통해 서버로부터 응답을 읽어들이다.
Fputs(buf, stdout); //출력
}
Close(clientfd);
exit(0);
}
3. server
서버 역할을 할 서버 파일
인자로 포트 번호가 주어져야 한다.
#include "../csapp.h"
void echo(int connfd);
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);
printf("Connected to (%s, %s)\n", client_hostname, client_port);
echo(connfd);
Close(connfd);
}
exit(0);
}
4. echo
클라이언트에서 서버로 들어온 값을 그대로 클라이언트에 보내준다.
#include "../csapp.h"
//connfd : 클라이언트와의 연결을 나타내는 연결 소켓
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 bytes\n", (int)n);
Rio_writen(connfd, buf, n);
}
}
※ 현재 폴더 구조 ※
5. server Makefile
서버를 실행하기 위한 Makefile
주의할점❗️ csapp 파일들은 같은 폴더에 존재하지 않으므로 상대 경로로 표시해주어야 한다.
CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -lpthread
all: client
echoclient.o: echoclient.c ../csapp.h
$(CC) $(CFLAGS) -c echoclient.c
client: echoclient.o ../csapp.o
$(CC) $(CFLAGS) echoclient.o ../csapp.o -o client $(LDFLAGS)
clean:
rm -f *~ *.o client
6.client Makefile
클라이언트를 실행할 Makefile
위와 마찬가지로 상대경로 주의❗️
CC = gcc
CFLAGS = -g -Wall
LDFLAGS = -lpthread
all: server
echoserver.o: echoserver.c ../csapp.h
$(CC) $(CFLAGS) -c echoserver.c
echo.o: echo.c ../csapp.h
$(CC) $(CFLAGS) -c echo.c
server: echoserver.o echo.o ../csapp.o
$(CC) $(CFLAGS) echoserver.o echo.o ../csapp.o -o server $(LDFLAGS)
clean:
rm -f *~ *.o server
3. 서버 실행하기
▶ 사용할 포트 번호 찾기
./port-for-user.pl
- bash: ./port-for-user.pl: Permission denied 와 같은 오류 발생
- 실행 권한이 없기 때문에 발생한 문제이다.
- ls -l port-for-user.pl : port-for-user.pl 파일 권한 확인하기
- -r-------- : 읽기 권한밖에 없는 상태였다.
- chmod +x port-for-user.pl : 실행권한 추가해주기
- -r-x--x--x : 실행권한을 추가해주었다.
- 위와 같이 실행 권한을 추가하고 다시 파일을 실행하면 안쓰는 포트 번호를 얻어낼 수 있었다.
▶ 서버 실행하기
- server Makefile 실행하여 실행파일 생성하기 = server 생성
- ./server 포트번호 : 서버 실행하기
▶ 클라이언트 실행하기
- client Makefile 실행하여 실행파일 생성하기 = client 생성
- ./client 서버주소 포트번호 : 클라이언트 실행하기
- 서버주소
- 현재 같은 로컬에서 실행 중이라서 로컬 호스트 주소를 사용했다.
- 우분투 서버의 public IP 주소를 사용해도 된다.
※ ec2 포트 열어주기 ※
4. 동작 과정 그려보기
C로 서버를 직접 실행하고 그 서버에 접속하는 작업을 하는 것이 처음이라서 감이 안잡혔었다.
특히 어떻게 실행을 해야할지 감이 안잡혔다.
같이 공부하는 분의 도움으로 파일 구조 및 실행의 과정에 대해 설명을 듣고 실행해보았다.
정말 이번에는 동료분의 설명이 매우 도움이 되었다. 같이 공부하는 사람이 있으니 정말 좋다!
728x90