Hogar Flores perennes Desarrollo de aplicaciones cliente-servidor utilizando Indy en Delphi. Componentes Indy utilizados en Delphi. Algunos ejemplos de uso de componentes Indy

Desarrollo de aplicaciones cliente-servidor utilizando Indy en Delphi. Componentes Indy utilizados en Delphi. Algunos ejemplos de uso de componentes Indy

El protocolo UDP es bastante bueno para la transmisión. mensajes de texto, es decir, puedes organizar chats locales y cosas similares. Decidí dar un ejemplo del trabajo más sencillo con UDP en Delphi.

Instrucción paso a paso:

Di un ejemplo, pero perdóname, no escribí cada línea, porque... No veo nada complicado y cualquiera puede resolverlo.

De hecho, si algo no te queda claro, puedes hacerme una pregunta. Y aquí está el código real:

usos
Windows, Mensajes, SysUtils, Variantes, Clases, Gráficos, Controles, Formularios,
Cuadros de diálogo, StdCtrls, IdUDPServer, IdBaseComponent, IdComponent, IdUDPBase,
IdUDPClient, IdSocketHandle;

tipo
TForm1 = clase(TForm)
IdUDPClient1: TIdUDPClient;
IdUDPServer1: TIdUDPServer;
Botón1: TBotón;
Etiqueta1: TLabel;
procedimiento FormCreate(Remitente: TObject);
procedimiento FormClose(Remitente: TObject; var Acción: TCloseAction);
procedimiento Button1Click(Remitente: TObject);
procedimiento IdUDPServer1UDPRead(AThread: TIdUDPListenerThread; AData: TBytes;
Encuadernación: TIdSocketHandle);
privado
(Declaraciones privadas)
público
(Declaraciones públicas)
fin;

var
Formulario1: TForm1;

($R *.dfm)
[b]//Procedimiento para enviar un mensaje
procedimiento TForm1.Button1Click (Remitente: TObject);
comenzar
intentar
IdUDPClient1.Active:= Verdadero;
IdUDPClient1.Host:= "localhost";
IdUDPClient1.Conectar;
si IdUDPClient1.Connected entonces
comenzar
IdUDPClient1.Send(TimeToStr(Tiempo));
Etiqueta1.Caption:= "bien";
fin;
IdUDPClient1.Active:= Falso;
pitido; pitido; pitido;
excepto
MessageDlg("Algo salió mal =(", mtError, , 0);
fin;
fin;
[b]
//Encendido apagado. Servidor UDP al iniciar y cerrar el formulario
procedimiento TForm1.FormClose(Remitente: TObject; var Acción: TCloseAction);
comenzar
IdUDPServer1.Active:= Falso;
fin;

procedimiento TForm1.FormCreate(Remitente: TObject);
comenzar
IdUDPServer1.Active:= Verdadero;
fin;

[b]//Procedimiento de reacción del servidor al recibir datos
procedimiento TForm1.IdUDPServer1UDPRead(AThread: TIdUDPListenerThread;
AData: TBytes; Encuadernación: TIdSocketHandle);
var
i:Entero;
s:cadena;
comenzar
s:= "";
intentar
yo:= 0;
mientras que (AData[i] 0) lo hace
comenzar
s:= s + chr(AData[i]);
yo:= yo + 1;
fin;
finalmente
Etiqueta1.Caption:= s;
fin;
fin;

En pocas palabras, Indy son componentes para trabajar cómodamente con protocolos de Internet populares. El principio de su funcionamiento se basa en el uso de enchufes en modo de bloqueo. Indy es interesante y conveniente porque es bastante abstracto. Y la programación en Indy se reduce a programación lineal. Por cierto, en Internet se distribuye ampliamente un artículo traducido, en el que aparecen las palabras “el modo de bloqueo no es el diablo” :)) En un momento me divirtió mucho esta traducción. El artículo forma parte del libro "Depths of Indy" de Hoover y Hariri. En principio, para trabajar con Indy no es necesario leerlo todo, pero aun así recomiendo familiarizarse con los principios de cómo funcionan los protocolos de Internet. En cuanto al régimen "diabólico". Una llamada de socket de bloqueo en realidad no devuelve el control hasta que haya completado su tarea. Cuando se realizan llamadas en el hilo principal, la interfaz de la aplicación puede congelarse. Para evitar esta desagradable situación, los desarrolladores indios crearon el componente TIdAntiFreeze. Solo necesita ingresarlo en el formulario y la interfaz de usuario se volverá a dibujar fácilmente mientras realiza llamadas de bloqueo.

Probablemente ya se haya familiarizado con el contenido de las distintas pestañas "Indy (...)" en Delphi. Hay muchos componentes allí y cada uno de ellos puede resultar útil. Yo mismo no he trabajado con todos porque no veo la necesidad de estudiarlos sin una tarea específica.

La distribución básica de Delphi incluye Indy v.9 con centavos. Probablemente sería aconsejable actualizar inmediatamente a más nueva versión(por ejemplo, actualmente tengo 10.0.76, pero parece que también hay versiones posteriores).

Hay componentes de cliente y servidor para trabajar con los mismos protocolos. Indy realmente simplifica el desarrollo de aplicaciones, a diferencia de la opción de desarrollar la misma funcionalidad en sockets. Por ejemplo, para establecer una conexión con el servidor, simplemente debes llamar al método Connect. Un establecimiento de conexión exitoso será marcado por el regreso del método sin causar una excepción. Si no se establece la conexión, se lanzará una excepción.

Ejemplo "académico" (el código no funciona, no lo ejecute :)):

Con IndyClient hazlo
comenzar
Anfitrión:= "test.com";
Puerto:= 2000;
Conectar;
Intentar
// trabajar con datos (leer, escribir...)
finalmente
Desconectar;
fin;
fin;

El host y el puerto se pueden configurar en el inspector de objetos o en tiempo de ejecución.

