Microsoft MVP성태의 닷넷 이야기
.NET Framework: 501. FtpWebRequest 타입을 이용해 FTP 파일 업로드 [링크 복사], [링크+제목 복사],
조회: 29728
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
(연관된 글이 1개 있습니다.)

FtpWebRequest 타입을 이용해 FTP 파일 업로드

사실 아래의 글에서 잘 설명하고 있지만,

How to: Upload Files with FTP
; https://docs.microsoft.com/en-us/dotnet/framework/network-programming/how-to-upload-files-with-ftp

좀 더 부가설명을 해보겠습니다.

우선, FtpWebRequest 타입은 기본값으로 Passive 모드의 연결을 합니다. 그래서 Active 모드만 가능하도록 설정된 FTP 서버로 접속했을 때는 다음과 같은 오류가 발생합니다.

// 192.168.0.22번 서버로 연결 시도를 하는 상황

System.Net.WebException: The remote server returned an error: 227 Entering Passive Mode (192,168,0,22,200,90).
. ---> System.Net.Sockets.SocketException: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond 192.168.0.22:51290
   at System.Net.Sockets.Socket.DoConnect(EndPoint endPointSnapshot, SocketAddress socketAddress)
   at System.Net.Sockets.Socket.Connect(EndPoint remoteEP)
   at System.Net.FtpControlStream.QueueOrCreateDataConection(PipelineEntry entry, ResponseDescription response, Boolean timeout, Stream& stream, Boolean& isSocketReady)
   at System.Net.FtpControlStream.PipelineCallback(PipelineEntry entry, ResponseDescription response, Boolean timeout, Stream& stream)
   at System.Net.CommandStream.PostReadCommandProcessing(Stream& stream)
   at System.Net.CommandStream.PostSendCommandProcessing(Stream& stream)
   at System.Net.CommandStream.ContinueCommandPipeline()
   at System.Net.FtpWebRequest.TimedSubmitRequestHelper(Boolean async)
   at System.Net.FtpWebRequest.SubmitRequest(Boolean async)
   --- End of inner exception stack trace ---
   at System.Net.FtpWebRequest.CheckError()
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.IO.Stream.Close()
   at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.GetRequestStream()
   at FtpUpload.Program.Main(String[] args) in c:\...\Program.cs:line 40

이런 경우, 명시적으로 UsePassive 속성 값을 false로 설정해 주시면 문제가 해결됩니다.

FtpWebRequest request = WebRequest.Create(uploadPath) as FtpWebRequest;

Console.WriteLine("Passive: " + request.UsePassive); // 기본값: true

request.UsePassive = false;




접속하는 계정 권한으로 서버에 쓰기 권한이 없을 때는 업로드 시에 이런 오류가 발생합니다.

System.Net.WebException: The remote server returned an error: (550) File unavailable (e.g., file not found, no access).
   at System.Net.FtpWebRequest.CheckError()
   at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
   at System.IO.Stream.Close()
   at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
   at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
   at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
   at System.Net.FtpWebRequest.GetRequestStream()
   at FtpUpload.Program.Main(String[] args) in c:\...\Program.cs:line 40

당연히 서버에 해당 계정으로 쓰기 권한을 주어야 문제가 해결됩니다.




아래와 같이 희한한 오류가 발생하는 경우가 있습니다.

System.Net.WebException was unhandled
  _HResult=-2146233079
  _message=The remote server returned an error: (553) File name not allowed.
  HResult=-2146233079
  IsTransient=false
  Message=The remote server returned an error: (553) File name not allowed.
  Source=System
  StackTrace:
       at System.Net.FtpWebRequest.CheckError()
       at System.Net.FtpWebRequest.SyncRequestCallback(Object obj)
       at System.IO.Stream.Close()
       at System.Net.ConnectionPool.Destroy(PooledStream pooledStream)
       at System.Net.ConnectionPool.PutConnection(PooledStream pooledStream, Object owningObject, Int32 creationTimeout, Boolean canReuse)
       at System.Net.FtpWebRequest.FinishRequestStage(RequestStage stage)
       at System.Net.FtpWebRequest.GetRequestStream()
       at FtpUpload.Program.Main(String[] args) in c:\...\Program.cs:line 40
  InnerException: 

검색해 보면 다음의 글이 나오는데요.

Can't connect to FTP: (553) File name not allowed
; http://stackoverflow.com/questions/9418404/cant-connect-to-ftp-553-file-name-not-allowed

원인은 로그인 계정과 연관된 기본 디렉터리(default directory) 경로까지 포함한 경우에 이런 현상이 발생합니다. 예를 들어, FileZilla와 같은 프로그램으로 FTP 서버 접속 시에 다음과 같은 상태 정보가 나타나는 데,

