GMS Linux: start?

This commit is contained in:
2025-12-30 01:20:20 +00:00
commit ac241a9148
48 changed files with 2028 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
TARGET = nc
SRCS = nc.c
CC = gcc
CFLAGS = -static -Wall
OUT_BIN ?= $(TARGET)
all: $(OUT_BIN)
$(OUT_BIN): $(SRCS)
@echo " [CC] Compiling to $(OUT_BIN)..."
$(CC) $(CFLAGS) -o $@ $^
clean:
rm -f $(TARGET)
+132
View File
@@ -0,0 +1,132 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/select.h>
#include <errno.h>
#define BUF_SIZE 1024
// 에러 처리 헬퍼
void error_exit(char *msg) {
perror(msg);
exit(1);
}
void loop(int sockfd) {
fd_set read_fds;
char buf[BUF_SIZE];
int max_fd = sockfd > STDIN_FILENO ? sockfd : STDIN_FILENO;
int stdin_eof = 0; // [NEW] 입력 종료 여부 플래그
while (1) {
FD_ZERO(&read_fds);
// [NEW] 입력이 아직 안 끝났을 때만 STDIN 감시
if (!stdin_eof) {
FD_SET(STDIN_FILENO, &read_fds);
}
FD_SET(sockfd, &read_fds); // 소켓은 항상 감시
if (select(max_fd + 1, &read_fds, NULL, NULL, NULL) < 0) {
if (errno == EINTR) continue;
error_exit("select");
}
// 1. 키보드/파일 입력 -> 소켓 전송
if (!stdin_eof && FD_ISSET(STDIN_FILENO, &read_fds)) {
int n = read(STDIN_FILENO, buf, BUF_SIZE);
if (n < 0) error_exit("read stdin");
if (n == 0) {
// [NEW] EOF(파일 끝) 도달 시:
// 즉시 종료하지 않고, "나는 보낼 거 다 보냈다"고 표시만 함
stdin_eof = 1;
// (선택사항) TCP Half-Close: 서버에게 "보낼 거 끝났다"고 알림
shutdown(sockfd, SHUT_WR);
} else {
if (write(sockfd, buf, n) < 0) error_exit("write to socket");
}
}
// 2. 소켓 수신 -> 화면 출력
if (FD_ISSET(sockfd, &read_fds)) {
int n = read(sockfd, buf, BUF_SIZE);
if (n < 0) error_exit("read socket");
if (n == 0) {
// [NEW] 서버가 연결을 끊었을 때 비로소 루프 종료!
break;
}
if (write(STDOUT_FILENO, buf, n) < 0) error_exit("write to stdout");
}
}
}
int main(int argc, char *argv[]) {
if (argc < 3) {
printf("Usage:\n");
printf(" Connect: nc <IP> <PORT>\n");
printf(" Listen : nc -l <PORT>\n");
return 1;
}
int sockfd;
struct sockaddr_in addr;
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
// --- Server Mode (-l) ---
if (strcmp(argv[1], "-l") == 0) {
int port = atoi(argv[2]);
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) error_exit("socket");
// 주소 재사용 허용 (Time-wait 방지)
int opt = 1;
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if (bind(listen_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) error_exit("bind");
if (listen(listen_fd, 1) < 0) error_exit("listen");
printf("Listening on port %d...\n", port);
struct sockaddr_in client_addr;
socklen_t client_len = sizeof(client_addr);
sockfd = accept(listen_fd, (struct sockaddr*)&client_addr, &client_len);
if (sockfd < 0) error_exit("accept");
printf("Connection from %s\n", inet_ntoa(client_addr.sin_addr));
close(listen_fd); // 더 이상 리스닝 안 함 (1:1 채팅)
}
// --- Client Mode ---
else {
char *ip = argv[1];
int port = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) error_exit("socket");
addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip, &addr.sin_addr) <= 0) error_exit("invalid address");
printf("Connecting to %s:%d...\n", ip, port);
if (connect(sockfd, (struct sockaddr*)&addr, sizeof(addr)) < 0) error_exit("connect");
printf("Connected!\n");
}
// 데이터 교환 루프 진입
loop(sockfd);
close(sockfd);
return 0;
}