¿Por qué se pueden utilizar componentes de Indy en tareas de análisis? ¡Varios usos! Lo más sencillo es obtener el contenido de la página (probablemente todo el mundo ya se haya encontrado con esto) utilizando el componente IdHTTP:

var
rcvrdata: TMemoryStream;
idHttp1: TidHttp;
comenzar
idHttp1:= TidHttp.Create(nulo);
rcvrdata:= TMemoryStream.Create;
idHttp1.Request.UserAgent:= "Mozilla/4.0 (compatible; MSIE 5.5; Windows 98)";
idHttp1.Request.AcceptLanguage:= "ru";
idHttp1.Response.KeepAlive:= verdadero;
idHttp1.HandleRedirects:= verdadero;
intentar
idHttp1.Get(Edit1.Text, rcvrdata);
finalmente
idHttp1.Gratis;
fin;
si rcvrdata.Size > 0 entonces comienza
ShowMessage("Recibido " + inttostr(rcvrdata.Size));
rcvrdata.SaveToFile("c:\111.tmp");
fin;
rcvrdata.Gratis;
fin;

Como puede ver, no sólo puede obtener el contenido de la página, sino también simular la carga de un documento desde un cliente específico. componentes indios son generalmente convenientes para generar encabezados y solicitudes POST. Más sobre esto con ejemplos la próxima vez.

Para mantenerse actualizado con las actualizaciones del blog, puede

Introducción a la India

