GMS Linux: start?
This commit is contained in:
@@ -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)
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user