Microsoft MVP성태의 닷넷 이야기
.NET Framework: 501. FtpWebRequest 타입을 이용해 FTP 파일 업로드 [링크 복사], [링크+제목 복사],
조회: 30119
글쓴 사람
정성태 (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
정성태

... 46  47  48  49  50  51  [52]  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12351정성태10/2/202010917오류 유형: 659. Nox 실행이 안 되는 경우 - Unable to bind to the underlying transport for ...
12350정성태9/25/202014408Windows: 175. 윈도우 환경에서 클라이언트 소켓의 최대 접속 수 [2]파일 다운로드1
12349정성태9/25/20209254Linux: 32. Ubuntu 20.04 - docker를 위한 tcp 바인딩 추가
12348정성태9/25/20209999오류 유형: 658. 리눅스 docker - Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock
12347정성태9/25/202024231Windows: 174. WSL 2의 네트워크 통신 방법 [4]
12346정성태9/25/20209240오류 유형: 657. IIS - http://localhost 방문 시 Service Unavailable 503 오류 발생
12345정성태9/25/20208891오류 유형: 656. iisreset 실행 시 "Restart attempt failed." 오류가 발생하지만 웹 서비스는 정상적인 경우파일 다운로드1
12344정성태9/25/202010069Windows: 173. 서비스 관리자에 "IIS Admin Service"가 등록되어 있지 않다면?
12343정성태9/24/202019865.NET Framework: 945. C# - 닷넷 응용 프로그램에서 메모리 누수가 발생할 수 있는 패턴 [5]
12342정성태9/24/202011074디버깅 기술: 171. windbg - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법
12341정성태9/23/202010134.NET Framework: 944. C# - 인스턴스가 살아 있어 메모리 누수가 발생하고 있는지 확인하는 방법파일 다운로드1
12340정성태9/23/20209878.NET Framework: 943. WPF - WindowsFormsHost를 담은 윈도우 생성 시 메모리 누수
12339정성태9/21/20209940오류 유형: 655. 코어 모드의 윈도우는 GUI 모드의 윈도우로 교체가 안 됩니다.
12338정성태9/21/20209438오류 유형: 654. 우분투 설치 시 "CHS: Error 2001 reading sector ..." 오류 발생
12337정성태9/21/202010796오류 유형: 653. Windows - Time zone 설정을 바꿔도 반영이 안 되는 경우
12336정성태9/21/202013273.NET Framework: 942. C# - WOL(Wake On Lan) 구현
12335정성태9/21/202022667Linux: 31. 우분투 20.04 초기 설정 - 고정 IP 및 SSH 설치
12334정성태9/21/20208061오류 유형: 652. windbg - !py 확장 명령어 실행 시 "failed to find python interpreter"
12333정성태9/20/20208472.NET Framework: 941. C# - 전위/후위 증감 연산자에 대한 오버로딩 구현 (2)
12332정성태9/18/202010594.NET Framework: 940. C# - Windows Forms ListView와 DataGridView의 예제 코드파일 다운로드1
12331정성태9/18/20209735오류 유형: 651. repadmin /syncall - 0x80090322 The target principal name is incorrect.
12330정성태9/18/202010792.NET Framework: 939. C# - 전위/후위 증감 연산자에 대한 오버로딩 구현 [2]파일 다운로드1
12329정성태9/16/202012697오류 유형: 650. ASUS 메인보드 관련 소프트웨어 설치 후 ArmouryCrate.UserSessionHelper.exe 프로세스 무한 종료 현상
12328정성태9/16/202012910VS.NET IDE: 150. TFS의 이력에서 "Get This Version"과 같은 기능을 Git으로 처리한다면?
12327정성태9/12/202010496.NET Framework: 938. C# - ICS(Internet Connection Sharing) 제어파일 다운로드1
12326정성태9/12/20209969개발 환경 구성: 516. Azure VM의 Network Adapter를 실수로 비활성화한 경우
... 46  47  48  49  50  51  [52]  53  54  55  56  57  58  59  60  ...