Introducción a la India
Publicado por Chad Z. Hower
Página de inicio: http://www.atozedsoftware.com
Traducción: Anatoli Podgoretsky
introducción
Escribí este artículo cuando la versión actual era Indy 8.0. Gran parte de este artículo es aplicable y muy útil en futuras versiones de Indy. Si le gustó este artículo y desea leer artículos más detallados, consulte el libro Indy in Depth.
Indy se está ejecutando en modo de bloqueo
Indy utiliza enchufes de bloqueo. El modo de bloqueo es similar a la lectura y escritura de archivos. Al leer o escribir datos, la función no devuelve el control hasta que se completa la operación. La diferencia con trabajar con archivos es que la llamada puede tardar más, ya que los datos solicitados aún no existen, esto depende de la velocidad a la que opere tu red o módem.
Por ejemplo, simplemente se llama a un método y se espera hasta que se devuelva el control al punto de llamada. Si la llamada fue exitosa, el método devolverá el control; si ocurre un error, se generará una excepción.
El encierro no es fatal
Debido al modo de bloqueo, nuestros oponentes nos han derrotado muchas veces, pero el modo de bloqueo no es el diablo.
El problema apareció después de portar Winsock a Windows. En Unix, el problema normalmente se resolvía mediante una bifurcación (similar a los subprocesos múltiples, pero a expensas de procesos individuales en lugar de arroyos). Los clientes y demonios de Unix tuvieron que bifurcar los procesos que deberían estar ejecutándose y usar el modo de bloqueo. Windows 3.x no se pudo paralelizar y no admitía muchos subprocesos. El uso de una interfaz de bloqueo congeló la interfaz de usuario e hizo que los programas no respondieran. Por lo tanto, se agregaron modos sin bloqueo a WinSock, lo que permitió a Windows 3.x con sus limitaciones usar Winsock sin bloquear el hilo principal y único del programa. Esto requirió una programación diferente, Microsoft y otros vilipendiaron apasionadamente los regímenes de bloqueo para ocultar Desventajas de Windows 3.x.
Luego vino Win32, que podía soportar subprocesos múltiples. Pero en ese momento sus cerebros ya estaban confusos (es decir, los desarrolladores consideraban que bloquear los sockets era creación del diablo) y ya era difícil cambiar lo que habían hecho. Por lo tanto, continúa la difamación de los regímenes bloqueadores.
En realidad, Unix sólo tiene sockets de bloqueo. Los sockets de bloqueo también tienen sus ventajas y son mucho mejores para subprocesos múltiples, seguridad y otros aspectos. Se han agregado algunas extensiones a Unix para sockets sin bloqueo. Sin embargo, funcionan de manera muy diferente que en Windows. Tampoco son estándar y no son muy comunes. Los sockets de bloqueo en Unix se utilizan en casi todos los casos y se seguirán utilizando.
Ventajas del modo de bloqueo·Más fácil de programar: los modos de bloqueo son más fáciles de programar. Todo el código de usuario puede estar en un solo lugar y ejecutarse en un orden secuencial natural. Más fácil de transferir a Unix: dado que Unix utiliza sockets de bloqueo, escriba el código portátil en en este caso más fácil. Indy utiliza este hecho para escribir código uniforme. ·Es más conveniente trabajar con hilos: dado que los encajes de bloqueo tienen una secuencia adquirida por herencia, son muy fáciles de usar en hilos.
Desventajas del modo de bloqueo · La interfaz de usuario se congela en los clientes: una llamada de socket de bloqueo no devuelve el control hasta que haya completado su tarea. Cuando se realiza una llamada de este tipo en el hilo principal de la aplicación, la aplicación no puede procesar los mensajes del usuario. Esto hace que la interfaz de usuario se congele, que las ventanas no se actualicen y que no se procesen otros mensajes hasta que se devuelva el control desde el socket de bloqueo.
Componente TIdAntiFreeze
Indy tiene un componente especial que soluciona el problema de la congelación. interfaz de usuario. Simplemente agregue un componente TIdAntiFreeze en cualquier lugar de su aplicación y podrá realizar llamadas de bloqueo sin congelar la interfaz de usuario.
TIdAntiFreeze se ejecuta en un temporizador interno fuera de la pila de llamadas y llama a Application.ProcessMessages cuando expira el tiempo de espera. Las llamadas externas a Indy siguen bloqueándose y por tanto funcionan exactamente igual que sin utilizar el componente TIdAntiFreeze. El uso de TIdAntiFreeze le permite obtener todas las ventajas de bloquear sockets, sin ninguna de sus desventajas.
Hilos de código (Threading)
Con los sockets de bloqueo, casi siempre se utilizan flujos de código. Los sockets sin bloqueo también pueden usar subprocesos, pero esto requiere algún procesamiento adicional y sus beneficios se pierden en comparación con los sockets con bloqueo.
Ventajas de los subprocesos · Establecimiento de prioridades: se pueden configurar las prioridades de los subprocesos individuales. Esto permite asignar más o menos tiempo de CPU a tareas individuales. ·Encapsulación: cada conexión puede contener algo parecido a una interfaz con otra conexión. ·Seguridad: cada hilo puede tener diferentes atributos de seguridad. ·Múltiples procesadores: proporciona una ventaja en sistemas con múltiples procesadores. ·No es necesario serializar: proporciona simultaneidad total. Sin muchos subprocesos, todas las solicitudes deben procesarse en un solo subproceso. Por lo tanto, cada tarea debe dividirse en pequeñas partes para que pueda realizarse rápidamente. Mientras se ejecuta un bloque, todos los demás se ven obligados a esperar a que termine. Al final de un bloque se ejecuta el siguiente y así sucesivamente. Con subprocesos múltiples, cada tarea se puede programar como una sola unidad y Sistema operativo Distribuye el tiempo entre todas las tareas.
Hilos de encuesta
Crear y destruir hilos requiere muchos recursos. Esta es una tarea particularmente difícil para servidores que tienen conexiones de corta duración. Cada servidor crea un hilo, lo usa un tiempo corto y luego lo destruye. Esto da como resultado que se creen y eliminen hilos con mucha frecuencia. Un ejemplo de esto es un servidor web. Se envía una única solicitud y se devuelve una respuesta simple. Al utilizar un navegador, pueden ocurrir cientos de conexiones y desconexiones al visualizar cualquier sitio web.
Los hilos de votación pueden corregir esta situación. En lugar de crear y destruir subprocesos a pedido, los subprocesos se seleccionan de una lista de subprocesos no utilizados pero ya creados del grupo. Cuando un hilo ya no es necesario, se devuelve al grupo en lugar de destruirse. Los subprocesos del grupo se marcan como no utilizados y, por lo tanto, no consumen tiempo de CPU. Para más más mejora Los subprocesos pueden adaptarse dinámicamente a las necesidades actuales del sistema.
Indy admite el sondeo de subprocesos. Se puede acceder al grupo de subprocesos en Indy a través del componente TIdThreadMgrPool.
muchos hilos
Un servidor muy cargado puede requerir cientos o incluso miles de subprocesos. Existe la creencia común de que cientos y miles de subprocesos pueden acabar con su sistema. Ésta es una creencia falsa.
En la mayoría de los servidores, los subprocesos esperan datos. Mientras espera una llamada de bloqueo, el hilo está inactivo. En un servidor con 500 hilos, sólo 50 pueden estar activos al mismo tiempo.
La cantidad de subprocesos que se ejecutan en su sistema puede sorprenderle. En cantidad minima ejecutando servidores y las aplicaciones en ejecución especificadas, mi sistema tiene 333 subprocesos creados, incluso con 333 subprocesos el procesador solo tiene una carga del 1%. Servidor IIS muy cargado ( internet Information Server) puede crear cientos y miles de hilos.
Hilos y secciones globales
Con múltiples subprocesos, debe garantizar la integridad de los datos al acceder a ellos. Esto puede resultar difícil para los programadores que no han trabajado con subprocesos. Pero, en general, la mayoría de los servidores no necesitan utilizar datos globales. La mayoría de los servidores realizan funciones aisladas. Cada hilo realiza su propia tarea aislada. Las secciones globales de lectura/escritura son una característica de muchas aplicaciones multiproceso, pero no son típicas de los servidores.
Metodología Indy
Indy es diferente de otros componentes de Winsock a los que está acostumbrado. Si ha trabajado con otros componentes, entonces la mejor solucion olvidará cómo funcionan. Muchos otros componentes utilizan llamadas sin bloqueo (asincrónicas) y funcionan de forma asincrónica. Necesitan reaccionar ante eventos, crear una máquina de estado y ejecutar ciclos de espera frecuentes.
Por ejemplo, con otros componentes, cuando llama a una conexión, debe esperar a que se produzca el evento de conexión o esperar en un bucle a que una propiedad indique que se ha producido la conexión. Con Indy, puedes llamar al método Connect y esperar a que regrese. Se emitirá un reembolso si la conexión se realiza correctamente o se genera una excepción si hay un problema. Por tanto, trabajar con Indy es muy similar a trabajar con archivos. Indy te permite poner todo tu código en un solo lugar, en lugar de distribuirlo por todas partes varios eventos. Además, Indy es muy sencillo y más cómodo a la hora de trabajar con hilos.
¿Qué tan diferente es Indy?
Breve descripción general · Se utilizan llamadas de bloqueo · No está orientado a eventos: hay eventos, pero se utilizan para necesidades informativas y no son realmente necesarios. ·Diseñado para hilos: Indy está diseñado para hilos, pero se puede utilizar sin hilos. Programación secuencial
Revisión detallada
Indy no solo usa llamadas de bloqueo (sincrónicas) sino que también funciona así. Una sesión típica de Indy se ve así:
con IndyClient comienza
Conectar; Intentar
//Haz tus cosas aquí
finalmente desconectar; fin;
fin;
Con otros componentes se ve así:
procedimiento TFormMain.TestOnClick (Remitente: TComponent);
comenzar
con SocketComponent comienza
Conectar; intentar
mientras no esté conectado, comience
si IsError entonces comienza
Abortar;
fin;

