Hallo Forum,
meine Problemstellung verlangt in einem regelmäßigem Zeitintervall Daten per FTP abzuholen und diese in einem weiteren Step abzuarbeiten.
Ich habe das ganze als Dienst mit einer in teilen selbstgeschriebenen FTP-Klasse gelöst. Diese Klasse nutzt den "RETR" Befehlt um Daten herunterzuladen.
Ursprünglich wurde das Programm auf Windows XP Maschinen betrieben und funktioniert dort auch nachwievor. Nun soll das Programm auf Windows Server 2003 betrieben werden, was leider bisher zu nicht nachvollziehbaren Problemen beim herunterladen führt.
Der Dienst meldet, das er den angegebenen Host nicht finden kann, obwohl zuvor ein Login erfolgreich durchgeführt worden ist. Meine Vermutung ist, das die Datenverbindung möglichweise in diesem Fall nicht funktioniert.
Nachfolgend noch etwas Code aus dem Service und der FTP Klasse:
Service Timer_Elapsed-Methode:
myFTP.FTPClient ftp = new myFTP.FTPClient();
ftp.RemoteHost = this.ftpHost;
ftp.RemoteUser = this.ftpUser;
ftp.RemotePassword = this.ftpPassword;
ftp.Login();
ftp.SetBinaryMode(false);
ftp.Download("TestDaten.txt", myFTP.FTPClient.DownloadCommand.GET);
ftp.Close();
...
FTP-Download-Methode (von mir auf .net 2.0 angepasst)
public void Download(string RemoteFileName, DownloadCommand CommandType)
{
if(!logined)
{
Login();
}
if (LocalFileName.Equals(""))
{
LocalFileName = RemoteFileName;
}
if(!System.IO.File.Exists(LocalFileName))
{
System.IO.Stream st = System.IO.File.Create(LocalFileName);
st.Close();
}
System.IO.FileStream output = new System.IO.FileStream(LocalFileName, System.IO.FileMode.Open);
System.Net.Sockets.Socket cSocket = createDataSocket();
long offset = 0;
if(resume)
{
offset = output.Length;
if(offset > 0)
{
sendCommand("REST " + offset);
if(this.returnValue != 350)
{
offset = 0;
}
}
if(offset > 0)
{
long npos = output.Seek(offset, System.IO.SeekOrigin.Begin);
}
}
//sendCommand("GET " + RemoteFileName);
//sendCommand("RETR " + RemoteFileName);
sendCommand(Enum.GetName(typeof(DownloadCommand), CommandType) + " " + RemoteFileName);
if(!(this.returnValue == 150 || this.returnValue == 125))
{
throw new System.IO.IOException(this.reply.Substring(4));
}
while(true)
{
this.bytes = cSocket.Receive(this.buffer, this.buffer.Length, 0);
output.Write(this.buffer,0,this.bytes);
if(bytes <= 0)
{
break;
}
}
output.Close();
if (cSocket.Connected)
{
cSocket.Close();
}
readReply();
if( !(this.returnValue == 226 || this.returnValue == 250) )
{
throw new System.IO.IOException(this.reply.Substring(4));
}
}
Datenkanal (von mir auf .net 2.0 angepasst)
private System.Net.Sockets.Socket createDataSocket()
{
sendCommand("PASV");
if(this.returnValue != 227)
{
throw new System.IO.IOException(this.reply.Substring(4));
}
int index1 = this.reply.IndexOf('(');
int index2 = this.reply.IndexOf(')');
string ipData = this.reply.Substring(index1 + 1, index2 - index1 - 1);
int[] parts = new int[6];
int len = ipData.Length;
int partCount = 0;
string buf="";
for (int i = 0; i < len && partCount <= 6; i++)
{
char ch = Char.Parse(ipData.Substring(i,1));
if (Char.IsDigit(ch))
{
buf+=ch;
}
else if (ch != ',')
{
throw new System.IO.IOException("Malformed PASV reply: " + this.reply);
}
if (ch == ',' || i+1 == len)
{
try
{
parts[partCount++] = Int32.Parse(buf);
buf="";
}
catch (Exception)
{
throw new System.IO.IOException("Malformed PASV reply: " + this.reply);
}
}
}
string ipAddress = parts[0] + "."+ parts[1]+ "." + parts[2] + "." + parts[3];
int port = (parts[4] << 8) + parts[5];
System.Net.Sockets.Socket s = new System.Net.Sockets.Socket(System.Net.Sockets.AddressFamily.InterNetwork, System.Net.Sockets.SocketType.Stream, System.Net.Sockets.ProtocolType.Tcp);
System.Net.IPEndPoint ipEndPoint = new System.Net.IPEndPoint(System.Net.Dns.GetHostEntry(ipAddress).AddressList[0], port);
try
{
s.Connect(ipEndPoint);
}
catch(Exception)
{
throw new System.IO.IOException("Can't connect to remote server");
}
return s;
}
Eine Firewall oder gesperrte Ports scheiden aus. Als Basis für meine FTP-Klasse diente dieser Code: http://www.csharphelp.com/archives/archive9.html