Status: Resolving address of www.jennifersoft.co.kr
Status: Connecting to 192.168.0.22:21...
Status: Connection established, waiting for welcome message...
Status: Server does not support non-ASCII characters.
Status: Connected
Status: Retrieving directory listing...
Status: Directory listing of "/home/mydir" successful
Status: Retrieving directory listing of "/home/mydir/appupload"...
Status: Calculating timezone offset of server...
Status: Timezone offsets: Server: 0 seconds. Local: 32400 seconds. Difference: 32400 seconds.
Status: Directory listing of "/home/mydir/appupload" successful
...[이하 생략]...

보는 바와 같이 로그인과 동시에 기본 디렉터리("/home/mydir")로 이동하고 있습니다. 바로 이 기본 디렉터리 경로를 FTP에 전달해 주면 안됩니다. 예를 들어, 경로가 "/home/mydir/appupload"라고 가정했을 때,

string uploadPath = "ftp://192.168.0.22/home/mydir/appupload/test.txt";
FtpWebRequest request = WebRequest.Create(uploadPath) as FtpWebRequest;

라고 전달하면 "(553) File name not allowed." 오류가 발생합니다. 따라서 기본 디렉터리를 빼고 다음과 같이 지정해야만 정상적으로 업로드가 됩니다.

string uploadPath = "ftp://192.168.0.22/appupload/test.txt";
FtpWebRequest request = WebRequest.Create(uploadPath) as FtpWebRequest;




마지막으로, 제가 테스트한 FTP 업로드 예제 코드입니다. (첨부 파일은 이 코드를 포함합니다.)

using System;
using System.IO;
using System.Net;

class Program
{
    static int Main(string[] args)
    {
        try
        {
            if (args.Length < 5)
            {
                Console.WriteLine("FtpUpload.exe [ftpserver] [userid] [userpass] [serverpath] [filename]");
                return 1;
            }

            string serverAddress = args[0];
            string userId = args[1];
            string userPass = args[2];
            string dir = args[3];
            string filePath = args[4];
            string fileName = Path.GetFileName(filePath);

            string uploadPath = "ftp://" + serverAddress + dir + fileName;

            FtpWebRequest request = WebRequest.Create(uploadPath) as FtpWebRequest;

            Console.WriteLine("Passive: " + request.UsePassive);

            request.Method = WebRequestMethods.Ftp.UploadFile;
            request.Credentials = new NetworkCredential(userId, userPass);

            byte[] fileContents = File.ReadAllBytes(filePath);
            Stream requestStream = request.GetRequestStream();
            request.ContentLength = fileContents.Length;
            requestStream.Write(fileContents, 0, fileContents.Length);
            requestStream.Close();

            FtpWebResponse response = request.GetResponse() as FtpWebResponse;

            Stream responseStream = response.GetResponseStream();
            StreamReader reader = new StreamReader(responseStream);
            Console.WriteLine(reader.ReadToEnd());

            Console.WriteLine("Complete, status {0}, length {1}", response.StatusDescription, response.ContentLength);

            response.Close();
        }
        catch (Exception e)
        {
            Console.WriteLine(e.ToString());
            return 1;
        }

        return 0;
    }
}




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2018-01-24 09시15분
[정윤문경아빠] 잇힝~
감사합니다.
덕분에 533 해결했어요
[guest]
2018-10-10 01시38분
[YH] 안녕하세요 FTP 파일 전송 로직을 처음 구현하여 기초가 아직 많이 없어 질문 합니다...
먼저 FTP 파일 전송을 하기 위해서는 서버에 설치되어있어야 하는 프로그램이 있나요? 알 FTP 프로그램과 같은..
두번째로 저 위 소스에 나와있는 ID와 PWD는 어떤거에 해당되는 것인가요? 접속할 서버의 계정 ID/PWD 인가요??
[guest]
2018-10-10 02시39분
서버에는 FTP 서비스를 하는 프로그램이 설치되어 있으면 됩니다. 윈도우의 경우 다음의 글을 참고하세요.

Set Up an FTP Server on Windows
; https://www.serv-u.com/features/file-transfer-protocol-server-windows/server-setup

계정은 FTP 서비스가 실행되고 있는 서버에 등록된 사용자 계정입니다.
정성태
2022-04-05 10시02분
아래의 글은 IFtpHomeDirectoryProvider, FTP Extensibility에 대한 예제 코드를 담고 있습니다.