OutData:= "Datos para enviar";
mientras que la longitud (OutData)> 0 comienza
Aplicación.ProcessMessages;
fin;
finalmente desconectar; fin;
fin;
fin;
procedimiento TFormMain.OnConnectError;
comenzar
IsError:= Verdadero;
fin;
procedimiento TFormMain.OnRead;
var
i: Entero;
comenzar
i:= SocketComponent.Send(OutData);
OutData:= Copiar(OutData, i + 1, MaxInt);
fin;
Muchos componentes no hacen un buen trabajo aislando al programador de la pila. Muchos componentes, en lugar de aislar al usuario de las complejidades de la pila, simplemente lo dejan a su cargo o proporcionan un contenedor sobre la pila.
manera especial india
Indy está diseñado desde cero para ser multiproceso. Crear servidores y clientes en Indy es similar a crear servidores y clientes en Unix. Las aplicaciones Unix normalmente llaman a la pila directamente con poca o ninguna capa de abstracción.
Normalmente, los servidores Unix tienen uno o más procesos de escucha que monitorean las solicitudes entrantes de los clientes. Para cada cliente que necesita ser atendido, un nuevo proceso. Esto simplifica la programación, cada proceso para un solo cliente. Cada proceso se ejecuta por sí solo. propio contexto seguridad, que se especifica mediante el proceso de escucha o el proceso basado en derechos existentes, identificación u otras cosas.
Los servidores Indy funcionan de forma muy similar. Windows, a diferencia de Unix, no puede multiplicar bien los procesos, pero funciona bien con subprocesos. Los servidores Indy crean un hilo separado para cada conexión de cliente.
Los servidores Indy asignan un hilo de escucha que está separado del hilo de código principal del programa. El hilo de escucha escucha las solicitudes entrantes de los clientes. Para cada cliente al que responde, un nuevo hilo para servicio al cliente. Luego, los eventos correspondientes se atienden en el contexto de ese hilo.
Opinión del cliente de Indy
Indy está diseñado para proporcionar muy nivel alto abstracciones. La complejidad y los detalles de la pila TCP/IP están ocultos para el programador. Normalmente, una sesión de cliente típica en Indy se ve así:
con IndyClient comienza
Anfitrión:= "zip.pbe.com"; // Anfitrión para llamar
Puerto:= 6000; // Puerto para llamar al servidor
Conectar; Intentar
//Haz tus cosas aquí
finalmente desconectar; fin;
fin;
Descripción general del servidor Indy
Los componentes del servidor Indy crean un hilo de escucha que está aislado del hilo del código del programa principal. El hilo de escucha escucha las solicitudes entrantes de los clientes. Para cada cliente al que responde, se crea un nuevo hilo para atender al cliente. Luego, los eventos correspondientes se atienden en el contexto de ese hilo.

Ejemplos prácticos
Los siguientes ejemplos le ayudarán a empezar a trabajar con componentes para fácil de usar, pero para demostrar ejemplos hechos como aplicaciones simples. Algunos proyectos se realizan con fines de demostración. varias situaciones. Estos ejemplos también están disponibles para descargar como archivos zip.
Nota del traductor: el enlace del sitio no funciona.
Ejemplo 1: verificación de código postal
El primer proyecto se hace lo más simple posible. Búsqueda por código postal, el cliente pregunta al servidor a qué ciudad y estado pertenece el código postal especificado.
Para quienes viven fuera de Estados Unidos y no saben qué es un código postal, es un código postal que indica el lugar de entrega. Los códigos postales constan de 5 dígitos.
Protocolo
El primer paso para construir un servidor y un cliente es desarrollar un protocolo. Para protocolos estándar, esto está definido por el RFC correspondiente. Para el código postal, el protocolo se define a continuación.
La mayoría de los protocolos de comunicación funcionan en modo texto. Intercambiar significa que se transmite un comando y, en respuesta, un estado y posiblemente datos. Los protocolos no se limitan al intercambio, sino que todavía se utiliza texto sin formato. El protocolo para determinar el código postal también se basa en texto. El texto sin formato facilita la depuración de los protocolos y permite la comunicación. idiomas diferentes programación y sistemas operativos.
Después de conectarse, el servidor envía un mensaje de saludo y luego acepta el comando. Este comando puede ser "ZipCode x" (donde x es el código postal) o "Salir". En respuesta al comando ZipCode, se envía una respuesta en forma de una línea con la respuesta o una línea vacía si no se encuentra el código. El comando Salir hace que el servidor cierre la conexión. El servidor puede aceptar varios comandos antes de enviar el comando Salir.
Código fuente del servidor

unidad Servidor Principal;

interfaz

usos

tipo

TformMain = clase(TForm)

IdTCPServer1: TIdTCPServer;

procedimiento FormCreate(Remitente: TObject);

procedimiento FormDestroy(Remitente: TObject);

procedimiento IdTCPServer1Connect(AThread: TIdPeerThread);

privado

Lista de códigos postales: TStrings;

público

fin ;

Formulario principal: Tform principal;

implementación

(R*.DFM)

procedimiento TformMain.IdTCPServer1Connect (AThread: TIdPeerThread);

comenzar

AThread.Connection .WriteLn ("Servidor de código postal Indy listo.");

fin ;

SComando: cadena;

comenzar

SComando:= LeerLn;

fin ;

fin ;

fin ;

procedimiento TformMain.FormCreate (Remitente: TObject);

comenzar

ZipCodeList:= TStringList.Create;

ZipCodeList.LoadFromFile(ExtractFilePath(Application.EXEName) + "ZipCodes.dat");

fin ;

procedimiento TformMain.FormDestroy (Remitente: TObject);

comenzar

ZipCodeList.Gratis;

fin ;

fin.

