C언어 Newwork Study 2

2025. 7. 11. 23:06·C/Study

 

 

 

 

 

 

 

 

 

 

🌟 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
'C/Study' 카테고리의 다른 글
  • C언어 Newwork Study 5
  • C언어 Newwork Study 4
  • C언어 Newwork Study 3
  • C언어 Newwork Study 1
eull
eull
eull 님의 블로그 입니다.
  • eull
    eull 님의 블로그
    eull
  • 전체
    오늘
    어제
    • 개발 환경 (32) N
      • Qt (1) N
        • API (0)
        • Project (1) N
      • MYSQL_Workbench (1)
        • setting (1)
      • Linux_Ubuntu (2)
        • Task (1)
        • Setting (1)
      • C (19)
        • Concept (4)
        • Task (8)
        • Project (1)
        • Study (5)
        • Setting (1)
      • C++ (1)
        • Study (0)
        • Concept (1)
      • Python (6)
        • Task (4)
        • Project (2)
      • 일상 (1)
      • Setting (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
eull
C언어 Newwork Study 2
상단으로

티스토리툴바