How to Use Managed Code (C#) to Create an FTP Home Directory Provider for the Days of the Week
; https://blogs.iis.net/robert_mcmurray/how-to-use-managed-code-c-to-create-an-ftp-home-directory-provider-for-the-days-of-the-week

How to Use Managed Code (C#) to Create a Simple FTP Home Directory Provider
; https://docs.microsoft.com/en-us/iis/develop/developing-for-ftp/how-to-use-managed-code-c-to-create-a-simple-ftp-home-directory-provider
정성태

... 61  [62]  63  64  65  66  67  68  69  70  71  72  73  74  75  ...
NoWriterDateCnt.TitleFile(s)
12078정성태12/13/201913239Linux: 26. .NET Core 응용 프로그램을 위한 메모리 덤프 방법 [3]
12077정성태12/13/201912753Linux: 25. 자주 실행할 명령어 또는 초기 환경을 "~/.bashrc" 파일에 등록
12076정성태12/12/201910960디버깅 기술: 142. Linux - lldb 환경에서 sos 확장 명령어를 이용한 닷넷 프로세스 디버깅 - 배포 방법에 따른 차이
12075정성태12/11/201911758디버깅 기술: 141. Linux - lldb 환경에서 sos 확장 명령어를 이용한 닷넷 프로세스 디버깅
12074정성태12/10/201911416디버깅 기술: 140. windbg/Visual Studio - 값이 변경된 경우를 위한 정지점(BP) 설정(Data Breakpoint)
12073정성태12/10/201913244Linux: 24. Linux/C# - 실행 파일이 아닌 스크립트 형식의 명령어를 Process.Start로 실행하는 방법
12072정성태12/9/201910600오류 유형: 583. iisreset 수행 시 "No such interface supported" 오류
12071정성태12/9/201912969오류 유형: 582. 리눅스 디스크 공간 부족 및 safemode 부팅 방법
12070정성태12/9/201915089오류 유형: 581. resize2fs: Bad magic number in super-block while trying to open /dev/.../root
12069정성태12/2/201911493디버깅 기술: 139. windbg - x64 덤프 분석 시 메서드의 인자 또는 로컬 변수의 값을 확인하는 방법
12068정성태11/28/201914773디버깅 기술: 138. windbg와 Win32 API로 알아보는 Windows Heap 정보 분석 [3]파일 다운로드2
12067정성태11/27/201911470디버깅 기술: 137. 실제 사례를 통해 Debug Diagnostics 도구가 생성한 닷넷 웹 응용 프로그램의 성능 장애 보고서 설명 [1]파일 다운로드1
12066정성태11/27/201911359디버깅 기술: 136. windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석 - OracleCommand.ExecuteReader에서 OpsSql.Prepare2 PInvoke 호출 분석
12065정성태11/25/201910255디버깅 기술: 135. windbg - C# PInvoke 호출 시 마샬링을 담당하는 함수 분석파일 다운로드1
12064정성태11/25/201912400오류 유형: 580. HTTP Error 500.0/500.33 - ANCM In-Process Handler Load Failure
12063정성태11/21/201911449디버깅 기술: 134. windbg - RtlReportCriticalFailure로부터 parameters 정보 찾는 방법
12062정성태11/21/201911592디버깅 기술: 133. windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례 - 두 번째 이야기
12061정성태11/20/201911688Windows: 167. CoTaskMemAlloc/CoTaskMemFree과 윈도우 Heap의 관계
12060정성태11/20/201912069디버깅 기술: 132. windbg/Visual Studio - HeapFree x64의 동작 분석
12059정성태11/20/201911624디버깅 기술: 131. windbg/Visual Studio - HeapFree x86의 동작 분석
12058정성태11/19/201912504디버깅 기술: 130. windbg - CoTaskMemFree/FreeCoTaskMem에서 발생한 덤프 분석 사례
12057정성태11/18/20199588오류 유형: 579. Visual Studio - Memory 창에서 유효한 주소 영역임에도 "Unable to evaluate the expression." 오류 출력
12056정성태11/18/201913405개발 환경 구성: 464. "Microsoft Visual Studio Installer Projects" 프로젝트로 EXE 서명 및 MSI 파일 서명 방법파일 다운로드1
12055정성태11/17/20199199개발 환경 구성: 463. Visual Studio의 Ctrl + Alt + M, 1 (Memory 1) 등의 단축키가 동작하지 않는 경우
12054정성태11/15/201910521.NET Framework: 869. C# - 일부러 GC Heap을 깨뜨려 GC 수행 시 비정상 종료시키는 예제
12053정성태11/15/201912170Windows: 166. 윈도우 10 - 명령행 창(cmd.exe) 속성에 (DotumChe, GulimChe, GungsuhChe 등의) 한글 폰트가 없는 경우
... 61  [62]  63  64  65  66  67  68  69  70  71  72  73  74  75  ...