Las únicas partes específicas de Indy en el proyecto son el componente IdTCPServer1, los métodos IdTCPServer1Connect e IdTCPServer1Execute.
El formulario contiene el componente IdTCPServer1 de tipo TIdTCPServer. Se han cambiado las siguientes propiedades: ·Activo = Verdadero: después de que se inicia la aplicación, el servidor escucha. DefaultPort = 6000 - Valor del puerto para de este proyecto. El servidor escucha las solicitudes de los clientes en este puerto.
El método IdTCPServer1Execute está asociado con el evento OnExecute del servidor. El evento OnExecute se genera después de que se acepta la conexión del cliente. El evento OnExecute es diferente de otros eventos que conoce. OnExecute se ejecuta en el contexto de un hilo. El evento del hilo se genera y se le pasa el argumento AThread al método. Esto es importante porque se pueden ejecutar varios eventos OnExecute al mismo tiempo. Esto se hace para que el servidor pueda funcionar sin crear un nuevo componente. También existen métodos que pueden anularse al crear herederos.
El evento OnConnect se activa después de que se acepta la conexión y se crea un hilo para ella. En este servidor, esto se utiliza para enviar un mensaje de bienvenida al cliente. Si lo desea, esto también se puede hacer en el evento OnExecute.
El evento OnExecute se puede activar varias veces hasta que la conexión se desconecte o se pierda. Esto elimina la necesidad de verificar la conexión en busca de desconexión o pérdida en un bucle dentro de un evento.
IdTCPServer1Execute utiliza dos funciones básicas, ReadLn y WriteLn. ReadLn lee una cadena de la conexión y WriteLn envía una cadena a la conexión.
sComando:= LeerLn;
El código anterior toma una cadena del cliente y la coloca en la variable de cadena local sCommand.

si SameText (sCommand, "QUIT") entonces comienza

finalice si no es el mismo texto (Copiar (sCommand, 1, 8), "Código postal ") y luego comience

WriteLn(ZipCodeList.Values[Copy(sCommand, 9, MaxInt)]);

fin ;


A continuación, se comprueba que sCommand tenga comandos válidos.
Si el comando es "Salir", se realiza la desconexión. No se permite leer ni escribir después de la desconexión. Una vez finalizado el evento, el hilo de escucha ya no lo llama, sino que borra el hilo y finaliza la conexión.
Si el comando es "Código postal", se extrae el parámetro después del comando y se escanea la tabla para detectar la presencia de la ciudad y el estado. Luego, la ciudad y el estado se pasan al cliente, o se pasa una cadena vacía si no hay coincidencia.
A continuación, el método sale. El servidor repetirá la llamada del evento nuevamente tan pronto como llegue. nuevo equipo, permitiendo al cliente enviar múltiples comandos.
Código fuente del cliente

unidad Cliente Principal;

interfaz

usos

Windows, Mensajes, SysUtils, Clases, Gráficos, Controles, Formularios, Cuadros de diálogo,

StdCtrls, ExtCtrls, IdAntiFreezeBase,

IdAntiFreeze, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

tipo

TformMain = clase(TForm)

Cliente: TIdTCPClient;

IdAntiFreeze1: TIdAntiFreeze;

Panel1: Panel T;

Panel2: Panel T;

Entrada de notas: TMemo;

LboxResultados: TListBox;

Panel3: Panel T;

Botón1: TBotón;

Botón2: TBotón;

Etiqueta1: TLabel;

procedimiento Button2Click(Remitente: TObject);

procedimiento Button1Click (Remitente: TObject);

privado

público

fin ;

Formulario principal: Tform principal;

implementación

(R*.DFM)

procedimiento TformMain.Button2Click (Remitente: TObject);

comenzar

MemoInput.Borrar;

LboxResults.Clear;

fin ;

procedimiento TformMain.Button1Click (Remitente: TObject);

Yo: número entero;

S: cadena;

comenzar

ButnLookup.Enabled: = verdadero; intentar

LboxResults.Clear;

con el Cliente comienza

Conectar; intentar

LboxResults.Items.Add(ReadLn);

para i:= 0 a memoInput.Lines .Count - 1 comienza

WriteLn("Código postal" + memoInput.Lines[i]);

LboxResults.Items.Add(memoInput.Lines[i]);

S:= LeerLn;

si s = "" entonces comienza

S:= "-- No se encontró ninguna entrada para este código postal.";

fin ;

LboxResults.Items.Add(s);

LboxResults.Items.Add("");

fin ;

WriteLn("Salir");

finalmente desconectar; fin ;

fin ;

finalmente butnLookup.Enabled: = verdadero; fin ;

fin ;

fin.


Las únicas partes específicas del componente del cliente son el método Button1Click.
El componente Cliente es de tipo TIdTCPClient y se coloca en el formulario. Se han cambiado las siguientes propiedades: ·Host = 127.0.0.1: el servidor está ubicado en la misma máquina que el cliente. ·Puerto = 6000 - Puerto del servidor
El método Button1Click está asociado con el evento OnClick del componente Button1. Cuando se hace clic en el botón, se llama a este método. La parte Indy de este método se puede reducir a lo siguiente: 1.Conéctese al servidor (Conectar;) 1.Lea el saludo del servidor. 1. Para cada línea ingresada por el usuario en TMemo: 1. Enviar una solicitud al servidor (WriteLn("ZipCode " + memoInput.Lines[i]);) 1. Leer una respuesta del servidor (s:= ReadLn; ) 1. Enviar el comando Salir (WriteLn("Salir");) 1.Desconectar (Desconectar;)
Pruebas
Este ejemplo ha sido probado y funciona con TCP/IP instalado. Puede cambiarlo para que funcione en una red de una computadora a otra. Iniciando el servidor en otra computadora y cambiando el nombre o IP del servidor en el cliente.
Para probar proyectos, compila y ejecuta el servidor. Luego compila y ejecuta el cliente. Ingrese su código postal en el campo de nota y presione la tecla de búsqueda.
Depuración
Los protocolos de texto son muy fáciles de depurar porque se pueden probar mediante Telnet. Para ello basta con conocer el puerto del servidor. El servidor de búsqueda de código postal escucha en el puerto 6000.
Inicie nuevamente el servidor de búsqueda de código postal. Luego abra una consola (por ejemplo, una ventana Dos). Ahora ingresa:
Telnet 127.0.0.1 6000
Ahora está conectado al servidor. Algunos servidores también envían un mensaje de bienvenida. Algunos no lo hacen. No verá las líneas que ingrese. La mayoría de los servidores no hacen eco para ahorrar tráfico. Sin embargo, puede cambiar la configuración de telnet configurando la opción "Echo On". Esto se hace de manera diferente en diferentes clientes telnet y algunos no tienen esta característica en absoluto. Ahora ingresa:
código postal 37642
Verá la respuesta del servidor:
CHURCH HILL, Tennessee
Para desconectarse del servidor, ingrese:
abandonar
Ejemplo 2: acceso a la base de datos
Este ejemplo emula un servidor que debe realizar tareas de bloqueo distintas de las llamadas a socket. Muchos servidores se ven obligados a trabajar en estas condiciones. Los servidores que necesitan acceder a la base de datos, llamar a procedimientos externos o cálculos muchas veces no pueden interrumpir estas llamadas, porque son llamadas externas o por la complejidad de esta. El acceso a la base de datos no se puede dividir en pequeños fragmentos y el desarrollador debe esperar a que finalice la operación con la base de datos. Esta es una característica no sólo de las llamadas a bases de datos, sino también de otras operaciones como compresión, cálculos y otros procesamientos del mismo tipo.
Para fines de demostración, imaginemos que el servidor realiza una llamada a la base de datos que tarda 5 segundos en completarse. Para simplificar, hagamos esto simplemente con una pausa, usemos la función Sleep(5000) para esto, en lugar de llamar realmente.
Este ejemplo también requiere menos detalles que el anterior porque muchos de los conceptos aún no se entienden.
Fuente

