🌟 TCP/IP 소켓 프로그래밍 예제 분석_p21. hello_serve r.c
더보기
#include <stdio.h>
// 표준 입출력 함수 사용 (예: printf, fputs)
#include <stdlib.h>
// 표준 라이브러리 함수 (예: atoi, exit 등 사용)
#include <string.h>
// 문자열 처리 함수들 (예: memset 사용)
#include <unistd.h>
// 유닉스 계열 시스템 함수 (예: read, write, close)
#include <arpa/inet.h>
// IP 주소 변환 등 네트워크 함수 (예: htons, htonl 등)
#include <sys/socket.h>
// 소켓 관련 함수 (예: socket(), bind(), listen(), accept() 등)
void error_handling(char *message);
// 오류 발생 시 메시지 출력 후 프로그램 종료 하는 함수의 프로토타입
int main(int argc, char *argv[])
// main 함수 시작. argc는 인자의 개수, argv는 IP 주소와 포트번호를 문자열로 저장하는 배열
{
int serv_sock;
// 서버 소켓. 클라이언트의 연결 요청을 기다리는 역할
int clnt_sock;
// 연결된 클라이언트와 실제로 통신하는 소켓
struct sockaddr_in serv_addr;
// 서버의 IP 주소와 포트 정보를 답는 구조체
struct sockaddr_in clnt_addr;
// 연결 요청을 한 클라이언트의 정보를 담는 구조체
socklen_t clnt_addr_size;
// 클라이언트 주소 구조체 크기 저장용 변수
char message[]="Hello World!";
// 클라이언트에 보낼 문자열 (응답 메시지)
if(argc!=2){
// 명령행 인자를 1개(포트)를 받지 못했을 경우 에러 메시지 출력
printf("Usage : %s <port>\n", argv[0]);
// 못 넣었다면 사용법 보여준 후 종료
exit(1);
}
serv_sock=socket(PF_INET, SOCK_STREAM, 0);
// socket() 함수: 네트워크 통신을 위한 소켓 생성
// PF_INET: IPv4 프로토콜 사용
// SOCK_STREAM: TCP(연결 지향형 스트림) 사용
// 0: 프로토콜 번호 자동 선택 (TCP면 0)
// 리턴값: 성공 시 소켓 파일 디스크립터 (정수), 실패 시 -1
if(serv_sock == -1)
// 실패 시 -1반환하고 오류 메시지 출력
error_handling("socket() error");
memset(&serv_addr, 0, sizeof(serv_addr));
// serv_addr 구조체를 0으로 초기화
// 필수 필드 이외 쓰레기값 제거 목적
serv_addr.sin_family=AF_INET;
// 주소 체계 지정: IPv4
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
// 서버 IP주소 설정.
// INADDR_ANY: 모든 네트워크 인터페이스에서 접속 허용
// htonl: 호스트 바이트 순서를 네트워크 바이트 순서로 변환
serv_addr.sin_port=htons(atoi(argv[1]));
// 포트 번호 설정
// argv[1]: 사용자가 실행 시 입력한 포트 번호
// atoi()로 문자열 -> 정수 변환
// htons(): 포트 번호를 네트워크 바이트 순서로 변환
if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1 )
// bind는 소켓을 특정 IP 주소와 포트 번호에 연결.
// serv_sock: 소켓 디스크립터
// struct sockaddr*) &serv_addr: 주소 정보 구조체
// sizeof(serv_k)
error_handling("bind() error");
// 실패 시 오휴 메시지 출력
if(listen(serv_sock, 5)==-1)
// 클라이언트 연결 요청 기다리는 강태로 전환
// 두 번째 인자 5는 대기 큐 . 동시에 최대 5개까지 대기 가능
error_handling("listen() error");
// 실패 시 오휴 메시지 출력
clnt_addr_size=sizeof(clnt_addr);
clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);
if(clnt_sock==-1)
// 클라이언트가 접속하면 연결 수락하고 새로운 소켓 생성
// serv_sock: 수신 대시 중인 소켓
// clnt_addr: 클라이언트 주소 정보 저장
error_handling("accept() error");
// 실패시 오류 메시지 출력
write(clnt_sock, message, sizeof(message));
// 클라이언트에 메시지 전송
// wtite()는 파일이나 소켓에 데이터 쓰임
close(clnt_sock);
// 클라이언트 닫기 -> 연결 종료
close(serv_sock);
// 서버 소켓 닫기 -> 프로그램 끝
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
// 에러 메시지 표준 에러 스트림에 출력
fputc('\n', stderr);
exit(1);
}
// 1. socket(): 소켓 생성
// 2. bild(): 주소 할당 (IP + 포트)
// 3. listen(): 연결 대기
// 4. accept(): 클라이언트 연결 수락
// 5. write(): 메시지 전송
// 6. close(): 소켓 닫기
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p23. hello_client. c
더보기
//socket함수와 connect 함수가 호출되고 문자열을 주고받는 것을 확인
#include <stdio.h> // printf, perror 등 입출력 함수
#include <stdlib.h> // exit, atoi 함수
#include <string.h> // memset, strlen 등 문자열 처리 함수
#include <unistd.h> // close, read 함수 (POSIX 표준 함수)
#include <arpa/inet.h> // inet_addr, htons 등 주소 변환 함수
#include <sys/socket.h> // socket, connect 함수 등 소켓 관련 함수
// 에러 메시지 출력 함수 선언
void error_handling(char *message);
int main(int argc, char *argv[]) //인자 확인 (argc, argv)
{
int sock; //소켓 디스크립터 저장용 변수
struct sockaddr_in serv_addr; //서버 주소 정보 저장용 구조체
char message[30]; //서버로부터 수신할 메시지를 담을 버퍼
int str_len; //read로 받은 데이터 길이 저장
if(argc!=3) //명령줄 인자(argument) 개수가 3개가 아니면 프로그램 종료
//조건식이 argc!=3인 이유는
//argv[0]: 실행 파일 이름
//argv[1]: IP 주소 (ex: "127.0.0.1")
//argv[2]: 포트 번호 (ex: "12345") 까지 총 3개가 필요함.
{
printf("Usage : %s <IP> <port>\n", argv[0]);
//클라이언트를 실행할 때 IP와 포트 번호를 반드시 입력받아야 함.
exit(1); //종료
}
//소켓 생성하고 실패시 -1 반환
sock=socket(PF_INET, SOCK_STREAM, 0);
//PF_INET: IPv4 사용(도메인)
//SOCK_STREAM: TCP 연결(신뢰성 보장, 스트림 방식)(타입)
//0: 프로토콜 자동 선택 (TCP 사용됨)
if(sock == -1){ //socket 함수는 호출 실패 시 -1 반환
error_handling("socket() error");
}
//서버 주소 구조체(struct sockaddr_in)를 설정
//클라이언트가 어떤 서버에 연결할 것인지 지정하는 과정
memset(&serv_addr, 0, sizeof(serv_addr));
//serv_addr 구조체의 모든 바이트를 0으로 초기화
serv_addr.sin_family=AF_INET;
//주소 체계를 IPv4로 지정
//이 설정이 있어야 connect() 또는 bind() 함수가 이 주소를 IPv4용으로 인식
//IPv4는
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
//사용자가 입력한 IP 문자열을 네트워크 바이트 순서의 정수로 변환해서 s_addr에 저장
//inet_addr() 함수: 문자열(IP 주소 형식, 예: "127.0.0.1") → 32비트 정수로 변환
serv_addr.sin_port=htons(atoi(argv[2]));
//atoi(argv[2]): 포트 번호 문자열(ex: "12345")을 정수형(int)으로 변환
//htons() 함수: short형(2바이트, 포트 번호)을 호스트 바이트 순서 → 네트워크 바이트 순서로 변환
if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){
error_handling("connect() error!");
}
str_len=read(sock, message, sizeof(message)-1);
//서버에서 데이터를 읽어옴
//read()는 최대 sizeof(message) - 1 바이트 읽음
if(str_len==-1){ //왜 -1? → 널 종료 문자 \0 넣기 위해
error_handling("read() error!");
}
printf("Message from server : %s \n", message); //서버에서 받은 메시지를 콘솔에 출력
close(sock); //소켓 종료
return 0; //프로그램 종료
}
//에러 처리 함수
void error_handling(char *message)
{
fputs(message, stderr); // 표준 에러 출력
fputc('\n', stderr); // 줄바꿈
exit(1); // 비정상 종료
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p30. low_open . c
더보기
#include <stdio.h>
// 표준 입출력 함수 사용 (예: printf, fputs)
#include <stdlib.h>
// 표준 라이브러리 함수 (예: exit 등)
#include <fcntl.h>
// 파일 제어 관련 함수 및 상수들 (예: open, O_CREAT 등)
#include <unistd.h>
// 유닉스 시스템 함수 (예: write, close 등)
void error_handling(char* message);
// 오류 발생 시 메시지를 출력하고 프로그램을 종료하는 함수의 프로토타입
int main(void)
{
int fd;
// 파일 디스크립터를 저장할 변수
char buf[] = "Let's go!\n";
// 파일에 쓸 문자열 데이터
fd = open("data.txt", O_CREAT | O_WRONLY | O_TRUNC);
// open(): 파일 열기 또는 생성하는 함수
// 첫 번째 인자: 파일 이름 ("data.txt")
// 두 번째 인자:
// O_CREAT : 파일이 없으면 새로 생성
// O_WRONLY: 쓰기 전용으로 열기
// O_TRUNC : 기존 내용 제거 (truncate)
// 리턴값: 성공 시 파일 디스크립터, 실패 시 -1
if (fd == -1)
error_handling("open() error!");
// 파일 열기에 실패한 경우 오류 메시지 출력
printf("file descriptor: %d \n", fd);
// 파일 디스크립터 값 출력 (성공적으로 열렸음을 확인)
if (write(fd, buf, sizeof(buf)) == -1)
error_handling("write() error!");
// write(): 파일에 데이터 쓰기
// fd: 대상 파일 디스크립터
// buf: 쓸 데이터가 저장된 배열
// sizeof(buf): 쓸 데이터의 크기 (문자열 길이 + NULL 문자 포함)
close(fd);
// open()으로 연 파일을 닫기 (자원 해제)
return 0;
// 프로그램 정상 종료
}
void error_handling(char* message)
{
fputs(message, stderr);
// 에러 메시지를 표준 에러 스트림에 출력
fputc('\n', stderr);
exit(1);
// 프로그램 강제 종료
}
/*
실행 예시:
root@com:/home/swyoon/tcpip# gcc low_open.c -o lopen
root@com:/home/swyoon/tcpip# ./lopen
file descriptor: 3
root@com:/home/swyoon/tcpip# cat data.txt
Let's go!
root@com:/home/swyoon/tcpip#
위 예시는 "data.txt"라는 파일을 생성하고, 그 안에 "Let's go!"라는 문자열을 저장한 후 종료.
생성된 파일은 동일 디렉터리에 존재하며 `cat` 명령어로 내용을 확인 가능
*/
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p32. low_read.c
더보기
#include <stdio.h>
// 표준 입출력 함수 사용 (예: printf, fputs)
#include <stdlib.h>
// 표준 라이브러리 함수 사용 (예: exit 등)
#include <fcntl.h>
// 파일 제어 관련 함수 및 상수들 (예: open, O_RDONLY 등)
#include <unistd.h>
// 유닉스 시스템 함수 (예: read, close 등)
#define BUF_SIZE 100
// 읽어올 데이터의 최대 크기를 정의
void error_handling(char* message);
// 오류 발생 시 메시지를 출력하고 프로그램을 종료하는 함수의 선언
int main(void)
{
int fd;
// 파일 디스크립터 저장용 변수
char buf[BUF_SIZE];
// 파일에서 읽은 데이터를 저장할 버퍼
fd = open("data.txt", O_RDONLY);
// open(): 파일 열기
// 첫 번째 인자: 열 파일 이름 ("data.txt")
// 두 번째 인자: O_RDONLY (읽기 전용으로 열기)
// 성공 시 파일 디스크립터를 반환, 실패 시 -1 반환
if(fd == -1)
error_handling("open() error!");
// 파일 열기 실패 시 오류 메시지 출력 후 종료
printf("file descriptor: %d \n", fd);
// 파일 디스크립터 번호 출력
if(read(fd, buf, sizeof(buf)) == -1)
error_handling("read() error!");
// read(): 파일에서 데이터 읽기
// fd: 읽을 대상 파일 디스크립터
// buf: 데이터를 저장할 버퍼
// sizeof(buf): 읽을 최대 크기 지정
// 실패 시 -1 반환하므로 에러 처리
printf("file data: %s", buf);
// 파일에서 읽은 내용을 문자열로 출력
close(fd);
// 열린 파일 디스크립터를 닫고 자원 해제
return 0;
// 프로그램 정상 종료
}
void error_handling(char* message)
{
fputs(message, stderr);
// 에러 메시지를 표준 에러 스트림에 출력
fputc('\n', stderr);
exit(1);
// 프로그램 종료
}
/*
실행 예시:
root@com:/home/swyoon/tcpip# gcc low_read.c -o lread
root@com:/home/swyoon/tcpip# ./lread
file descriptor: 3
file data: Let's go!
root@com:/home/swyoon/tcpip#
위 코드는 "data.txt"라는 파일을 읽기 전용으로 열고, 내용을 `buf`에 저장한 후 출력.
파일의 첫 100바이트까지만 읽음 (BUF_SIZE 기준).
읽은 후 반드시 close()로 파일을 닫아 자원을 정리해야 함!
*/
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p33. fd_seri.c
더보기
#include <stdio.h>
// 표준 입출력 함수 (예: printf)
#include <fcntl.h>
// 파일 제어 관련 함수 및 상수 (예: open, O_CREAT 등)
#include <unistd.h>
// 유닉스 시스템 호출 함수 (예: close)
#include <sys/socket.h>
// 소켓 관련 함수 및 상수 (예: socket)
int main(void)
{
int fd1, fd2, fd3;
// 파일 디스크립터를 저장할 변수들 선언
fd1 = socket(PF_INET, SOCK_STREAM, 0);
// fd1: TCP 소켓 생성
// PF_INET: IPv4 인터넷 프로토콜
// SOCK_STREAM: 연결 지향형 소켓 (TCP)
// 0: 자동으로 프로토콜 선택 (IPPROTO_TCP)
// 성공 시 양의 정수(파일 디스크립터) 반환, 실패 시 -1
fd2 = open("test.dat", O_CREAT | O_WRONLY | O_TRUNC, 0644);
// fd2: 파일 열기 (없으면 생성)
// "test.dat": 파일 이름
// O_CREAT: 파일이 없으면 새로 생성
// O_WRONLY: 쓰기 전용
// O_TRUNC: 기존 파일이 있다면 내용 제거
// 0644: 권한 (rw-r--r--), 파일 생성 시 필요
fd3 = socket(PF_INET, SOCK_DGRAM, 0);
// fd3: UDP 소켓 생성
// SOCK_DGRAM: 비연결형 소켓 (UDP)
// 각각의 디스크립터 값 출력
printf("file descriptor 1: %d\n", fd1);
printf("file descriptor 2: %d\n", fd2);
printf("file descriptor 3: %d\n", fd3);
// 사용이 끝난 파일/소켓 디스크립터는 반드시 닫아야 함
close(fd1); // TCP 소켓 닫기
close(fd2); // 파일 닫기
close(fd3); // UDP 소켓 닫기
return 0; // 프로그램 정상 종료
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p56. tcp_client.c
더보기
#include <stdio.h> // printf, perror 등 입출력 함수
#include <stdlib.h> // exit, atoi 함수
#include <string.h> // memset, strlen 등 문자열 처리 함수
#include <unistd.h> // close, read 함수 (POSIX 표준 함수)
#include <arpa/inet.h> // inet_addr, htons 등 주소 변환 함수
#include <sys/socket.h> // socket, connect 함수 등 소켓 관련 함수
void main(int argc, char* argv[])
{
int sock;
struct sockaddr_in serv_addr;
char message[30];
int str_len = 0;
int idx=0, read_len=0;
// IP와 포트를 안 주면 프로그램이 제대로 작동하지 않기 때문에 밑의 조건식 실행
if(argc!=3){ //실행인자가 3개([0]실행파일 이름, [1]IP주소, [2]포트 번호)가 아니면 종료
printf("Usage : %s <IP> <port>\n", argv[0]); //argv[0]은 실행한 프로그램 이름에서 IP와 PORT가 필요하다는 것을 알려줌
exit(1); //비정상 종료 = 1
}
//소켓 생성
sock = socket(PF_INET, SOCK_STREAM, 0); //PF_INET = IPv4, SOCK_STREAM = TCP(연결 지향형), 소켓 타입 지정, 0 = 프로토콜 자동 설정(TCP 선택됨)
if(sock == -1) error_handling("socket() error");
//서버 주소 구조체 초기화와 세팅
memset(&serv_addr, 0, sizeof(serv_addr)); //구조체를 0으로 초기화
//필요한 필드만 정확히 채워서 연결할 서버의 주소를 완성하기 위해 밑의 서버 주소에 필요한 정보를 채우는 핵심 설정 필요
serv_addr.sin_family=AF_INET; //IPv4 주소 체계
serv_addr.sin_addr.s_addr=inet_addr(argv[1]); //IP문자열을 32비트 정수로 변환
serv_addr.sin_port=htons(atoi(argv[2])); //포트 문자열을 정수로 변환하고 바이트 순서를 변환(빅엔디언)
//서버 연결 요청
if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1)
//서번에 TCP연결을 시도했지만 connect() 실패 시 -1반환
//connect()함수는 지정된 IP주소와 포트(&serv_addr)로 -> 지정된 소켓(sock))을 통해 -> 서버에게 연결 요청을 보낸다
//(struct sockaddr *)&serv_addr <- 구조체 형변환(IPv4 주소->일반주소형식)
//sizeof(serv_addr) <- 주소 구조체의 바이트 크기(connect가 필요로 함)
//connect() 내부에서 구조체 크기만큼 메모리를 읽어서 주소 정보를 정확히 해석하기 위해 필요
error_handling("connect() error!");
//데이터 수신(1바이트씩 반복)
while(read_len=read(sock, &message[idx++], 1))
//서버가 보내는 데이터를 1바이트씩 반복해서 읽음
//read가 0을 반환하면 데이터가 없으므로 종료
{
if(read_len==-1) //만약 오류-1이 발생하면 error_handling함수 가져옴
error_handling("read() error!");
str_len+=read_len; //읽은 횟수 누적
}
//수신 메시지 출력
printf("Mesage from server: %s \n", message); //받은 메시지 출력
printf("Function read call count: %d \n", str_len); //몇 번 읽었는지 출력
close(sock); //열린 소켓을 종료
return 0; //프로그램 종료
}
void error_handling(char *message) //에러 처리 함수
{
fputs(message, stderr); // 표준 에러 출력
fputc('\n', stderr); // 줄바꿈
exit(1); // 비정상 종료
}
// 1. IP와 포트 인자 확인
// 2. 소켓 생성
// 3. 서버 주소 구조체 초기화 및 설정
// 4. 서버에 연결 요청
// 5. 1바이트씩 데이터 수신 (반복)
// 6. 수신된 메시지 출력
// 7. 소켓 종료
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p74. endian_conv.c
더보기
#include <stdio.h>
// 표준 입출력 함수 (예: printf)
#include <arpa/inet.h>
// 네트워크 바이트 순서 변환 함수 (예: htons, htonl)
// 바이트 순서(Byte Order)
// - 리틀 엔디언(Little Endian): Intel CPU (호스트 바이트 순서)
// - 빅 엔디언(Big Endian): 네트워크에서 사용되는 표준 (Network Byte Order)
int main(int argc, char *argv[])
{
unsigned short host_port = 0x1234;
// 16비트 포트 번호를 호스트 바이트 순서로 정의 (0x1234)
unsigned short net_port;
// 변환된 네트워크 바이트 순서 포트를 저장할 변수
unsigned long host_addr = 0x12345678;
// 32비트 IP 주소를 호스트 바이트 순서로 정의 (0x12345678)
unsigned long net_addr;
// 변환된 네트워크 바이트 순서 주소를 저장할 변수
// htons(): 16비트 값을 호스트 -> 네트워크 바이트 순서로 변환
net_port = htons(host_port);
// htonl(): 32비트 값을 호스트 -> 네트워크 바이트 순서로 변환
net_addr = htonl(host_addr);
// 각각의 값 출력 (16진수 형태)
printf("Host ordered port: %#x \n", host_port);
// 예: 0x1234
printf("Network ordered port: %#x \n", net_port);
// 리틀 엔디언 시스템이라면: 0x3412
printf("Host ordered address: %#lx \n", host_addr);
// 예: 0x12345678
printf("Network ordered address: %#lx \n", net_addr);
// 리틀 엔디언 시스템이라면: 0x78563412
return 0;
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p77. inet_addr.c
더보기
#include <stdio.h>
// 표준 입출력 함수 (예: printf)
#include <arpa/inet.h>
// 네트워크 관련 함수와 상수 정의 (예: inet_addr, INADDR_NONE)
int main(int argc, char *argv[])
{
char *addr1 = "127.212.124.78";
// 올바른 IPv4 주소 문자열 (각 자리 0~255 사이)
char *addr2 = "127.212.124.256";
// 잘못된 IPv4 주소 (마지막 옥텟이 256으로, 유효 범위 초과)
unsigned long conv_addr;
// ▶ 첫 번째 주소 변환 시도
conv_addr = inet_addr(addr1);
// inet_addr(): 문자열 형태의 IPv4 주소를 정수형 네트워크 바이트 순서로 변환
// 성공 시: 변환된 32비트 값 (network byte order)
// 실패 시: INADDR_NONE 반환
if(conv_addr == INADDR_NONE)
printf("Error occured! \n");
else
printf("Network ordered integer addr: %#lx \n", conv_addr);
// 변환된 주소를 16진수로 출력
// ▶ 두 번째 주소 변환 시도 (유효하지 않음)
conv_addr = inet_addr(addr2);
if(conv_addr == INADDR_NONE)
printf("Error occureded \n");
else
printf("Network ordered integer addr: %#lx \n\n", conv_addr);
return 0;
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p78. inet_aton.c
더보기
#include <stdio.h>
// 표준 입력/출력 라이브러리. 화면에 메세지 출력, 사용자 입력시 사용
#include <stdlib.h>
// error_handling() 함수에서 사용된 fputs는 여기서 제공되는 함수
#include <arpa/inet.h>
// 네트워크 관련 함수 제공, 특히 ip 주소를 다루는 함수 포함으로 문자열로 된
// ip함수를 네트워크 바이트 순서로 변환하는 역할
void error_handling(char *message);
// 함수 미리 선언 하는 이유는 다른 파일에서 이 함수를 사용할 수 있도록 함수를 공유하는 역할을 함
// 고로 다른 소스 파일들에서 함수 선언을 미리 알게 됨
//만일 미리 선언 안 하면 컴파일시 해당 함수가 무엇인지 알 수 없게 되어 오류 발생
// 함수의 선언이 컴파일러에게 함수가 어떻게 생겼는지 미리 알려주는 역할
int main(int argc, char *argv[])
// argc는 명령행 인수의 개수
// argv는 명령행 인수들을 담고 있는 배열
// 현 코드에서 main() 함수에 직접 IP를 입력받아 하드코딩 되어 있어 argc, argv는 필요하지 않다.
{
char *addr="127.232.124.79";
// IP 주소를 문자열로 저장하는 변수
struct sockaddr_in addr_inet;
//소켓 프로그래밍 구조체, 인터넷 주소 정보 저장해서 IP 주소나 포느 번호 포함. 현재는 IP 주소 처리만 담당
if(!inet_aton(addr, &addr_inet.sin_addr))
// inet_aton() 함수는 문자열로 표현된 IP 주소를 네트워크 바이트로 변환해서 add_inet.sin_addr에 저장
// inet_aton()이 실패하면 0을 반환하고 성공하면 1 반환해서 sin.addr 구조체에 반환된 IP 주소 저장.
error_handling("Conversion error");
// error_handling() 함수는 오류 메시지를 출력하는 함수
// 즉 실패하면 오류 메세지 출력 함수가 호출됨
else
printf("Network ordered integer addr: %#x \n", addr_inet.sin_addr.s_addr);
// 반환에 성공하면 else 블록 실행되서 addr_inet.sin_addr.s_addr를 16진수 형식으로 출력
//(이 값은 네트워크 바이트 순서로 변환된 IP 주소 출력)
//%#x는 16진수로 출려될 때 접두사 0x를 붙여 출력되도록 하는 포맷 지정자
return 0;
}
void error_handling(char *message)
// 오류 출력하는 함수, 인자로 받은 메시지를 표준 에러 스크림 stderr에 출력
{
fputs(message, stderr);
// fputs()는 문자열을 출력하는 함수, 여기선 표준 에러 스트림에 message 문자열을 출력
fputc('\n', stderr);
// fputc() 는 한 문자를 출력하는 함수, 여기서 줄 바꿈 문자를 출력해서 메시지 뒤에 한 줄을 뛰움
}
// 이 프로그램은 하드코딩된 IP 주소를 네트워크 바이트 순서로 변환하고, 그 값을 출력하는 프로그램
// 프로그램에서는 "127.232.124.79"라는 IP 주소를 네트워크 바이트 순서로 변환하고, 그 값을 16진수 형태로 출력
// stdio.h는 표준 입출력 관련 함수를 사용.
// stdlib.h는 표준 라이브러리 함수. 메모리 할당, 프로세스 종료 등의 함수가 있음.
// arpa/inet.h 는 네트워크 관련 함수 사용 헤더 파일. IP 주소 문자열을 네트워크 바이트 순서 정수로 변환 역할
// error_handling() 함수 선언: 에러 발생 시 에러 메시지를 출력하는 함수의 프로토타입
// addr은 하드코딩된 IP 주소
// addr_inet:struct sockaddr_in 구조체로 IP 주소와 포트 번호 저장 가능 구조체
// inet_aton() 함수 호출
// 문자열로 된 IP 주소 네트워크 바이트 순서의 정수로 변환
// 첫 번째 매개변수로 IP 주소 문자열 입력. 두 번째 매개변수로 변환된 값을 구조체의 sin.addr에 저장
// 함수가 실패하면 0 반환하고 erroer_handling() 함수 로출되어 에러 메세지 출력
// 변환 성공 시
// addr_inet.sin_addr.s_addr에 네트워크 바이트 순서로 변환된 IP 주소 저장
// 그 값을 16진수 형태로 출력. %#x는 16진수 형식으로 출력하고 앞에 0x 붙여서 출력
// error_handling()는 에러 메시지 출력
// fputs는 에러 메시지 출력
// fputc는 줄 바꿈 추가
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p80. inet_ntoa.c
더보기
//함수 반환값이 static 메모리를 사용하기 때문에, 이전 결과가 덮어쓰기되는 문제
//inet_ntoa() 함수는 struct in_addr 구조체에 들어 있는 IPv4 주소를 문자열(IP 주소 형태)로 바꿔주는 함수
#include <stdio.h> //입출력
#include <string.h> //문자열
#include <arpa/inet.h> //네트워크 주소 반환
int main(int argc, char *argv[]) //인자 확인 (argc, argv)
{
struct sockaddr_in addr1, addr2; //addr1, addr2: 각각 IP 주소를 저장할 구조체
//두 번째 호출이 이전 반환값을 덮어쓰는 것을 확인하기 위해 주소 2개 받기
char *str_ptr; //문자열 포인터 (inet_ntoa의 반환값 저장)
char str_arr[20]; //문자열을 안전하게 복사해서 보관할 배열
addr1.sin_addr.s_addr=htonl(0x1020304);
//0x1020304 → 16진수 IP 주소를 빅엔디언(네트워크 바이트 순서)로 변환해 저장
//inet_ntoa()를 사용할 수 있게 세팅
addr2.sin_addr.s_addr=htonl(0x1010101);
str_ptr=inet_ntoa(addr1.sin_addr); //addr1의 IP 주소를 문자열로 변환
strcpy(str_arr, str_ptr);
//현재 IP 문자열을 안전하게 str_arr에 복사
//이후 str_ptr이 변경돼도 str_arr에 남아 있게 하기 위함
printf("Dotted-Decimal notation1: %s \n", str_ptr);//addr1의 IP 출력
inet_ntoa(addr2.sin_addr);
printf("Dotted-Decimal notation2: %s \n", str_ptr); //덮어써진 결과
printf("Dotted-Decimal notation3: %s \n", str_arr); //복사해둔 원래 결과
return 0;
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p103. hello _serve r.c <중복>
더보기
#include <stdio.h>
// 표준 입출력 함수 사용 (예: printf, fputs)
#include <stdlib.h>
// 표준 라이브러리 함수 (예: atoi, exit 등 사용)
#include <string.h>
// 문자열 처리 함수들 (예: memset 사용)
#include <unistd.h>
// 유닉스 계열 시스템 함수 (예: read, write, close)
#include <arpa/inet.h>
// IP 주소 변환 등 네트워크 함수 (예: htons, htonl 등)
#include <sys/socket.h>
// 소켓 관련 함수 (예: socket(), bind(), listen(), accept() 등)
void error_handling(char *message);
// 오류 발생 시 메시지 출력 후 프로그램 종료 하는 함수의 프로토타입
int main(int argc, char *argv[])
// main 함수 시작. argc는 인자의 개수, argv는 IP 주소와 포트번호를 문자열로 저장하는 배열
{
int serv_sock;
// 서버 소켓. 클라이언트의 연결 요청을 기다리는 역할
int clnt_sock;
// 연결된 클라이언트와 실제로 통신하는 소켓
struct sockaddr_in serv_addr;
// 서버의 IP 주소와 포트 정보를 답는 구조체
struct sockaddr_in clnt_addr;
// 연결 요청을 한 클라이언트의 정보를 담는 구조체
socklen_t clnt_addr_size;
// 클라이언트 주소 구조체 크기 저장용 변수
char message[]="Hello World!";
// 클라이언트에 보낼 문자열 (응답 메시지)
if(argc!=2){
// 명령행 인자를 1개(포트)를 받지 못했을 경우 에러 메시지 출력
printf("Usage : %s <port>\n", argv[0]);
// 못 넣었다면 사용법 보여준 후 종료
exit(1);
}
serv_sock=socket(PF_INET, SOCK_STREAM, 0);
// socket() 함수: 네트워크 통신을 위한 소켓 생성
// PF_INET: IPv4 프로토콜 사용
// SOCK_STREAM: TCP(연결 지향형 스트림) 사용
// 0: 프로토콜 번호 자동 선택 (TCP면 0)
// 리턴값: 성공 시 소켓 파일 디스크립터 (정수), 실패 시 -1
if(serv_sock == -1)
// 실패 시 -1반환하고 오류 메시지 출력
error_handling("socket() error");
memset(&serv_addr, 0, sizeof(serv_addr));
// serv_addr 구조체를 0으로 초기화
// 필수 필드 이외 쓰레기값 제거 목적
serv_addr.sin_family=AF_INET;
// 주소 체계 지정: IPv4
serv_addr.sin_addr.s_addr=htonl(INADDR_ANY);
// 서버 IP주소 설정.
// INADDR_ANY: 모든 네트워크 인터페이스에서 접속 허용
// htonl: 호스트 바이트 순서를 네트워크 바이트 순서로 변환
serv_addr.sin_port=htons(atoi(argv[1]));
// 포트 번호 설정
// argv[1]: 사용자가 실행 시 입력한 포트 번호
// atoi()로 문자열 -> 정수 변환
// htons(): 포트 번호를 네트워크 바이트 순서로 변환
if(bind(serv_sock, (struct sockaddr*) &serv_addr, sizeof(serv_addr))==-1 )
// bind는 소켓을 특정 IP 주소와 포트 번호에 연결.
// serv_sock: 소켓 디스크립터
// struct sockaddr*) &serv_addr: 주소 정보 구조체
// sizeof(serv_k)
error_handling("bind() error");
// 실패 시 오휴 메시지 출력
if(listen(serv_sock, 5)==-1)
// 클라이언트 연결 요청 기다리는 강태로 전환
// 두 번째 인자 5는 대기 큐 . 동시에 최대 5개까지 대기 가능
error_handling("listen() error");
// 실패 시 오휴 메시지 출력
clnt_addr_size=sizeof(clnt_addr);
clnt_sock=accept(serv_sock, (struct sockaddr*)&clnt_addr,&clnt_addr_size);
if(clnt_sock==-1)
// 클라이언트가 접속하면 연결 수락하고 새로운 소켓 생성
// serv_sock: 수신 대시 중인 소켓
// clnt_addr: 클라이언트 주소 정보 저장
error_handling("accept() error");
// 실패시 오류 메시지 출력
write(clnt_sock, message, sizeof(message));
// 클라이언트에 메시지 전송
// wtite()는 파일이나 소켓에 데이터 쓰임
close(clnt_sock);
// 클라이언트 닫기 -> 연결 종료
close(serv_sock);
// 서버 소켓 닫기 -> 프로그램 끝
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
// 에러 메시지 표준 에러 스트림에 출력
fputc('\n', stderr);
exit(1);
}
// 1. socket(): 소켓 생성
// 2. bild(): 주소 할당 (IP + 포트)
// 3. listen(): 연결 대기
// 4. accept(): 클라이언트 연결 수락
// 5. write(): 메시지 전송
// 6. close(): 소켓 닫기
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p106. hello_client.c <중복>
더보기
//socket함수와 connect 함수가 호출되고 문자열을 주고받는 것을 확인
#include <stdio.h> // printf, perror 등 입출력 함수
#include <stdlib.h> // exit, atoi 함수
#include <string.h> // memset, strlen 등 문자열 처리 함수
#include <unistd.h> // close, read 함수 (POSIX 표준 함수)
#include <arpa/inet.h> // inet_addr, htons 등 주소 변환 함수
#include <sys/socket.h> // socket, connect 함수 등 소켓 관련 함수
// 에러 메시지 출력 함수 선언
void error_handling(char *message);
int main(int argc, char *argv[]) //인자 확인 (argc, argv)
{
int sock; //소켓 디스크립터 저장용 변수
struct sockaddr_in serv_addr; //서버 주소 정보 저장용 구조체
char message[30]; //서버로부터 수신할 메시지를 담을 버퍼
int str_len; //read로 받은 데이터 길이 저장
if(argc!=3) //명령줄 인자(argument) 개수가 3개가 아니면 프로그램 종료
//조건식이 argc!=3인 이유는
//argv[0]: 실행 파일 이름
//argv[1]: IP 주소 (ex: "127.0.0.1")
//argv[2]: 포트 번호 (ex: "12345") 까지 총 3개가 필요함.
{
printf("Usage : %s <IP> <port>\n", argv[0]);
//클라이언트를 실행할 때 IP와 포트 번호를 반드시 입력받아야 함.
exit(1); //종료
}
//소켓 생성하고 실패시 -1 반환
sock=socket(PF_INET, SOCK_STREAM, 0);
//PF_INET: IPv4 사용(도메인)
//SOCK_STREAM: TCP 연결(신뢰성 보장, 스트림 방식)(타입)
//0: 프로토콜 자동 선택 (TCP 사용됨)
if(sock == -1){ //socket 함수는 호출 실패 시 -1 반환
error_handling("socket() error");
}
//서버 주소 구조체(struct sockaddr_in)를 설정
//클라이언트가 어떤 서버에 연결할 것인지 지정하는 과정
memset(&serv_addr, 0, sizeof(serv_addr));
//serv_addr 구조체의 모든 바이트를 0으로 초기화
serv_addr.sin_family=AF_INET;
//주소 체계를 IPv4로 지정
//이 설정이 있어야 connect() 또는 bind() 함수가 이 주소를 IPv4용으로 인식
//IPv4는
serv_addr.sin_addr.s_addr=inet_addr(argv[1]);
//사용자가 입력한 IP 문자열을 네트워크 바이트 순서의 정수로 변환해서 s_addr에 저장
//inet_addr() 함수: 문자열(IP 주소 형식, 예: "127.0.0.1") → 32비트 정수로 변환
serv_addr.sin_port=htons(atoi(argv[2]));
//atoi(argv[2]): 포트 번호 문자열(ex: "12345")을 정수형(int)으로 변환
//htons() 함수: short형(2바이트, 포트 번호)을 호스트 바이트 순서 → 네트워크 바이트 순서로 변환
if(connect(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr))==-1){
error_handling("connect() error!");
}
str_len=read(sock, message, sizeof(message)-1);
//서버에서 데이터를 읽어옴
//read()는 최대 sizeof(message) - 1 바이트 읽음
if(str_len==-1){ //왜 -1? → 널 종료 문자 \0 넣기 위해
error_handling("read() error!");
}
printf("Message from server : %s \n", message); //서버에서 받은 메시지를 콘솔에 출력
close(sock); //소켓 종료
return 0; //프로그램 종료
}
//에러 처리 함수
void error_handling(char *message)
{
fputs(message, stderr); // 표준 에러 출력
fputc('\n', stderr); // 줄바꿈
exit(1); // 비정상 종료
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p110. echo_server.c
더보기
#include <stdio.h>
// 표준 입출력 함수 (예: printf, fputs)
#include <stdlib.h>
// 표준 라이브러리 함수 (예: atoi, exit 등)
#include <string.h>
// 메모리 관련 함수 (예: memset)
#include <unistd.h>
// 유닉스 시스템 함수 (예: read, write, close)
#include <arpa/inet.h>
// 주소 변환 함수 (예: htons, htonl 등)
#include <sys/socket.h>
// 소켓 함수 (예: socket, bind, listen, accept)
#define BUF_SIZE 1024
// 한 번에 송수신할 최대 버퍼 크기
void error_handling(char *message);
// 오류 발생 시 메시지를 출력하고 프로그램을 종료하는 함수
int main(int argc, char *argv[])
{
int serv_sock, clnt_sock;
// 서버용 소켓, 클라이언트용 소켓
char message[BUF_SIZE];
// 클라이언트로부터 받은 메시지를 저장할 버퍼
int str_len, i;
// str_len: 수신한 바이트 수, i: 클라이언트 수 카운트
struct sockaddr_in serv_adr;
// 서버 주소 구조체
struct sockaddr_in clnt_adr;
// 클라이언트 주소 구조체
socklen_t clnt_adr_sz;
// 클라이언트 주소 구조체 크기
// 포트 인자 확인
if(argc != 2) {
printf("Usage : %s <port>\n", argv[0]);
exit(1);
}
// 1. 서버 소켓 생성
serv_sock = socket(PF_INET, SOCK_STREAM, 0);
if(serv_sock == -1)
error_handling("socket() error");
// 2. 서버 주소 설정
memset(&serv_adr, 0, sizeof(serv_adr));
serv_adr.sin_family = AF_INET; // IPv4
serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); // 모든 IP에서 접속 허용
serv_adr.sin_port = htons(atoi(argv[1])); // 포트 번호 (문자열 -> 정수)
// 3. 소켓과 주소 연결(bind)
if(bind(serv_sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr)) == -1)
error_handling("bind() error");
// 4. 연결 요청 대기 상태로 전환
if(listen(serv_sock, 5) == -1)
error_handling("listen() error");
clnt_adr_sz = sizeof(clnt_adr);
// 최대 5명의 클라이언트를 순차적으로 처리
for(i = 0; i < 5; i++)
{
// 5. 클라이언트 연결 수락
clnt_sock = accept(serv_sock, (struct sockaddr*)&clnt_adr, &clnt_adr_sz);
if(clnt_sock == -1)
error_handling("accept() error");
else
printf("Connected client %d \n", i + 1);
// 6. 에코 처리 (클라이언트가 보낸 메시지를 그대로 다시 보냄)
while((str_len = read(clnt_sock, message, BUF_SIZE)) != 0)
write(clnt_sock, message, str_len);
// 7. 클라이언트 소켓 종료
close(clnt_sock);
}
// 8. 서버 소켓 종료
close(serv_sock);
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr); // 에러 메시지를 stderr로 출력
fputc('\n', stderr);
exit(1); // 비정상 종료
}
🌟 TCP/IP 소켓 프로그래밍 예제 분석_ p113. ehco_client.c
더보기
#include <stdio.h>
// 표준 입출력 라이브러리. printf(), fgets(), fputs() 등 사용자 입력 및 출력에 필요
#include <stdlib.h>
// 표준 라이브러리. atoi(), 에러 처리 함수에 사용
#include <string.h>
// 문자열 비교와 초기화를 위한 라이브러리
#include <unistd.h>
// UNIX 계열에서 read(), write(), close() 같은 시스템 호출을 사용하기 위한 헤더파일
#include <arpa/inet.h>
// IP 주소 변환, 소켓 주소 구조체 정의
#include <sys/socket.h>
// 소켓 생성 및 통신에 필요한 함수 및 자료형 정의. 예: socket(), connect() 등
#define BUF_SIZE 1024
// 메시지를 저장할 버퍼의 크기 정의
void error_handling(char *message);
// 오류 발생 시 메시지 출력 후 프로그램 종료 하는 함수의 프로토타입
int main(int argc, char *argv[])
// main 함수 시작. argc는 인자의 개수, argv는 IP 주소와 포트번호를 문자열로 저장하는 배열
// 예를 들어 "./client 127.0.0.1 9190"
// agrv[0]: ./client(프로그램 이름) // grgv[1]:127.0.0.1 (IP주소) // grgv[2]: 9190 (포트번호)
{
int sock;
// 통신용 소켓
char message[BUF_SIZE];
// 송수신할 메시지를 저장할 배열
int str_len;
// 실제 받은 문자열 길이 저장할 변수
struct sockaddr_in serv_adr;
// 서버 주소를 저장할 구조체
if(argc!=3) {
// 명령행 인자를 2개(IP와 포트)를 받지 못했을 경우 에러 메시지 출력
printf("Usage : %s <IP> <port>\n", argv[0]);
exit(1);
// 못 넣었다면 사용법 보여준 후 종료
}
sock=socket(PF_INET, SOCK_STREAM, 0);
// PF_INET: IPv4 인터넷 프로토콜 사용
// SOCK_STREAM: TCP 연결 사용 (데이터의 신뢰성 보장)
// 0: 기본 프로토콜 사용
// 반환된 값은 소켓의 파일 디스크입터. 실패 시 -1 반환
if(sock==-1)
error_handling("socket() error");
// 소켓 생성 실패 시 에러 출력
memset(&serv_adr, 0, sizeof(serv_adr));
// serv_adr: 어느 서버에 연결할지 주소 정보 담는 곳
// memset: 구조체 전체를 0으로 초기화
serv_adr.sin_family=AF_INET;
// sin_family: 주소 체계 설정 (IPv4)
serv_adr.sin_addr.s_addr=inet_addr(argv[1]);
// IP 주소를 문자열에서 숫자로 변환해서 구조체에 저장
// argv[1]은 명령행 인자로 입력한 IP 주소
serv_adr.sin_port=htons(atoi(argv[2]));
// 포트번호 설정. atoi는 문자열을 숫자로 변환
// htons는 호스트 바이트 순서를 네트워크 바이트 순서로 전환
if(connect(sock, (struct sockaddr*)&serv_adr, sizeof(serv_adr))==-1)
error_handling("connect() error!");
// 서버에 연결 시도, 실패시 에러 출력
else
puts("Connected...........");
// 연결 성공 시 메시지 출력
while(1)
{
fputs("Input message(Q to quit): ", stdout);
// 사용자에게 메시지 입력 안내문 출력
fgets(message, BUF_SIZE, stdin);
// 사용자로부터 메시지 입력 (최대 BUF_SIZE-1 글자)
if(!strcmp(message,"q\n") || !strcmp(message,"Q\n"))
break;
// q 또는 Q 입력 시 반복 재생 (채팅 종료)
write(sock, message, strlen(message));
// 입력한 메시지 서버로 전송
str_len=read(sock, message, BUF_SIZE-1);
// 서버로부터 응답 메시비를 읽음
message[str_len]=0;
// 문자열 마지막에 널 문자 추가하려 출력 가능하게 만듦
printf("Message from server: %s", message);
// 서버에서 받은 메시지 출력
}
close(sock);
// 통신 종료 후 소켓 닫기
return 0;
}
void error_handling(char *message)
{
fputs(message, stderr);
// 에러 메시지 표준 에러 스트림에 출력
fputc('\n', stderr);
exit(1);
}
// 1. 프로그램 실행과 입력값 확인 (명령행 인자 확인 IP, 포트)
// 2. 소켓 생성
// 3. 서버 주소 정보 설정 (구조체)
// 4. 서버에 연결 시도
// 5. 사용자 입력 받기
// 6. 서버에 메시지 전송
// 7. 서버 응답 받아 출력
// 8. 사용자가 q/Q 입력시 종료
// 9. 소켓 닫고 프로그램 종료
'C > Study' 카테고리의 다른 글
C언어 Newwork Study 5 (1) | 2025.07.11 |
---|---|
C언어 Newwork Study 4 (1) | 2025.07.11 |
C언어 Newwork Study 3 (0) | 2025.07.11 |
C언어 Newwork Study 1 (0) | 2025.06.30 |