.net - net - el uri solicitado no es válido para este comando ftp
¿Cómo mejorar el rendimiento de FtpWebRequest? (18)
Tengo una aplicación escrita en .NET 3.5 que usa FTP para cargar / descargar archivos de un servidor. La aplicación funciona bien, pero hay problemas de rendimiento:
Lleva mucho tiempo establecer una conexión con el servidor FTP. El servidor FTP está en una red diferente y tiene Windows 2003 Server (IIS FTP). Cuando se ponen en cola varios archivos para su carga, el cambio de un archivo a otro crea una nueva conexión usando FTPWebRequest y lleva mucho tiempo (alrededor de 8-10 segundos).
¿Es posible reutilizar la conexión? No estoy muy seguro sobre la propiedad KeepAlive. Qué conexiones se mantienen vivas y reutilizadas.
El IIS-FTP en Windows Server 2003 no es compatible con SSL por lo que cualquiera puede ver fácilmente el nombre de usuario / contraseña a través de un detector de paquetes como WireShark. Descubrí que Windows Server 2008 admite SSL a través de FTP en su nueva versión si es IIS 7.0.
Básicamente quiero mejorar el rendimiento de carga y descarga de mi aplicación. Cualquier idea será apreciada.
** Tenga en cuenta que 3 no es un problema, pero me gustaría que la gente tenga comentarios al respecto
AFAIK, cada FtpWebRequest tiene que configurar una nueva conexión, incluido el inicio de sesión en el servidor. Si desea acelerar las transferencias FTP, le recomendaría que use un cliente FTP alternativo en su lugar. Algunos de estos clientes alternativos pueden iniciar sesión y luego realizar múltiples acciones usando la misma conexión de comando.
Los ejemplos de tales clientes incluyen: http://www.codeproject.com/KB/IP/FtpClient.aspx que también incluye una buena explicación de por qué estas bibliotecas pueden operar más rápido que el estándar FtpWebRequest y http://www.codeproject.com/KB/macros/ftp_class_library.aspx que también parece una implementación bastante simple.
Personalmente, volví a implementar mi propia implementación de FTP en .NET 1.1 días antes de que se introdujera FtpWebRequest, y esto todavía funciona bien para .NET 2.0 en adelante.
Definitivamente debería verificar BITS que es una gran mejora con respecto a FTP. Las contraseñas de texto claro no son la única debilidad en FTP. También está la cuestión de predecir el puerto que se abrirá para una carga o descarga pasiva y solo una dificultad general cuando los clientes usan NAT o firewalls.
BITS funciona a través de HTTP / HTTPS utilizando extensiones IIS y admite cargas y descargas en cola que se pueden programar con baja prioridad. En general, es mucho más flexible que FTP si usa Windows en el cliente y el servidor.
Este enlace describe ConnectionGroupName y KeepAlive afecta: WebRequest ConnectionGroupName
Estuve trabajando unos días con eso ... y la velocidad era realmente baja, nada que comparar con FileZilla ... finalmente lo resolví con multithreads. 10 hilos que hacen conexiones para descargar me dan una buena tasa, tal vez incluso podrían mejorarse más ... con una configuración de ftprequest estándar
PeticionFTP.ConnectionGroupName = "MyGroupName"
PeticionFTP.ServicePoint.ConnectionLimit = 4
PeticionFTP.ServicePoint.CloseConnectionGroup("MyGroupName")
PeticionFTP.KeepAlive = False
PeticionFTP.UsePassive = False
PeticionFTP.UseBinary = True
PeticionFTP.Credentials = New NetworkCredential(lHost.User, lHost.Password)
He hecho algunos experimentos (cargando aproximadamente 20 archivos en varios tamaños) en FtpWebRequest con los siguientes factores
KeepAlive = verdadero / falso
ftpRequest.KeepAlive = isKeepAlive;
Nombre del grupo de conexión = definido por el usuario o nulo
ftpRequest.ConnectionGroupName = "MyGroupName";
Límite de conexión = 2 (predeterminado) o 4 u 8
ftpRequest.ServicePoint.ConnectionLimit = ConnectionLimit;
Modo = Sincrónico o Asíncrono
mira este ejemplo
Mis resultados:
Use ConnectionGroupName, KeepAlive = true took (21188.62 msec)
Use ConnectionGroupName, KeepAlive = false took (53449.00 msec)
No ConnectionGroupName, KeepAlive = falso tomó (40335.17 msec)
Use ConnectionGroupName, KeepAlive = true; async = true, connections = 2 tomó (11576.84 msec)
Use ConnectionGroupName, KeepAlive = true; async = true, connections = 4 took (10572.56 msec)
Use ConnectionGroupName, KeepAlive = true; async = true, connections = 8 took (10598.76 msec)
Conclusiones
FtpWebRequest
se ha diseñado para admitir un grupo de conexiones internas. Para garantizar que se utiliza el grupo de conexiones, debemos asegurarnos de que se establezcaConnectionGroupName
.Configurar una conexión es costoso. Si nos estamos conectando al mismo servidor ftp utilizando las mismas credenciales, tener el indicador mantener activo establecido en verdadero minimizará la cantidad de conexiones configuradas.
Asincrónico es la forma recomendada si tienes muchos archivos para ftp.
El número predeterminado de conexiones es 2. En mi entorno, un límite de conexión de 4 me dará la mayor ganancia de rendimiento general. Aumentar la cantidad de conexiones puede o no mejorar el rendimiento. Le recomendaría que tenga el límite de conexión como un parámetro de configuración para que pueda ajustar este parámetro en su entorno.
Espero que encuentres esto útil.
He tenido buenos resultados con la biblioteca ftp de EDT:
http://www.enterprisedt.com/products/edtftpnet/overview.html
Hice algunos puntos de referencia en FtpWebRequest, similar a la respuesta de @Sid anterior. Establecer KeepAlive en true mejora, pero no las llamadas asincrónicas en mi prueba. La prueba consiste en
1) FtpWebRequest para comprobar la existencia del archivo 2) FtpWebRequest para subirlo 3) FtpWebRequest para cambiar el nombre del archivo en el servidor
Test FTP client 30 files of size 5 Kbytes took ... 14.897 seconds Test upload (alive true, connection name) 30 files of size 5 Kbytes took ... 34.229 seconds Test async(alive true, connection name) 30 files of size 5 Kbytes took ... 40.659 seconds Test send thread (alive true, connection name) 30 files of size 5 Kbytes took ... 38.926 seconds, 30 files
Lo que mejoró fue una implementación de un cliente FTP hecho usando la clase Socket
el punto de referencia está aquí
KeepAlive está funcionando. FtpWebRequest almacena en caché las conexiones internas, por lo que se pueden reutilizar después de un tiempo. Para obtener detalles y una explicación de este mecanismo, puede consultar ServicePoint .
Otra buena fuente de información es buscar en el origen de FtpWebRequest (puede hacerlo en VS2008).
Mire esta página - http://www.ietf.org/rfc/rfc959.txt
Dice de usar un puerto diferente cuando se conecta para poder reutilizar la conexión.
¿Eso funciona?
No importa si las conexiones individuales tardan en conectarse siempre que pueda iniciar muchas en paralelo. Si tiene muchos elementos para transferir (digamos cientos), entonces tiene sentido lanzar decenas e incluso cientos de WebRequests en paralelo, utilizando los métodos asincrónicos como BeginGetRequestStream y BeginGetResponse . Trabajé en proyectos que enfrentaban problemas similares (tiempos de conexión / autentificación largos) pero al emitir muchas llamadas en paralelo, el rendimiento general era en realidad muy bueno.
También hace una gran diferencia si usa los métodos asíncronos o el sincrónico, tan pronto como tenga muchas (decenas, cientos) de solicitudes. Esto se aplica no solo a sus métodos de Solicitud web, sino también a los métodos de read / write Stream que usará luego de obtener la secuencia de carga / descarga. El libro Improving .Net Performance and Scalability está un poco desactualizado, pero gran parte de sus consejos sigue en pie y es de lectura gratuita en línea.
Una cosa a tener en cuenta es que la clase ServicePointManager encuentra al acecho en el Framwework con un único propósito: arruinar su rendimiento. Asegúrese de obtener el ServicePoint de su URL y cambie ConnectionLimit a un valor razonable (al menos tan alto como la cantidad de solicitudes concurrentes que desee).
Para resolver el problema del rendimiento, simplemente debe configurar:
ftpRequest.ConnectionGroupName = "MyGroupName"; ftpRequest.KeepAlive = false; ftpRequest.ServicePoint.CloseConnectionGroup("MyGroupName");
Personalmente, he migrado todas nuestras aplicaciones del uso de FTP para cargar y descargar archivos, y en su lugar lancé una solución basada en XML Web Services en ASP.NET.
El rendimiento es mucho mejor, la seguridad es tanto o tan poca como desee codificar (y puede usar las cosas integradas en .NET) y todo puede pasar por SSL sin problemas.
Nuestra tasa de éxito de obtener conexiones de nuestros clientes a través de sus propios servidores de seguridad es mucho mejor que ejecutar FTP.
Pruebe este código a continuación, obtendrá un mejor rendimiento:
private void Upload144_Click(object sender, EventArgs e)
{
OpenFileDialog fileobj = new OpenFileDialog();
fileobj.InitialDirectory = "C://";
//fileobj.Filter = "Video files (*.mp4)";
//fileobj.ShowDialog();
if (fileobj.ShowDialog() == DialogResult.OK)
{
if (fileobj.CheckFileExists)
{
string test = Properties.Settings.Default.Connection;
SqlConnection con = new SqlConnection(test);
con.Open();
string correctfilename = System.IO.Path.GetFileName(fileobj.FileName);
SqlCommand cmd = new SqlCommand("Insert into Path(ID,Path5) VALUES ((select isnull(MAX(id),0) + 1 from Path),''//Videos//" + correctfilename + "'')", con);
cmd.ExecuteNonQuery();
string path = Application.StartupPath.Substring(0, Application.StartupPath.Length - 10);
con.Close();
//For Progressbar
DataTable dt = new DataTable();
// SqlDataAdapter da = new SqlDataAdapter(cmd);
// da.Fill(dt);
timer5.Enabled = true;
// FOR FtpServer File Upload::
string uploadfile = fileobj.FileName;
string uploadFileName = new FileInfo(uploadfile).Name;
string uploadUrl = "ftp://ftp.infotech.com/";
FileStream fs = new FileStream(uploadfile, FileMode.Open, FileAccess.Read);
try
{
long FileSize = new FileInfo(uploadfile).Length; // File size of file being uploaded.
Byte[] buffer = new Byte[FileSize];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
fs = null;
string ftpUrl = string.Format("{0}/{1}", uploadUrl, uploadFileName);
FtpWebRequest requestObj = FtpWebRequest.Create(ftpUrl) as FtpWebRequest;
requestObj.Method = WebRequestMethods.Ftp.UploadFile;
requestObj.Credentials = new NetworkCredential("[email protected]", "test@123");
Stream requestStream = requestObj.GetRequestStream();
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
requestObj = null;
}
catch (Exception ex)
{
//MessageBox.Show("File upload/transfer Failed./r/nError Message:/r/n" + ex.Message, "Succeeded", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
}
Punto único de consejo:
BAJO TAMPÓN / TAMAÑOS DE CHUNK REDUCIR SIGNIFICATIVAMENTE EL RENDIMIENTO
Motivo: muchos más discos I / o, memoria i / o, ftp stream init y muchos más factores
Recomiendo cambiar a rsync .
Pros:
Optimizado para reducir el tiempo de transferencia.
Admite SSH para una transferencia segura
Utiliza TCP, lo que hace que su departamento de TI / firewall sea más feliz
Contras:
Sin soporte nativo de .NET
Diseñado para instalaciones de servidores Linux, aunque hay puertos decentes para Windows como DeltaCopy
En general, es una opción mucho mejor que FTP
Recomiendo encarecidamente Starksoft FTP / FTPS Component para .NET y Mono . Tiene un objeto de conexión que puedes guardar en caché y reutilizar.
Sé que es un hilo viejo, pero recientemente tuve que pasar por una situación similar.
Necesitábamos descargar más de 70 archivos XML de un servidor ftp en menos de 25 minutos sin abrir más de 5 conexiones durante ese período de tiempo.
Estas fueron todas las alternativas que probamos:
- wget - Fue rápido, pero cada GET significaba una nueva conexión. Tuvimos que parar debido a la cantidad de conexiones creadas. Tuvimos algunos problemas con GETM que están bien documentados en la web, por lo que no era una opción.
- FtpWebRequest: cada llamada a Crear registraría una nueva conexión, aunque usamos las propiedades KeepAlive y ConnectionGroupName. Además, fue muy lento.
- Webclient: no verificamos si creaba una nueva conexión para cada archivo (aunque supongo que sí), pero copió 1 archivo / minuto. Entonces no era una opción.
Terminamos usando una secuencia de comandos por lotes de FTP antigua. Es rápido y solo uso una conexión para descargar todos los archivos. No es flexible, pero es mucho más rápido que todo lo demás que he probado (75 archivos en menos de 20 minutos).
Debug Network
Algunos trucos para la depuración de red simple:
- Compruebe los tiempos de respuesta cuando hace ping al servidor FTP desde el servidor de aplicaciones.
- Compruebe los tiempos de respuesta para una ruta de rastreo (
tracert
desde un shell de DOS). - Transfiera un archivo desde la línea de comando usando el comando
ftp
. - Conéctese al servidor FTP a través de Telnet:
telnet server 21
.
Los resultados proporcionarán pistas para resolver el problema.
Hardware de red
Para una ruta de rastreo lenta:
- Determine por qué las dos computadoras tienen problemas de red.
- Actualice el hardware de red entre el enlace más lento.
configuración de la red
Para un ping lento:
- Verifique la configuración de red en cada máquina.
- Asegúrese de que la configuración sea óptima.
Validar API
Una sesión lenta de línea de comando le dirá que el problema no está aislado de la API de FTP que está utilizando. No elimina la API como un problema potencial, pero ciertamente lo hace menos probable.
Errores de red
Si los paquetes se eliminan entre el origen y el destino, el ping le avisará. Es posible que deba aumentar el tamaño del paquete a 1500 bytes para ver cualquier error.
Servidor FTP Queue
Si no tiene control sobre el servidor FTP de destino, solicite a un servidor intermediario que reciba los archivos cargados. El intermediario luego envía los archivos al servidor remoto a cualquier velocidad que pueda. Esto da la ilusión de que los archivos se envían rápidamente. Sin embargo, si los archivos deben existir en el servidor remoto tan pronto como se cargan, es posible que esta solución no sea viable.
Software de servidor FTP
Use un daemon FTP diferente en el servidor FTP, como ProFTPd como un servicio de Windows . (ProFTPd tiene complementos para varias bases de datos que permiten la autenticación mediante consultas SQL).
Sistema operativo del servidor FTP
Un sistema operativo basado en Unix podría ser una mejor opción que uno basado en Microsoft.
Software de cliente FTP
Hay varias API diferentes para enviar y recibir archivos a través de FTP. Podría tomar algún trabajo hacer que su aplicación sea lo suficientemente modular como para que simplemente pueda conectar un nuevo servicio de transferencia de archivos. Algunas API diferentes se enumeran como respuestas aquí.
Protocolo alterno
Si FTP no es un requisito absoluto, intente:
- una unidad de red de Windows
- HTTPS
- scp, rsync o programas similares (puede que se requiera Cygwin )