Microsoft MVP성태의 닷넷 이야기
.NET Framework: 501. FtpWebRequest 타입을 이용해 FTP 파일 업로드 [링크 복사], [링크+제목 복사],
조회: 29720
글쓴 사람
정성태 (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)
12002정성태8/12/201911235.NET Framework: 853. Excel Sheet를 WinForm에서 사용하는 방법 - 두 번째 이야기 [5]
12001정성태8/10/201915690.NET Framework: 852. WPF/WinForm에서 UWP의 기능을 이용해 Bluetooth 기기와 Pairing하는 방법 [1]
12000정성태8/9/201914563.NET Framework: 851. WinForm/WPF에서 Console 창을 띄워 출력하는 방법파일 다운로드1
11999정성태8/1/201910386오류 유형: 563. C# - .NET Core 2.0 이하의 Unix Domain Socket 사용 시 System.IndexOutOfRangeException 오류
11998정성태7/30/201911511오류 유형: 562. .NET Remoting에서 서비스 호출 시 SYN_SENT로 남는 현상파일 다운로드1
11997정성태7/30/201913147.NET Framework: 850. C# - Excel(을 비롯해 Office 제품군) COM 객체를 제어 후 Excel.exe 프로세스가 남아 있는 문제 [2]파일 다운로드1
11996정성태7/25/201915536.NET Framework: 849. C# - Socket의 TIME_WAIT 상태를 없애는 방법파일 다운로드1
11995정성태7/23/201918601.NET Framework: 848. C# - smtp.daum.net 서비스(Implicit SSL)를 이용해 메일 보내는 방법 [2]
11994정성태7/22/201914114개발 환경 구성: 454. Azure 가상 머신(VM)에서 SMTP 메일 전송하는 방법파일 다운로드1
11993정성태7/22/20199657오류 유형: 561. Dism.exe 수행 시 "Error: 2 - The system cannot find the file specified." 오류 발생
11992정성태7/22/201911346오류 유형: 560. 서비스 관리자 실행 시 "Windows was unable to open service control manager database on [...]. Error 5: Access is denied." 오류 발생
11991정성태7/18/20198993디버깅 기술: 128. windbg - x64 환경에서 닷넷 예외가 발생한 경우 인자를 확인할 수 없었던 사례
11990정성태7/18/201911109오류 유형: 559. Settings / Update & Security 화면 진입 시 프로그램 종료
11989정성태7/18/20199982Windows: 162. Windows Server 2019 빌드 17763부터 Alt + F4 입력시 곧바로 로그아웃하는 현상
11988정성태7/18/201911492개발 환경 구성: 453. 마이크로소프트가 지정한 모든 Root 인증서를 설치하는 방법
11987정성태7/17/201916428오류 유형: 558. 윈도우 - KMODE_EXCEPTION_NOT_HANDLED 블루스크린(BSOD) 문제 [1]
11986정성태7/17/20199338오류 유형: 557. 드라이브 문자를 할당하지 않은 파티션을 탐색기에서 드라이브 문자와 함께 보여주는 문제
11985정성태7/17/20199374개발 환경 구성: 452. msbuild - csproj에 환경 변수 조건 사용 [1]
11984정성태7/9/201917585개발 환경 구성: 451. Microsoft Edge (Chromium)을 대상으로 한 Selenium WebDriver 사용법 [1]
11983정성태7/8/20198710오류 유형: 556. nodemon - 'mocha' is not recognized as an internal or external command, operable program or batch file.
11982정성태7/8/20198748오류 유형: 555. Visual Studio 빌드 오류 - result: unexpected exception occured (-1002 - 0xfffffc16)
11981정성태7/7/201910835Math: 64. C# - 3층 구조의 신경망(분류)파일 다운로드1
11980정성태7/7/201921252개발 환경 구성: 450. Visual Studio Code의 Java 확장을 이용한 간단한 프로젝트 구축파일 다운로드1
11979정성태7/7/201910815개발 환경 구성: 449. TFS에서 gitlab/github등의 git 서버로 마이그레이션하는 방법
11978정성태7/6/201910182Windows: 161. 계정 정보가 동일하지 않은 PC 간의 인증을 수행하는 방법 [1]
11977정성태7/6/201914717오류 유형: 554. git push - error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413 Request Entity Too Large
... 61  62  63  64  [65]  66  67  68  69  70  71  72  73  74  75  ...