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에 C로 FTP Server와 Client 작성하기

http://crazythink.github.io/2018/06/03/ftp/

Author

Daeyoung Kim

Posted on

2018-06-03

Updated on

2018-06-03

Licensed under

댓글