
// 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
#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);
}
초기 상태

아직 서버와 클라이언트를 연결하지 않아 아무 것도 잡히지 않는 모습
연결했을 때 보다 쉽게 파악하기 위해
tcp.port == 9001
필터링을 설정하여 바로 찾을 수 있게끔 해준다

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


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


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

먼저 위에서 분석했던 대로 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