Linux에 C로 FTP Server와 Client 작성하기

FTP Server

컴파일 및 실행 방법

1
2
$ gcc -o server server.c
$ ./server 9999

server.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <netinet/in.h>
#include <fcntl.h>

int tcp_listen(int host, int port, int backlog) {
int sd;
struct sockaddr_in servaddr;

sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) {
perror("socket fail");
exit(1);
}
// servaddr 구조체의 내용 세팅
bzero((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(host);
servaddr.sin_port = htons(port);
if (bind(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind fail"); exit(1);
}
// 클라이언트로부터 연결요청을 기다림
listen(sd, backlog);
return sd;
}

int main(int argc, char *argv[])
{
struct sockaddr_in server, client;
struct stat obj;
int sock1, sock2;
char buf[100], command[5], filename[20];
int k, i, size, len, c;
int filehandle;

sock1 = tcp_listen(INADDR_ANY, atoi(argv[1]), 5);

len = sizeof(client);
sock2 = accept(sock1, (struct sockaddr*)&client, &len);
while (1) {
recv(sock2, buf, 100, 0);
sscanf(buf, "%s", command);
if (!strcmp(command, "ls")) {//ls명령어를 입력받았다면
system("ls >temps.txt");
stat("temps.txt", &obj);
size = obj.st_size;
send(sock2, &size, sizeof(int), 0);
filehandle = open("temps.txt", O_RDONLY);
sendfile(sock2, filehandle, NULL, size);
}
else if (!strcmp(command, "get")) {//get명령어를 입력받았다면
sscanf(buf, "%s%s", filename, filename);
stat(filename, &obj);
filehandle = open(filename, O_RDONLY);
size = obj.st_size;
if (filehandle == -1)
size = 0;
send(sock2, &size, sizeof(int), 0);
if (size)
sendfile(sock2, filehandle, NULL, size);

}
else if (!strcmp(command, "put")) {//put명령어를 입력받았다면
int c = 0, len;
char *f;
sscanf(buf + strlen(command), "%s", filename);
recv(sock2, &size, sizeof(int), 0);

while (1) {
filehandle = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (filehandle == -1)
sprintf(filename + strlen(filename), "_1");
else break;
}
f = malloc(size);
recv(sock2, f, size, 0);
c = write(filehandle, f, size);
close(filehandle);
send(sock2, &c, sizeof(int), 0);
}
else if (!strcmp(command, "pwd")) {//pwd명령어를 입력받았다면
system("pwd>temp.txt");
i = 0;
FILE*f = fopen("temp.txt", "r");
while (!feof(f)) buf[i++] = fgetc(f);
buf[i - 1] = '\0';
fclose(f);
send(sock2, buf, 100, 0);
}
else if (!strcmp(command, "cd")) {//cd명령어를 입력받았다면
if (chdir(buf + 3) == 0) c = 1;
else c = 0;
send(sock2, &c, sizeof(int), 0);
}
else if (!strcmp(command, "bye") || !strcmp(command, "quit")) {
//종료 명령어를 입력받았다면
printf("FTP server quitting..\n");
i = 1;
send(sock2, &i, sizeof(int), 0);
exit(0);
}
}
return 0;
}

FTP Client

컴파일 및 실행 방법

1
2
$ gcc -o client client.c
$ ./client 127.0.0.1 9999

client.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <sys/sendfile.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>

#define MAXLINE 511

int tcp_connect(int af, char *servip, unsigned short port) {
struct sockaddr_in servaddr;
int s;
// 소켓 생성
if ((s = socket(af, SOCK_STREAM, 0)) < 0)
return -1;
// 채팅 서버의 소켓주소 구조체 servaddr 초기화
bzero((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = af;
inet_pton(AF_INET, servip, &servaddr.sin_addr);
servaddr.sin_port = htons(port);

// 연결요청
if (connect(s, (struct sockaddr *)&servaddr, sizeof(servaddr))
< 0)
return -1;
return s;
}

int main(int argc, char *argv[])
{
struct sockaddr_in server;
struct stat obj;
int sock;
char bufmsg[MAXLINE];
char buf[100], command[5], filename[MAXLINE], *f;
char temp[20];
int k, size, status;
int filehandle;

if (argc != 3) {
printf("사용법 : %s server_ip port\n", argv[0]);
exit(1);
}

sock = tcp_connect(AF_INET, argv[1], atoi(argv[2]));
if (sock == -1) {
printf("tcp_connect fail");
exit(1);
}

while (1) {
printf("\033[1;33m명령어 : get, put, pwd, ls, cd, quit\n");
printf("\033[1;32mclient> ");
fgets(bufmsg, MAXLINE, stdin); //명령어 입력
fprintf(stderr, "\033[97m"); //글자색을 흰색으로 변경
if (!strcmp(bufmsg, "get\n")) {//get명령어를 입력받았다면
printf("다운로드할 파일 : ");
scanf("%s", filename); //파일 이름 입력
fgets(temp, MAXLINE, stdin); //버퍼에 남은 엔터 제거
strcpy(buf, "get ");
strcat(buf, filename);
send(sock, buf, 100, 0); //명령어 전송
recv(sock, &size, sizeof(int), 0);
if (!size) {//파일이 없다면
printf("파일이 없습니다\n");
continue;
}
f = malloc(size);
recv(sock, f, size, 0);
while (1) {
filehandle = open(filename, O_CREAT | O_EXCL | O_WRONLY, 0666);
if (filehandle == -1) //같은 이름이 있다면 이름 끝에 _1 추가
sprintf(filename + strlen(filename), "_1");
else break;
}
write(filehandle, f, size, 0);
close(filehandle);
printf("다운로드 완료\n");//전송이 잘 되었다면
}
else if (!strcmp(bufmsg, "put\n")) {//put명령어를 입력받았다면
printf("업로드할 파일 : ");
scanf("%s", filename); //파일 이름 입력
fgets(temp, MAXLINE, stdin); //버퍼에 남은 엔터 제거
filehandle = open(filename, O_RDONLY);
if (filehandle == -1) {//파일이 없다면
printf("파일이 없습니다.\n");
continue;
}
strcpy(buf, "put ");
strcat(buf, filename);
send(sock, buf, 100, 0);
stat(filename, &obj);
size = obj.st_size;
send(sock, &size, sizeof(int), 0);//명령어 전송
sendfile(sock, filehandle, NULL, size);//파일 전송
recv(sock, &status, sizeof(int), 0);
if (status)//업로드가 잘 되었다면
printf("업로드 완료\n");
else
printf("업로드 실패\n");
}
else if (!strcmp(bufmsg, "pwd\n")) {//pwd명령어를 입력받았다면
strcpy(buf, "pwd");
send(sock, buf, 100, 0);
recv(sock, buf, 100, 0);
printf("--The path of the Remote Directory--\n%s", buf);
}
else if (!strcmp(bufmsg, "ls\n")) {//ls명령어를 입력받았다면
strcpy(buf, "ls");
send(sock, buf, 100, 0);
recv(sock, &size, sizeof(int), 0);
f = malloc(size);
recv(sock, f, size, 0);
filehandle = creat("temp.txt", O_WRONLY);
write(filehandle, f, size, 0);
close(filehandle);
printf("--The Remote Directory List--\n");
system("cat temp.txt"); //현재 디렉토리의 파일 출력
}
else if (!strcmp(bufmsg, "cd\n")) {//cd명령어를 입력받았다면
strcpy(buf, "cd ");
printf("이동할 경로 이름 : ");
scanf("%s", buf + 3); //위치 입력
fgets(temp, MAXLINE, stdin); //버퍼에 남은 엔터 제거
send(sock, buf, 100, 0); //명령어 전송
recv(sock, &status, sizeof(int), 0);
if (status)
printf("경로 변경 완료\n");
else
printf("경로 변경 실패\n");
}
else if (!strcmp(bufmsg, "quit\n")) {//quit명령어를 입력받았다면
strcpy(buf, "quit");
send(sock, buf, 100, 0);
recv(sock, &status, 100, 0);
if (status) {
printf("서버를 닫는 중..\n");
exit(0);
}
printf("서버 닫기 실패\n");
}
}
}

Linux에서 Socket으로 채팅구현하기

서버를 구동시킨 후 클라이언트를 실행합니다.
클라이언트는 2개 이상 실행이 가능하며 단체 대화방 처럼 사용이 가능합니다.
서버에서 지원하는 명령어는 아래와 같습니다.
help num_user num_chat ip_list

Server

컴파일 및 실행 방법

1
2
$ gcc -o server server.c -lpthread
$ ./server 9999

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <pthread.h>

#define MAXLINE 511
#define MAX_SOCK 1024 // 솔라리스의 경우 64

char *EXIT_STRING = "exit"; // 클라이언트의 종료요청 문자열
char *START_STRING = "Connected to chat_server \n";
// 클라이언트 환영 메시지
int maxfdp1; // 최대 소켓번호 +1
int num_user = 0; // 채팅 참가자 수
int num_chat = 0; // 지금까지 오간 대화의 수
int clisock_list[MAX_SOCK]; // 채팅에 참가자 소켓번호 목록
char ip_list[MAX_SOCK][20]; //접속한 ip목록
int listen_sock; // 서버의 리슨 소켓

// 새로운 채팅 참가자 처리
void addClient(int s, struct sockaddr_in *newcliaddr);
int getmax(); // 최대 소켓 번호 찾기
void removeClient(int s); // 채팅 탈퇴 처리 함수
int tcp_listen(int host, int port, int backlog); // 소켓 생성 및 listen
void errquit(char *mesg) { perror(mesg); exit(1); }

time_t ct;
struct tm tm;

void *thread_function(void *arg) { //명령어를 처리할 스레드
int i;
printf("명령어 목록 : help, num_user, num_chat, ip_list\n");
while (1) {
char bufmsg[MAXLINE + 1];
fprintf(stderr, "\033[1;32m"); //글자색을 녹색으로 변경
printf("server>"); //커서 출력
fgets(bufmsg, MAXLINE, stdin); //명령어 입력
if (!strcmp(bufmsg, "\n")) continue; //엔터 무시
else if (!strcmp(bufmsg, "help\n")) //명령어 처리
printf("help, num_user, num_chat, ip_list\n");
else if (!strcmp(bufmsg, "num_user\n"))//명령어 처리
printf("현재 참가자 수 = %d\n", num_user);
else if (!strcmp(bufmsg, "num_chat\n"))//명령어 처리
printf("지금까지 오간 대화의 수 = %d\n", num_chat);
else if (!strcmp(bufmsg, "ip_list\n")) //명령어 처리
for (i = 0; i < num_user; i++)
printf("%s\n", ip_list[i]);
else //예외 처리
printf("해당 명령어가 없습니다.help를 참조하세요.\n");
}
}

int main(int argc, char *argv[]) {
struct sockaddr_in cliaddr;
char buf[MAXLINE + 1]; //클라이언트에서 받은 메시지
int i, j, nbyte, accp_sock, addrlen = sizeof(struct
sockaddr_in);
fd_set read_fds; //읽기를 감지할 fd_set 구조체
pthread_t a_thread;

if (argc != 2) {
printf("사용법 :%s port\n", argv[0]);
exit(0);
}

// tcp_listen(host, port, backlog) 함수 호출
listen_sock = tcp_listen(INADDR_ANY, atoi(argv[1]), 5);
//스레드 생성
pthread_create(&a_thread, NULL, thread_function, (void *)NULL);
while (1) {
FD_ZERO(&read_fds);
FD_SET(listen_sock, &read_fds);
for (i = 0; i < num_user; i++)
FD_SET(clisock_list[i], &read_fds);

maxfdp1 = getmax() + 1; // maxfdp1 재 계산
if (select(maxfdp1, &read_fds, NULL, NULL, NULL) < 0)
errquit("select fail");

if (FD_ISSET(listen_sock, &read_fds)) {
accp_sock = accept(listen_sock,
(struct sockaddr*)&cliaddr, &addrlen);
if (accp_sock == -1) errquit("accept fail");
addClient(accp_sock, &cliaddr);
send(accp_sock, START_STRING, strlen(START_STRING), 0);
ct = time(NULL); //현재 시간을 받아옴
tm = *localtime(&ct);
write(1, "\033[0G", 4); //커서의 X좌표를 0으로 이동
printf("[%02d:%02d:%02d]", tm.tm_hour, tm.tm_min, tm.tm_sec);
fprintf(stderr, "\033[33m");//글자색을 노란색으로 변경
printf("사용자 1명 추가. 현재 참가자 수 = %d\n", num_user);
fprintf(stderr, "\033[32m");//글자색을 녹색으로 변경
fprintf(stderr, "server>"); //커서 출력
}

// 클라이언트가 보낸 메시지를 모든 클라이언트에게 방송
for (i = 0; i < num_user; i++) {
if (FD_ISSET(clisock_list[i], &read_fds)) {
num_chat++; //총 대화 수 증가
nbyte = recv(clisock_list[i], buf, MAXLINE, 0);
if (nbyte <= 0) {
removeClient(i); // 클라이언트의 종료
continue;
}
buf[nbyte] = 0;
// 종료문자 처리
if (strstr(buf, EXIT_STRING) != NULL) {
removeClient(i); // 클라이언트의 종료
continue;
}
// 모든 채팅 참가자에게 메시지 방송
for (j = 0; j < num_user; j++)
send(clisock_list[j], buf, nbyte, 0);
printf("\033[0G"); //커서의 X좌표를 0으로 이동
fprintf(stderr, "\033[97m");//글자색을 흰색으로 변경
printf("%s", buf); //메시지 출력
fprintf(stderr, "\033[32m");//글자색을 녹색으로 변경
fprintf(stderr, "server>"); //커서 출력
}
}

} // end of while

return 0;
}

// 새로운 채팅 참가자 처리
void addClient(int s, struct sockaddr_in *newcliaddr) {
char buf[20];
inet_ntop(AF_INET, &newcliaddr->sin_addr, buf, sizeof(buf));
write(1, "\033[0G", 4); //커서의 X좌표를 0으로 이동
fprintf(stderr, "\033[33m"); //글자색을 노란색으로 변경
printf("new client: %s\n", buf);//ip출력
// 채팅 클라이언트 목록에 추가
clisock_list[num_user] = s;
strcpy(ip_list[num_user], buf);
num_user++; //유저 수 증가
}

// 채팅 탈퇴 처리
void removeClient(int s) {
close(clisock_list[s]);
if (s != num_user - 1) { //저장된 리스트 재배열
clisock_list[s] = clisock_list[num_user - 1];
strcpy(ip_list[s], ip_list[num_user - 1]);
}
num_user--; //유저 수 감소
ct = time(NULL); //현재 시간을 받아옴
tm = *localtime(&ct);
write(1, "\033[0G", 4); //커서의 X좌표를 0으로 이동
fprintf(stderr, "\033[33m");//글자색을 노란색으로 변경
printf("[%02d:%02d:%02d]", tm.tm_hour, tm.tm_min, tm.tm_sec);
printf("채팅 참가자 1명 탈퇴. 현재 참가자 수 = %d\n", num_user);
fprintf(stderr, "\033[32m");//글자색을 녹색으로 변경
fprintf(stderr, "server>"); //커서 출력
}

// 최대 소켓번호 찾기
int getmax() {
// Minimum 소켓번호는 가정 먼저 생성된 listen_sock
int max = listen_sock;
int i;
for (i = 0; i < num_user; i++)
if (clisock_list[i] > max)
max = clisock_list[i];
return max;
}

// listen 소켓 생성 및 listen
int tcp_listen(int host, int port, int backlog) {
int sd;
struct sockaddr_in servaddr;

sd = socket(AF_INET, SOCK_STREAM, 0);
if (sd == -1) {
perror("socket fail");
exit(1);
}
// servaddr 구조체의 내용 세팅
bzero((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(host);
servaddr.sin_port = htons(port);
if (bind(sd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) {
perror("bind fail"); exit(1);
}
// 클라이언트로부터 연결요청을 기다림
listen(sd, backlog);
return sd;
}

Client

컴파일 및 실행 방법

1
2
$ gcc -o client client.c
$ ./client 127.0.0.1 9999 nick

소스코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <time.h>

#define MAXLINE 1000
#define NAME_LEN 20

char *EXIT_STRING = "exit";
// 소켓 생성 및 서버 연결, 생성된 소켓리턴
int tcp_connect(int af, char *servip, unsigned short port);
void errquit(char *mesg) { perror(mesg); exit(1); }

int main(int argc, char *argv[]) {
char bufname[NAME_LEN]; // 이름
char bufmsg[MAXLINE]; // 메시지부분
char bufall[MAXLINE + NAME_LEN];
int maxfdp1; // 최대 소켓 디스크립터
int s; // 소켓
int namelen; // 이름의 길이
fd_set read_fds;
time_t ct;
struct tm tm;

if (argc != 4) {
printf("사용법 : %s sever_ip port name \n", argv[0]);
exit(0);
}

s = tcp_connect(AF_INET, argv[1], atoi(argv[2]));
if (s == -1)
errquit("tcp_connect fail");

puts("서버에 접속되었습니다.");
maxfdp1 = s + 1;
FD_ZERO(&read_fds);

while (1) {
FD_SET(0, &read_fds);
FD_SET(s, &read_fds);
if (select(maxfdp1, &read_fds, NULL, NULL, NULL) < 0)
errquit("select fail");
if (FD_ISSET(s, &read_fds)) {
int nbyte;
if ((nbyte = recv(s, bufmsg, MAXLINE, 0)) > 0) {
bufmsg[nbyte] = 0;
write(1, "\033[0G", 4); //커서의 X좌표를 0으로 이동
printf("%s", bufmsg); //메시지 출력
fprintf(stderr, "\033[1;32m"); //글자색을 녹색으로 변경
fprintf(stderr, "%s>", argv[3]);//내 닉네임 출력

}
}
if (FD_ISSET(0, &read_fds)) {
if (fgets(bufmsg, MAXLINE, stdin)) {
fprintf(stderr, "\033[1;33m"); //글자색을 노란색으로 변경
fprintf(stderr, "\033[1A"); //Y좌표를 현재 위치로부터 -1만큼 이동
ct = time(NULL); //현재 시간을 받아옴
tm = *localtime(&ct);
sprintf(bufall, "[%02d:%02d:%02d]%s>%s", tm.tm_hour, tm.tm_min, tm.tm_sec, argv[3], bufmsg);//메시지에 현재시간 추가
if (send(s, bufall, strlen(bufall), 0) < 0)
puts("Error : Write error on socket.");
if (strstr(bufmsg, EXIT_STRING) != NULL) {
puts("Good bye.");
close(s);
exit(0);
}
}
}
} // end of while
}

int tcp_connect(int af, char *servip, unsigned short port) {
struct sockaddr_in servaddr;
int s;
// 소켓 생성
if ((s = socket(af, SOCK_STREAM, 0)) < 0)
return -1;
// 채팅 서버의 소켓주소 구조체 servaddr 초기화
bzero((char *)&servaddr, sizeof(servaddr));
servaddr.sin_family = af;
inet_pton(AF_INET, servip, &servaddr.sin_addr);
servaddr.sin_port = htons(port);

// 연결요청
if (connect(s, (struct sockaddr *)&servaddr, sizeof(servaddr))
< 0)
return -1;
return s;
}

Linux에 색상 출력하기

Terminal에 미리보기

형식 지정

1
2
3
4
5
6
7
> for code in {30..37}; do \
echo -en "\033[${code}m"'\\033['"$code"'m'"\033[0m"; \
echo -en " \033[$code;1m"'\\033['"$code"';1m'"\033[0m"; \
echo -en " \033[$code;3m"'\\033['"$code"';3m'"\033[0m"; \
echo -en " \033[$code;4m"'\\033['"$code"';4m'"\033[0m"; \
echo -e " \033[$((code+60))m"'\\033['"$((code+60))"'m'"\033[0m"; \
done
형식 종류
Bold 1
Underscore 4
Background 3

255 색상 출력

1
2
3
> for code in {0..255}
do echo -e "\033[38;5;${code}m"'\\033[38;5;'"$code"m"\033[0m"
done
색상 종류 범위
Basic 8 colors 30~37
Basic “high contrast” colors 90~97
xerm-256 colors 0~255

사용법

이 코드를 사용하기 전에 위에 있는 코드를 Terminal에 실행 후 색상을 확인하고 사용 바람!!

bash

1
$ echo -e "\033[38;5;[0~255]m[contents]\033[0m"

C(gcc)

[0~255] 중에서 하나 골라서 입력
[contents] 부분에 내용 입력

1
2
3
4
5
6
7
8
9
10
11
12
13
//방법1
fprintf(stderr, "\033[38;5;[0~255]m[contents]\033[0m");

//방법2
printf("\033[38;5;[0~255]m[contents]\033[0m");

//방법3
printf("\033[38;5;[0~255]m"); //글자색 변경
printf("[contents]"); //내용 입력
printf("\033[0m"); //원래 색(흰색)으로 변경

//방법4 - 색상&밑줄
printf("\033[33;4m[contents]\033[0m");

<참조> http://jafrog.com/2013/11/23/colors-in-terminal.html