unidad principal;

interfaz

usos

Windows, Mensajes, SysUtils, Clases, Gráficos, Controles, Formularios, Cuadros de diálogo,

IdBaseComponent, IdComponent, IdTCPServer;

tipo

TformMain = clase(TForm)

IdTCPServer1: TIdTCPServer;

procedimiento IdTCPServer1Execute(AThread: TIdPeerThread);

privado

público

fin ;

Formulario principal: Tform principal;

implementación

(R*.DFM)

procedimiento TformMain.IdTCPServer1Execute (AThread: TIdPeerThread);

Yo: número entero;

comenzar

con AThread.La conexión comienza

WriteLn("Hola. Servidor de base de datos listo.");

Yo:= StrToIntDef(ReadLn, 0);

// La suspensión se sustituye por una base de datos larga u otra llamada

Dormir(5000);

WriteLn(IntToStr(i * 7));

fin ;

fin ;

fin.

Debido a que el evento Ejecutar ocurre en el contexto de un hilo, el código de procesamiento puede tener cualquier longitud. Cada cliente tiene su propio hilo y no bloquea a otros clientes.
Pruebas
Para probar el servidor de base de datos, compílelo y ejecútelo. Conéctese mediante Telnet al puerto 6001. El servidor responderá con un mensaje de bienvenida. Ingresar número. El servidor "procesará" su solicitud y responderá en 5 segundos.

¡Hola a todos!

Al desarrollar el siguiente proyecto web, surgió la tarea: implementar en Delphi un software cliente que transfiriera datos al servidor mediante el método POST. La aplicación debe transmitir texto y cargar archivos al servidor web.

La implementación de dicho envío de datos utilizando lenguajes de desarrollo web del lado del servidor (por ejemplo, PHP) es bastante simple, pero si necesita escribir software multiusuario basado en aplicaciones que interactúe con el servidor, entonces es un poco más complicado. El método de conectarse directamente a la base de datos y vía FTP al servidor desde Delphi ya no es necesario porque no es seguro ni confiable (cambio de contraseñas, datos de conexión, etc.) y crea archivos adicionales. Problemas de compatibilidad de software en el lado del cliente. Para resolver el problema, decidí escribir scripts en PHP (parte del servidor) que procesarán las solicitudes POST entrantes y devolverán el resultado al cliente (aplicación Delphi). Las ventajas de este enfoque son que todas las conexiones y el procesamiento de datos se realizan en el servidor, lo que es mucho más seguro que una "conexión" directa.

Cuando comencé a buscar en Google, encontré mucha información dispersa, principalmente en foros, pero estaba toda fragmentada. Una cosa era segura que se utilizaría Indy: el componente IdHTTP con el método POST implementado. En esencia, todo es simple, este método toma dos parámetros URL del recurso y DataStream (flujo de datos), y en respuesta devuelve el resultado en forma de texto (también puede ser el código HTML de la página). Lo principal era formación correcta DataStream (flujo de datos transmitidos), pero en el camino surgieron obstáculos adicionales, a saber, la codificación rusa (si no fuera buena). Aquí empezó la diversión de varias horas de deambular por Internet. En general, basta de charla, pasemos a la práctica y la implementación del software.

Entonces el programa es simple. Debe enviar datos al servidor usando el método POST, los datos contienen " Título " (línea), " Descripción " (texto multilínea) y archivo gráfico(jpg,png,gif-datos binarios). El servidor debe aceptar estos datos, procesarlos, guardar el archivo gráfico en el servidor y devolver una respuesta. Como respuesta, devolveremos Delphi a la aplicación, el mismo texto solo con etiquetas agregadas y un enlace al archivo descargado. Nada más.

Comencemos con la implementación de la parte del servidor (similar a la API del sitio). Abra cualquier editor de texto (bloc de notas) y escriba el siguiente código en él:

"; ) else ( echo "Título: Faltante"."
"; ) //Compruebe los datos entrantes para detectar la presencia de datos del campo "contenido" if (!empty($_POST["content"]))( echo "Content: ".$_POST["content"]."
"; ) else ( echo "Contenido: Faltante"."
"; ) //Compruebe los datos entrantes para detectar la presencia de un archivo adjunto "archivo" if (!empty($_FILES["file"])) ( $finfo = pathinfo($_FILES["file"]["name" ]); //obtener información sobre el archivo (nombre, extensión, etc.) //Verificar el tipo de archivo en la lista de tipos permitidos (IMPROVISACIÓN:)) if (stripos("jpgpnggif",$finfo["extensión"] )==0)( echo ">>>>>>>Tipo de archivo no válido<<<<<<<<"; exit; //Если не допустим тип, полностью останавливаем скрипт } $fname = "files/" . "testimgfile." . $finfo["extension"]; //формируем путь и новое имя файла move_uploaded_file($_FILES["file"]["tmp_name"],$fname);//сохраняем временный файл "tmp_name" в файл $fname echo "http://".$_SERVER["HTTP_HOST"]."/".$fname; //возвращаем полный путь к файлу } ?>

