[NP] Time / Calculator Implementation

mlnls·2024년 7월 12일

NP_Project

목록 보기
2/4
post-thumbnail

Server Code

// Server Code

#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
#include <signal.h>
#include <time.h>

#define MAX_CLIENTS 10

void error_proc();
void sigint_handler(int signum);

int srvSd;
int clients[MAX_CLIENTS] = {0};

int main(int argc, char **argv)
{
    struct sockaddr_in srvAddr, clntAddr;
    int clntAddrLen, readLen;
    char rBuff[BUFSIZ];
    fd_set read_fds;

    if (argc != 2)
    {
        printf("Usage: %s [port] \n", argv[0]);
        exit(1);
    }
    printf("Server start...\n");

    signal(SIGINT, sigint_handler);

    srvSd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (srvSd == -1)
        error_proc();

    memset(&srvAddr, 0, sizeof(srvAddr));
    srvAddr.sin_addr.s_addr = htonl(INADDR_ANY);
    srvAddr.sin_family = AF_INET;
    srvAddr.sin_port = htons(atoi(argv[1]));

    if (bind(srvSd, (struct sockaddr *)&srvAddr, sizeof(srvAddr)) == -1)
        error_proc();
    if (listen(srvSd, 2) < 0)
        error_proc();

    FD_ZERO(&read_fds);
    FD_SET(srvSd, &read_fds);
    int maxSd = srvSd;

    while (1)
    {
        fd_set tmp_fds = read_fds;

        int activity = select(maxSd + 1, &tmp_fds, NULL, NULL, NULL);
        if (activity < 0)
        {
            printf("Select error\n");
            break;
        }

        if (FD_ISSET(srvSd, &tmp_fds))
        {
            clntAddrLen = sizeof(clntAddr);
            int clntSd = accept(srvSd, (struct sockaddr *)&clntAddr, &clntAddrLen);
            if (clntSd == -1)
                error_proc();
            printf("client %s:%d is connected...\n",
                   inet_ntoa(clntAddr.sin_addr),
                   ntohs(clntAddr.sin_port));

            for (int i = 0; i < MAX_CLIENTS; i++)
            {
                if (clients[i] == 0)
                {
                    clients[i] = clntSd;
                    break;
                }
            }

            FD_SET(clntSd, &read_fds);
            if (clntSd > maxSd)
                maxSd = clntSd;
        }

        for (int i = 0; i < MAX_CLIENTS; i++)
        {
            int clntSd = clients[i];
            if (FD_ISSET(clntSd, &tmp_fds))
            {
                readLen = read(clntSd, rBuff, BUFSIZ - 1);
                if (readLen <= 0)
                {
                    printf("Client(%d) disconnected.\n", clntSd);
                    close(clntSd);
                    FD_CLR(clntSd, &read_fds);
                    clients[i] = 0;
                }
                else
                {
                    rBuff[readLen] = '\0';
                    printf("Client(%d): %s", clntSd, rBuff);

                    if (strcmp(rBuff, "-1") == 0||strcmp(rBuff, "-1\n") == 0)
                    {
                        printf("Server is shutting down...\n");
                        close(srvSd);
                        for (int i = 0; i < MAX_CLIENTS; i++)
                        {
                            if (clients[i] != 0)
                            {
                                close(clients[i]);
                                FD_CLR(clients[i], &read_fds);
                            }
                        }
                        exit(0);
                    }
                    else if (strstr(rBuff, "cal") != NULL)
                    {
                        int num1, num2, result;
                        char operation;
                        sscanf(rBuff, "cal %d %c %d", &num1, &operation, &num2);
                        switch (operation)
                        {
                        case '+':
                            result = num1 + num2;
                            break;
                        case '-':
                            result = num1 - num2;
                            break;
                        case '*':
                            result = num1 * num2;
                            break;
                        default:
                            result = 0;
                            break;
                        }
                        sprintf(rBuff, "%d\n", result);
                        write(clntSd, rBuff, strlen(rBuff));
                    }
                    else if (strcmp(rBuff, "time") == 0||strcmp(rBuff, "time\n") == 0)
                    {
                        time_t rawtime;
                        struct tm *timeinfo;
                        time(&rawtime);
                        timeinfo = localtime(&rawtime);
                        sprintf(rBuff, "%s", asctime(timeinfo));
                        write(clntSd, rBuff, strlen(rBuff));
                    }
                    else
                    {
                        write(clntSd, rBuff, strlen(rBuff));
                    }
                }
            }
        }
    }

    close(srvSd);
    return 0;
}

