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

(시리즈 글이 2개 있습니다.)
.NET Framework: 501. FtpWebRequest 타입을 이용해 FTP 파일 업로드
; https://www.sysnet.pe.kr/2/0/2873

.NET Framework: 679. C# - 개인 키 보안의 SFTP를 이용한 파일 업로드
; https://www.sysnet.pe.kr/2/0/11285




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

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

How to: Upload Files with FTP
; https://learn.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;
    }
}




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







[최초 등록일: ]
[최종 수정일: 8/14/2024]

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://learn.microsoft.com/en-us/iis/develop/developing-for-ftp/how-to-use-managed-code-c-to-create-a-simple-ftp-home-directory-provider
정성태

... [151]  152  153  154  155  156  157  158  159  160  161  162  163  164  165  ...
NoWriterDateCnt.TitleFile(s)
1277정성태5/8/201231274오류 유형: 152. cmd.exe - The system cannot write to the specified device. [2]
1276정성태4/28/201223120Phone: 5. 모든 Marketplace에 윈폰 앱을 등록하는 방법 [1]
1275정성태4/28/201227004개발 환경 구성: 150. 프로세스 실행으로 잠긴 파일이지만, 이름은 변경가능하다는 사실! 아셨나요? [7]
1274정성태4/17/201221544Phone: 4. "Holiday Calendar" 윈폰 응용 프로그램 등록
1273정성태4/6/201224726Phone: 3. 윈도우 폰을 위한 Holiyday Calendar 앱 개발파일 다운로드1
1272정성태4/5/201226297오류 유형: 151. ASP.NET - EcbGetUnicodeServerVariables 코드에서 System.AccessViolationException 예외 발생
1271정성태4/3/201228975Math: 6. 동전을 여러 더미로 나누는 경우의 수 세기 [1]
1270정성태3/29/201222948오류 유형: 150. Visual Studio 2010 원격 디버깅 오류 - Kerberos authentication failed
1269정성태3/27/201236751오류 유형: 149. ODP.NET 오류 - The provider is not compatible with the version of Oracle client
1268정성태3/27/201233229오류 유형: 148. WCF svc 호출 시 HTTP Error 404.17 - Not Found [1]
1267정성태3/16/201231201.NET Framework: 314. C++의 inline asm 사용을 .NET으로 포팅하는 방법 [1]파일 다운로드1
1266정성태3/14/201234419개발 환경 구성: 149. RAID 1 구성 시 하드 디스크 장애 발생 해결에 대한 경험담
1265정성태3/13/201224724VC++: 61. 아이태니엄(IA64: Itanium) 에서 겪은 C++ 포인터 연산 문제 [2]
1264정성태3/10/201244119.NET Framework: 313. WELL512 난수 발생 알고리즘 - C# [5]파일 다운로드1
1263정성태3/9/201222928개발 환경 구성: 148. tinyget 사용법
1262정성태3/8/201243797개발 환경 구성: 147. .keystore 파일에 저장된 개인키 추출 방법과 인증기관으로부터 온 공개키를 합친 pfx 파일 만드는 방법 [1]
1261정성태3/7/201224509Phone: 2. 개발자용 윈도우 폰 7 기기 등록하는 방법
1260정성태3/6/201224371Phone: 1. 윈도폰 7 개발자 (회사) 등록하는 방법 [3]
1259정성태3/4/201235860Windows: 57. 새로 추가된 네트워크 커널 디버깅 및 PowerShell 3.0 [1]
1258정성태3/3/201237482개발 환경 구성: 146. SQL Server 2012에 포함된 LocalDB 기능 소개 [3]파일 다운로드1
1257정성태3/3/201225672.NET Framework: 312. Native 스레드와 Managed 스레드 개체의 상태 관계 [1]파일 다운로드1
1256정성태3/3/201229213Math: 5. Euler's totient function - C#파일 다운로드1
1255정성태3/3/201231592Math: 4. 소수 판정 및 소인수 분해 소스 코드 - C# [1]파일 다운로드1
1254정성태3/1/201226564Windows: 56. Windows 8 Consumer Preview를 사용해 보고... [1]
1253정성태3/1/201228037VS.NET IDE: 71. Visual Studio 11 Ultimate 베타 설치 [3]
1252정성태3/1/201225397Windows: 55. 윈도우 8 베타 설치 과정 [1]
... [151]  152  153  154  155  156  157  158  159  160  161  162  163  164  165  ...