nota! Al guardar (a través del bloc de notas), debe especificar la codificación "UTF-8", de lo contrario, habrá problemas al mostrar el alfabeto cirílico.

El guión intentó proporcionar comentarios detallados. Copie este script a su servidor web, si no tiene uno, puede usar mi script para la prueba, se encuentra en: http://api..php

El diseño utiliza los siguientes componentes: Etiqueta, Botón (2 piezas), Editar (2 piezas), Nota (2 piezas), CheckBox, OpenDialog, IdHTTP. Proporcione los siguientes nombres de componentes (propiedad “ Nombre”):

  1. Editar (título) – Nombre=título;
  2. Editar (ruta al archivo) Nombre = archivo img;
  3. Nota(Contenido)Nombre = contenido;
  4. Memo (Resultado) – Nombre = respuesta;
  5. Botón(…) - Nombre = chkfile;
  6. Botón (POST) – Nombre = PublicarPero;
  7. OpenDialog (cuadro de diálogo de selección de archivos) – Nombre = PictDialog;

Dejemos IdHTTP1 y CheckBox1 sin cambios (¡cansados! :)))).

Para no accidentalmente " editar»ruta a Editar( archivo img), establezca su propiedad ReadOnly en True. Asimismo, en archivo img Y chkarchivo Establezca la propiedad Habilitada en falso. Los activaremos usando CheckBox, es decir. Le brindaremos la oportunidad de elegir si desea cargar una imagen o no.

Para diálogo abierto ( PictDialog) debe configurar el filtro (propiedad de filtro) de la siguiente manera:

¡La preparación visual real ha terminado! ¡Empecemos a codificar!

En el proyecto generaremos un flujo de datos utilizando el tipo incluido con Indy - TidMultiPartFormDataStream. Aunque encontramos opciones de implementación usando TStream, trabajar con TidMultiPartFormDataStream –¡más fácil!

Para que este tipo esté disponible para nuestro proyecto, necesitamos agregar la siguiente biblioteca a Usos: IdMultipartFormData.

Para CheckBox1, cree un evento OnClick (haciendo doble clic con el mouse en un objeto) y agregue el siguiente código a este evento:

Procedimiento TForm1.CheckBox1Click(Remitente: TObject); comenzar //activar o desactivar los elementos de la ruta del archivo y los botones de diálogo imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; fin;

Aquí activamos los objetos. archivo img Ychkarchivo dependiendo de la presencia de una marca de verificación (si la casilla de verificación está marcada, los objetos se activan).

Ahora organicemos la selección de imágenes. Para hacer esto, cree un evento OnClick en el botón chkarchivo(también haciendo doble clic sobre el objeto) y escribe lo siguiente:

Procedimiento TForm1.chkfileClick(Remitente: TObject); comenzar //abre el cuadro de diálogo e ingresa la ruta completa al archivo en imgfile(TEdit) si PictDialog.Execute luego imgfile.Text:= PictDialog.FileName; fin;

Este evento activará un cuadro de diálogo de selección de imagen y si el usuario hace clic en " Abierto", entonces la ruta a este archivo se agregará a archivo img.

Y ahora llegamos al último botón "POST". Cree un evento OnClick para este botón y agregue el siguiente código:

Procedimiento TForm1.PostButClick(Remitente: TObject); var datosPost:TIdMultiPartFormDataStream; comenzar dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; si CheckBox1.Checked y (trim(imgfile.Text)="") entonces //comprobando si el archivo está seleccionado o no, comienza ShowMessage("¡Debes seleccionar un archivo gráfico!"); salida; fin; si CheckBox1.Checked entonces dataPost.AddFile("file",imgfile.Text,""); //agrega un campo con la respuesta del archivo.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; fin;

Entonces, en orden (aunque hay comentarios):

publicación de datos – objeto de tipo TIdMultiPartFormDataStream. Le permite crear una estructura de solicitud POST que consta de campos de diferentes tipos.

datosPublicar . Agregar campo de formulario (" título ", título . Texto ," utf -8 "). Transferencia de contenido := " 8 poco "; – agrega un campo llamado "título" al DataPost, un valor de "título.Texto", establece la codificación de los datos transmitidos en "utf-8" (el parámetro es opcional, pero sin su indicación explícita, el cirílico se transmite con signos de interrogación “?”) y un método muy importante "Transferencia de contenido". Sin este método, los datos se envían al servidor " abracadabra" Tenga en cuenta que el nombre del campo (“título”) en el lado emisor debe coincidir con el nombre especificado en el script: $_POST["título"].

Los datos se transfieren de manera similar al campo "contenido".

datosPublicar . Agregar archivo (" archivo ", archivo img . Texto ,"") – con esta línea creamos un flujo con los datos del archivo.

Todo, se generan los datos, solo queda transferirlos al script en el servidor y recibir una respuesta:

respuesta.Texto:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,);

porque TMemo no entiende la etiqueta de salto de línea "
", usaremos la función " " para reemplazarlo con saltos de línea comprensibles "#13#10".

Cuando todo esté completo, borre la memoria del objeto DataPost con la línea:

publicación de datos.Gratis;

Aunque en nuestro ejemplo esto sucederá automáticamente al final del procedimiento, pero aún así...

El resultado real del programa en la pantalla:

Por lo tanto, podemos enviar tantos datos o archivos al servidor como queramos, procesar estos datos en el servidor e informar a la aplicación el resultado del script. Incluso podría ser solo 0 o 1, lo que indicará a la aplicación que reaccione más.

Todo. Buena suerte a todos. Espero que la información haya sido útil y le encuentres utilidad.

Puede descargar el ejemplo y el script terminados.

