일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 진수변환기
- C
- 자료구조
- 콘솔 키보드 이벤트
- InfluxDB
- Linked List
- 딕셔너리
- UI
- ws2_32.lib
- 문자열파싱
- 문자열 다루기
- Android
- FTP
- InfluxDBClient
- 메모리반환
- dictionary
- 문자열다루기
- Mat 변수
- 연결리스트
- flutter
- 파일입출력
- socket
- 소켓프로그래밍
- 코틀린
- vs code
- dart
- Kotlin
- vscode
- background service
- foreground service
- Today
- Total
무슨 일로 C 하셨습니까?
[C] 소켓 프로그래밍::FTP - 디렉토리 본문
카카오톡으로 사진을 넘겨주듯 보내는 쪽에서 선택해서 파일을 넘겨주면 좋겠지만
받는 쪽에서 원하는 파일을 선택하게 만들고싶다.
그것도 한정된 몇개의 파일이 상대방 컴퓨터 내의 모든 파일을 대상으로
그것을 가능하도록 만들어보겠다.
#include<stdio.h>
#include<io.h>
void f() {
struct _finddata_t target;
intptr_t handle;
int result;
handle = _findfirst("*.*", &target);
if (handle == -1) return;
while (1)
{
printf("%s[%d]\n", target.name,target.size);
result = _findnext(handle, &target);
if (result == -1) break;
}
_findclose(handle);
return;
}
여러 오픈 소스들을 토대로 만든 코드로
실행하면 다음과 같이 현재 위치 상 폴더 디렉토리를 볼 수 있다.
(기본 경로는 프로젝트 내 실행파일(.exe)이 있는 폴더이다.)
파일 이름 뿐만 아니라 확장자, 파일 크기 까지 알 수 있고 크기로 마루어 보아 해당 파일이 폴더인지 파일인지 구분할 수 있을 것으로 보인다.
이렇게 알아낸 목록을 상대방에게 보여주면 원하는 파일을 선택할 수 있을 것이다.
먼저 읽어온 디렉토리에 대한 정보를 담을 수 있는 자료형을 정의하자
typedef struct _filedata {
int idx;
char* name;
int size;
struct _filedata* link;
}filedata;
추후에 어떻게 추가될지는 모르겠지만 일단은 파일의 순번, 이름, 크기를 담도록 했다.
filedata* GetDirectory(char* _path) {
struct _finddata_t target;
intptr_t handle;
char* file_ = StringAdd1(_path, "*.*");
handle = _findfirst(file_, &target);
if (handle == -1)
{
printf("empty\n");
return;
}
int idx = 0;
filedata* hptr = NULL;
filedata* node, * ptr;
while (1)
{
node = (filedata*)malloc(sizeof(filedata));
node->idx = idx++;
node->size = target.size;
node->name = StringAdd1(target.name, "");
node->link = NULL;
if (hptr == NULL) {
hptr = node;
ptr = node;
}
else {
ptr->link = node;
ptr = node;
}
if (_findnext(handle, &target) == -1) break;
}
_findclose(handle);
free(file_);
return hptr;
}
읽어온 파일을 자료형에 맞게 저장하는 함수이다.
( 각각 _자료형 : 매개변수, 자료형_ : 동적할당을 한 변수로 메모리 반환을 해야하는 변수 를 의미 )
데이터의 index는 그저 컴퓨터가 파일을 읽은 순서대로 부여한다.
void Sender_Directory(SOCKET _sock, filedata* _files){
filedata* ptr = _files;
char msg[100];
while (1)
{
if (ptr == NULL) {
send(_sock, "fin", 3, 0);
recv(_sock, msg, 100, 0);
msg[4] = 0;
printf("last msg : %s\n", msg);
break;
}
sprintf(msg, "%d,%s,%d\n", ptr->index, ptr->name, ptr->size);
if (send(_sock, msg, StringLength(msg), 0) == -1) {
puts("send err");
break;
}
printf("send data is : %s\n", msg);
ptr = ptr->link;
}
return;
}
읽어온 디렉토리를 전달하는 함수이다.
앞서 읽어서 저장한 파일 목록을 차례대로 연결된 소켓에 전송하면 된다.
- 전송 포맷은 "인덱스, 파일명, 파일크기"으로 csv 포맷으로 보내도록 하겠다.
void Receiver_Directory(SOCKET sock) {
char msg[100];
int msgsz;
while (1) {
msgsz = recv(sock, msg, 100, 0);
msg[msgsz] = 0;
char** files_ = StringParser(msg, ",");
printf("recv is : %s,%s,%s\n", files_[0], files_[1], files_[2]);
matfree(files_);
}
}
수신 쪽은 더 간단하다. 목록을 받아내기만 하면 된다.
- 송수신 포맷은 당연히 csv포맷을 사용할 것이기 때문에 데이터를 전처리하는 로직으로 구현하진 않아도 되겠다.
간단하게 동작시켜 보자
// 송신자(서버) 몸체
void Sender() {
SOCKET sock = Sender_Connector();
char msg[100];
char path[] = "C:\\Users\\OJJJ\\Desktop\\";
filedata* files_ = GetDirectory(path);
Sender_Directory(sock, files_);
int len = recv(sock, msg, 100, 0);
msg[len] = 0;
printf("msg rcv : %s\n", msg);
int index;
sscanf(msg, "%d", &index);
printf("file searching : %d\n", index);
filedata* ptr = files_;
for (int i = 1; i <= index; i++) {
ptr = ptr->link;
}
printf(".... is %s", ptr->name);
Sender_Data(sock, path, ptr->name);
}
파일을 주는 쪽이다. 상대방에게 디렉토리를 보낸 후 요청 받은 파일을 전송하도록 한다.
// 수신자(클라이언트) 몸체
void Receiver() {
SOCKET sock = Receiver_Connector();
char msg[100];
char path[] = "C:\\Users\\OJJJ\\Desktop\\";
char filename[] = "copy.jpg";
Receiver_Directory(sock);
int num;
printf("select >> ");
scanf("%d", &num);
sprintf(msg, "%d\n", num);
send(sock, msg, StringLength(msg), 0);
Receiver_Data(sock, path, filename);
}
파일을 받는 쪽이다. 받은 파일 목록을 보고 해당 파일을 선택해서 상대방에게 요청하도록 한다.
받은 디렉토리에서 lena.jpg를 요청해서 다운 받는데 성공했다.
송/수신 프로세스 속도에 따라서 약간의 문제가 발생한다.
송신 측이 늦는 건 상관이 없는데 수신 측에 딜레이가 발생하면 송신 패킷이 쌓이는 문제를 야기할 수 있다.
위 실행결과를 보면 11, 14번 파일이 정상적으로 수신되지 않은 것을 볼 수 있다. 이러한 문제가 발생하지 않도록 해결해야한다.
------- 송신부
while (1) {
if (send(sock_, msg, StringLength(msg), 0) == -1) break;
len = recv(sock_, ans, PACKSZ, 0);
if (len == -1) break;
ans[len] = 0;
if (StringCompare(ans, "go") == COMPARE_SAME) break;
}
-------- 수신부
msgsz = send(sock_, "go", 2, 0);
그냥 단순하게 수신부에서 정상적으로 수신했을때만 송신부가 다음 파일을 송신하게 만들면 되겠다.
또한 상위, 하위 폴더로의 경로 이동이 가능해야한다.
'C - 이걸 굳이? > FTP' 카테고리의 다른 글
[C] 소켓 프로그래밍::FTP - UI(2) (0) | 2021.04.25 |
---|---|
[C] 소켓 프로그래밍::FTP - UI(1) (0) | 2021.03.31 |
[C] 소켓 프로그래밍::FTP - 파일 전송 (1) | 2020.12.10 |
[C] 소켓 프로그래밍::FTP - 연결 (0) | 2020.12.04 |
[C] 소켓 프로그래밍::FTP (0) | 2020.12.03 |