void error_proc()
{
    fprintf(stderr, "Error: %s \n", strerror(errno));
    exit(1);
}

void sigint_handler(int signum)
{
    printf("\nSIGINT received. Server is shutting down...\n");
    fflush(stdout);
	close(srvSd);
    exit(0);
}

Client Code

// Client Code

#include <stdlib.h>
#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>

void error_proc();

int main(int argc, char **argv)
{
    int clntSd;
    struct sockaddr_in clntAddr;
    int recvByte;
    char rBuff[BUFSIZ];
    fd_set read_fds;

    if (argc != 3)
    {
        printf("Usage: %s [IP Address] [Port]\n", argv[0]);
        exit(1);
    }

    clntSd = socket(AF_INET, SOCK_STREAM, 0);
    if (clntSd == -1)
        error_proc();
    printf("==== client program =====\n");

    memset(&clntAddr, 0, sizeof(clntAddr));
    clntAddr.sin_family = AF_INET;
    clntAddr.sin_addr.s_addr = inet_addr(argv[1]);
    clntAddr.sin_port = htons(atoi(argv[2]));

    if (connect(clntSd, (struct sockaddr *)&clntAddr,
                sizeof(clntAddr)) == -1)
    {
        close(clntSd);
        error_proc();
    }

	while (1)
	{
		FD_ZERO(&read_fds);
		FD_SET(clntSd, &read_fds);
		FD_SET(0, &read_fds);

		if (select(clntSd + 1, &read_fds, NULL, NULL, NULL) < 0)
		{
			printf("Select error\n");
			break;
		}

		if (FD_ISSET(clntSd, &read_fds))
		{
			recvByte = read(clntSd, rBuff, BUFSIZ - 1);
			if (recvByte <= 0)
			{
				printf("Server disconnected.\n");
				close(clntSd);
				exit(1);
			}
			rBuff[recvByte] = '\0';
			printf("Server: %s", rBuff);
		}
		else if (FD_ISSET(0, &read_fds))
		{
			char wBuff[BUFSIZ];
			fgets(wBuff, BUFSIZ - 1, stdin);
			write(clntSd, wBuff, strlen(wBuff));

			// 클라이언트가 "END"를 입력하면 종료
			if (strcmp(wBuff, "END\n") == 0)
			{
				printf("END ^^\n", wBuff);
				break;
			}
		}
	}

    close(clntSd);
    return 0;
}

void error_proc()
{
    fprintf(stderr, "Error: %s\n", strerror(errno));
    exit(errno);
}

Wireshark를 통한 분석

초기 상태

아직 서버와 클라이언트를 연결하지 않아 아무 것도 잡히지 않는 모습
연결했을 때 보다 쉽게 파악하기 위해

tcp.port == 9001

필터링을 설정하여 바로 찾을 수 있게끔 해준다

위와 같이 연결 했을때, wireshark에 SYN ACK를 보내 TCP 연결을 확인한다
IP address와 Port number를 확인하면 동일한 것을 알 수 있다
-> 제대로 연결이 되었다는 뜻!

위와 같이 Time / Calculator 진행 중에도 모두 packet을 주고받으며 잘 연결되어 있음을 확인할 수 있다

위 그림과 같이 -1을 호출하여 서버를 종료시키자 FIN ACK를 보내며 TCP 연결을 마무리한다


Netstat을 통한 분석

먼저 위에서 분석했던 대로 wireshark에서 port number를 확인해준다

# 해당 프로토콜을 사용하고 있는 프로그램을 보여줌
netstat -p tcp

위의 그림을 보면 localhost.53810 이 동일하게 잡히는 모습을 볼 수 있다
이처럼 netstat을 통해서도 TCP 통신중인 외부 port number을 확인할 수 있다

# 현재 다른 시스템과 연결된 상태(Established)인 모든 포트 정보를 조회
netstat -an | grep "ESTABLISHED"

우리의 port와 같은 <-> 54512 를 확인할 수 있다

# 사용자가 사용중인 모든 포트를 조회
netstat -tnl

우리가 사용하는 포트가 위에 뜨는 것을 확인할 수 있다
127.0.0.1.9001

profile
@mlnl_s

0개의 댓글