//sol3_server.c
#include <stdio.h> //표준 입출력 라이브러리
#include <string.h> // 문자열 관련 함수 사용 위한 라이브러리
#include <unistd.h> // memset등 사용
#include <stdlib.h> // exit 등 사용
#include <sys/socket.h> // 소켓 관련 라이브러리
#include <arpa/inet.h> // 아파넷 관련 라이브러리
char stack[100] = { 0, }; // 문자 저장배열
double result[100] = { 0, }; // 결과 연산 및 결과값 계산 배열
int p_top = -1; // postfix 배열 순서 번호
int s_top = -1; // stack 배열 순서 번호
int r_top = -1; // result 배열 순서 번호
double temp = 0; // 결과값 저장 변수
char Priority(char c) { // 우선순위 지정 함수
switch (c) {
case '(':
return 0;
case '+':
case '-':
return 1;
case '*':
case '/':
return 2;
}
}
char push(char infix[]) { // push함수 : 스택에 infix 문자열 집어넣는다.
stack[++s_top] = infix;
return stack;
}
char infixToPostfix(char infix[], char postfix[], char stack[]) { // infix를 postfix로 바꾸는 함수
for (int i = 0; i < strlen(infix); i++) {
if (infix[i] >= 48 && infix[i] <= 57) // infix[i]가 숫자일경우
postfix[++p_top] = infix[i];
else if (infix[i] == '(') // '('가 들어올경우
stack[++s_top] = infix[i];
else if (infix[i] == ')') { // ')'가 들어올경우
for (; ; ) {
if (stack[s_top] == '(') { //'('만나면 널값으로 바꾸고 for문 탈출
stack[s_top--] = NULL;
break;
}
postfix[++p_top] = stack[s_top]; //'('만나기 전까지의 스택의 연산자를 식에 집어넣는다.
stack[s_top--] = NULL; //사용한 스택값 널로 변경.
}
}
else if (Priority(stack[s_top]) < Priority(infix[i])) // 앞에있는 연산자보다 뒤에오는 연산자의 우선순위가 높을때
stack[++s_top] = infix[i]; // 연산자를 그대로 스택에 넣는다
else {
while(Priority(stack[s_top]) >= Priority(infix[i])) { // 앞에있는 연산자보다 뒤에오는 연산자의 우선순위가 낮거나 같을 때,
postfix[++p_top] = stack[s_top]; // 높은 우선순위를 가진 연산자가 스택에서 다 나올 때 까지 꺼낸다.
stack[s_top--] = 0;
}
push(infix[i]); // 스택에 연산자 넣기
}
}
while (s_top != -1) // 마지막 남은 stack의 연산자를 pop해주는 반복문
postfix[++p_top] = stack[s_top--];
}
double calculate(char postfix[]) { // 값을 계산하는 함수
for (int i = 0; postfix[i] != NULL; i++) { // postfix의 값을 하나씩 불러오면서 계산을 한다.
if (postfix[i] >= 48 && postfix[i] <= 57) { // postfix[i]가 숫자일경우(아스키코드 값 48~57)
postfix[i] = (int)postfix[i] - 48; //정수값으로 변환
result[++r_top] = (double)postfix[i]; // 숫자를 result배열에 저장
}
else { // postfix[i]가 연산자일 경우
if (postfix[i] == '+')
temp = result[r_top - 1] + result[r_top];
else if (postfix[i] == '-')
temp = result[r_top - 1] - result[r_top];
else if (postfix[i] == '*')
temp = result[r_top - 1] * result[r_top];
else if (postfix[i] == '/')
temp = result[r_top - 1] / result[r_top];
result[r_top--] = 0;
result[r_top] = temp; //결과값을 result배열에 저장
}
}
return result[0]; // 결과값 반환
}
// 에러 발생 시 내용 출력하는 에러 핸들러
void error_handling(char * message){
fputs(message,stderr);
fputc('\n',stderr);
exit(1);
}
void main(){
int ss, sa;
char infix[100] = { 0, };
char postfix[100] = { 0, };
double result1 = 0;
struct sockaddr_in ssa;
// ssa 구조체 초기화 후 통신타입, ip주소, 포트번호 지정
memset(&ssa, 0, sizeof(ssa));
ssa.sin_family = AF_INET;
ssa.sin_addr.s_addr = htonl(INADDR_ANY); // 어떤 주소이든 상관없다.
ssa.sin_port = htons(11234); // 포트번호 11234
// tcp 통신 소켓 생성
ss = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if(ss == -1) // 소켓 생성 실패할 경우 에러 메세지 출력
error_handling("socket error");
//소켓과 서버 주소를 연결한다. 실패할 경우 에러 메세지 출력
if(bind(ss,(struct sockaddr *) &ssa, sizeof(ssa))==-1){
error_handling("bind error");
}
// 서버는 무한루프를 돌면서 클라이언트의 요청이 있을 때 마다 서비스해준다.
while(1){
// 소켓을 사용가능한 상태로 활성화. 소켓 대기열의 크기는 10.
if(listen(ss,10)==-1){
error_handling("listen error");
}
//클라이언트로부터 요청이 오면 연결을 수락한다.
sa = accept(ss,0,0);
if(sa ==-1){
error_handling("accept error");
}
//클라이언트에게 계산할 식을 수신받는다.
recv(sa,infix,sizeof(infix),0);
// 계산 식을 스택을 이용한 후위연산식으로 변경한다.
infixToPostfix(infix, postfix, stack);
//계산을 수행하고 결과값을 result에 저장한다.
result1 = calculate(postfix);
//결과값을 클라이언트에게 전송.
send(sa,&result1,sizeof(result1),0);
//통신 종료 전 계산기 값 모두 초기화 시켜주기
memset( stack, 0, sizeof(stack));
memset( result, 0, sizeof(result));
p_top = -1;
s_top = -1;
r_top = -1;
temp = 0;
close(sa); //클라이언트와의 통신 소켓 닫기
}