Código del módulo completo:

Unidad PostUnidad; la interfaz utiliza Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, IdHTTP, IdMultipartFormData, Vcl.ExtDlgs; tipo TForm1 = clase(TForm) IdHTTP1: TIdHTTP; título: TEdit; contenido: TMemo; PublicarPero: TButton; respuesta: TMemo; Etiqueta1: TLabel; Etiqueta2: TLabel; Etiqueta3: TLabel; archivo img:TEdit; chkfile: TButton; Etiqueta4: TLabel; Casilla de verificación1: TCheckBox; PictDialog:TOpenDialog; procedimiento PostButClick(Remitente: TObject); procedimiento chkfileClick(Remitente: TObject); procedimiento CheckBox1Click (Remitente: TObject); privado (declaraciones privadas) público (declaraciones públicas) fin; var Formulario1: TForm1; implementación ($R *.dfm) procedimiento TForm1.CheckBox1Click(Sender: TObject); comenzar //activar o desactivar los elementos de la ruta del archivo y los botones de diálogo imgfile.Enabled:=CheckBox1.Checked; chkfile.Enabled:=CheckBox1.Checked; fin; procedimiento TForm1.chkfileClick (Remitente: TObject); comenzar //abre el cuadro de diálogo e ingresa la ruta completa al archivo en imgfile(TEdit) si PictDialog.Execute luego imgfile.Text:= PictDialog.FileName; fin; procedimiento TForm1.PostButClick(Remitente: TObject); var datosPost:TIdMultiPartFormDataStream; comenzar dataPost:=TIdMultiPartFormDataStream.Create; dataPost.AddFormField("title",title.Text,"utf-8").ContentTransfer:= "8bit"; dataPost.AddFormField("content",content.Text,"utf-8").ContentTransfer:= "8bit"; si CheckBox1.Checked y (trim(imgfile.Text)="") entonces //comprobando si el archivo está seleccionado o no, comienza ShowMessage("¡Debes seleccionar un archivo gráfico!"); salida; fin; si CheckBox1.Checked entonces dataPost.AddFile("file",imgfile.Text,""); //agrega un campo con la respuesta del archivo.Text:= StringReplace(idHTTP1.Post("http://api..php",dataPost),"
",#13#10,); datapost.Free; fin; fin.

Indy es un paquete de componentes bastante potente que le permite desarrollar varias aplicaciones de red. En este tutorial te diré cómo puedes crear aplicaciones cliente-servidor usando los componentes TIdTCPClient y TIdTCPServer.

En primer lugar, me gustaría señalar dos ventajas importantes de estos componentes. El más importante de ellos es el subproceso múltiple, lo que significa que el servidor crea un subproceso separado para cada cliente, y esto ciertamente afecta el rendimiento del programa del servidor en computadoras con un procesador multinúcleo. La segunda ventaja es la facilidad de uso. De 10 a 20 líneas de código son suficientes para escribir una aplicación cliente-servidor sencilla. Este paquete de componentes está presente en conjuntos estándar de Delphi.

Escribamos un programa simple que le permita transferir un mensaje de texto de un cliente a un servidor. Comencemos a crear el servidor.
Coloquemos el componente IdTCPServer de la pestaña “Servidores Indy” en el formulario. Realizaremos todas las configuraciones para este componente en tiempo de ejecución en el evento OnCreate del formulario:
IdTCPServer1.DefaultPort:= 12345;
IdTCPServer1.Active:= verdadero;
Aquí todo es simple: indicamos el puerto en el que funcionará el servidor y activamos el servidor.

Para recibir datos del cliente en el servidor, existe un evento especial "OnExecute". Este evento se ve así:

comenzar
fin;

Editemos el contenido del evento de la siguiente manera:
procedimiento TForm3.IdTCPServer1Execute(AContext: TIdContext);
var
l:cadena; // variable de cadena en la que recibiremos
comenzar
l:= AContext.Connection.IOHandler.ReadLn();
Memo1.Lines.Add(l);
fin;

Ahora, tan pronto como llegue un mensaje al servidor, lo escribiremos en la variable de cadena l y lo enviaremos a un campo de texto de varias líneas.

Esto, como era de esperar, pone fin a la creación del servidor. Indy hará el resto por nosotros. Comencemos con el programa cliente. Se conectará al servidor, le enviará un mensaje y se desconectará del servidor.

Creemos un nuevo proyecto y coloquemos el componente IdTCPClient en el formulario, que se puede encontrar en la pestaña "Clientes Indy". También colocaremos un Editar simple y un botón. Creemos un controlador de eventos OnClick para el botón, dentro del cual escribiremos:
IdTCPClient1.Puerto:= 12345;
IdTCPClient1.Host:= '127.0.0.1';
IdTCPClient1.Conectar;
IdTCPClient1.IOHandler.WriteLn(Edit1.Text);
IdTCPClient1.Desconectar;

No es necesario colocar este código en el evento OnCreate. Puede colocar este código en cualquier lugar que desee si lo desea.
En la primera línea asignamos un puerto y es necesario especificar el mismo puerto que especificamos en el programa del servidor; de lo contrario, el cliente simplemente no encontrará el servidor. Luego indicamos la dirección IP del servidor. El servidor en sí puede estar ubicado en la red local o de forma remota. En este último caso, la conexión se realizará a través de Internet y será necesario especificar una dirección IP en Internet.

Especifiqué la dirección "127.0.0.1", lo que significa que el servidor es la computadora en la que se ejecuta el cliente. Este método es muy conveniente para probar aplicaciones de red.
Luego hacemos una conexión, enviamos un mensaje y nos desconectamos.Al igual que el mensaje en sí, también puedes tomar la dirección IP desde Edit o desde cualquier variable de cadena.

También se completa el trabajo en el programa del cliente. Como puede ver, Indy hace un gran trabajo para nosotros, lo que hace posible que incluso un programador sin experiencia cree su propia aplicación de red.

Nuevo en el sitio

>

Más popular