Desarrollo de una aplicación cliente-servidor en Delphi. Creando una aplicación cliente-servidor en Delphi

Para desarrollar la aplicación Directorio Telefónico se utiliza el entorno de programación visual Delphi 7. El proyecto del programa contendrá tres ventanas:

  • 1. fMain: la forma principal del programa.
  • 2. fEditor: formulario para agregar/editar entradas.
  • 3. fDM - módulo de datos.

En el formulario fDM agregaremos un componente ADOConnection, 1 componente tipo ADOTable, 1 componente tipo DataSource. Haga doble clic en la propiedad ConnectionString del componente ADOConnection. Se abrirá la ventana para conectar el componente a ADO (Fig.2):

Puc. 2. Ventana para conectarse a ADO.

Haga clic en el botón Construir. Se abre una nueva ventana (Fig. 3.) que contiene la configuración de conexión:

Arroz. 3.

Seleccione Proveedor de datos: Proveedor Microsoft OLE DB para SQL Server. En la pestaña Conexión: seleccione el nombre del servidor en el que se encuentra su base de datos. Ahora establezcamos la propiedad Conectado en Verdadero. Cambiemos las siguientes propiedades de ADOTable: Conexión a ADOConnection1; TableName en el suscriptor; Activo a Verdadero. Cambie las siguientes propiedades de DataSource (este será un enlace a la tabla): DataSet a ADOTable.

Vayamos al formulario principal. Seleccione el comando Archivo -> Usar unidad y conecte el módulo DM a él. Ahora podremos ver las tablas desde el formulario principal.

Coloquemos los componentes en el formulario principal. Están ubicados en el área de la ventana principal del entorno integrado, que se denomina paleta de componentes (Fig. 4).

Arroz. 4.

Agreguemos tres botones al formulario principal fMain (Fig. 5). Están destinados a editar la entrada actual, agregar una nueva y eliminarla.

Fig.5.

La pestaña DataControls se centra en componentes de visualización de datos visuales (visibles para el usuario), como DBGrid (una cuadrícula que muestra todos los datos en una tabla y le permite editarlos), DBEdit (un campo de edición de datos diseñado para ingresar o editar un campo de un registro, es decir, celdas de la tabla), DBMemo (para editar campos MEMO), etc. La única excepción es el componente DBNavigator. Este componente no está diseñado para mostrar datos, sino para moverse a través de registros en un conjunto de datos, insertar un nuevo registro o eliminar uno antiguo. Agregue y seleccione DBGrid, en su propiedad DataSource seleccione fDM.ADOTable. La cuadrícula reacciona y vemos los nombres de los campos (Fig. 6).

Arroz. 6.

Ahora creemos un filtro de registros basado en varios criterios. Para hacer esto, agregue dos componentes GroupBox al formulario. En el inspector de objetos (Fig. 7), en la propiedad Título del componente GroupBox1, ingrese "Filtrar por un campo" y para el componente GroupBox2 "Filtrar por varios campos".

Fig.7.

En GroupBox1 agregaremos 3 etiquetas, 1 ComboBox, 1 Edit y 2 RadioButtons. Para Etiqueta1 en la propiedad Caption escribiremos “Buscar en”, para Etiqueta2 “Ingresar datos”, para Etiqueta3 “Método”. En la propiedad Elementos del componente ComboBox, ingrese dos líneas: apellido, teléfono (Fig. 8).

Fig.8.

RadioButton tiene la propiedad Título "Desde el principio de la línea" y "Cualquier aparición". En el segundo GroupBox, agregue tres etiquetas con la propiedad Título: Apellido, Nombre, Teléfono. Tres componentes de edición y un botón con la propiedad de título "Buscar". Y agregue otro Botón al formulario para eliminar el filtro.

Ahora crearemos una ventana del editor de datos. Creemos un nuevo formulario (Archivo -> Nuevo -> Formulario). Cambiemos el nombre de su propiedad Nombre a fEditor. Usando el comando Archivo -> Usar unidad, conectaremos el módulo de datos DM al formulario. Ahora necesitamos instalar los siguientes componentes en el formulario: 8 Label, 7 DBEdit, 1 DBComboBox.

Finalicemos el componente DBComboBox. Haga doble clic en su propiedad Elementos para abrir el editor. Introduciremos tres líneas en él:

Calle

carril

Avenida

Guarde el texto haciendo clic en Aceptar.

Conectemos los componentes de control. mientras sostiene , seleccione todos los componentes de control (todos los componentes excepto Etiqueta). En su propiedad DataSource, seleccione fDM.DSLichData, conectando los componentes al conjunto de datos deseado (tabla). Eliminemos la selección general y seleccionemos el primer DBEdit. En su propiedad DataField, seleccione el campo "Apellido". Esta propiedad conecta el componente seleccionado a un campo de tabla específico. De la misma forma conectaremos el resto de componentes a los campos correspondientes.

En la parte inferior derecha, instale el componente de navegación DBNavigator desde la pestaña Controles de datos. Este componente está diseñado para navegar a través de registros, habilitar el modo de edición de registros, guardar o cancelar cambios realizados, agregar un nuevo registro o eliminar uno existente. En su propiedad DataSource, seleccione fDM.DSLichData para conectar el componente a la tabla principal. Sólo necesitamos de este componente la capacidad de ir al principio o al final de la tabla, al registro anterior o siguiente. Por lo tanto, expandamos su propiedad VisibleButtons (visibilidad de los botones del componente) y establezcamos todos los botones en False excepto nbFirst, nbPrior, nbNext y nbLast. Al hacer clic en estos botones se llamará a los métodos correspondientes del componente ADOTable. Estos métodos hacen lo siguiente:

Primero: va al primer registro de la tabla. Anterior: va al registro anterior. Siguiente: pasa al siguiente registro. Último: vaya al último registro.

Cuando a DBNavigator solo le quedan cuatro botones, estos botones se alargarán. Reduzcamos el ancho del componente para que los botones adquieran una apariencia más familiar.

fDM.TLichData.Append;

DBEdit1.SetFocus;

Usando el método Append, agregamos un nuevo registro a la tabla. A continuación, transferimos el foco de entrada a DBEdit1 para que el usuario no tenga que hacerlo él mismo.

si fDM.TLichData.Modified entonces

fDM.TLichData.Post;

Aquí guardamos los cambios en la tabla, si los hubiera, y cerramos la ventana.

Pasemos al formulario principal. Comencemos con el botón "Nuevo suscriptor". Deberá agregar un nuevo registro a cada tabla y luego abrir la ventana del editor:

fDM.TLichData.Append;

fEditor.ShowModal;

Generemos un procedimiento OnClick para el botón "Editar". Sólo habrá una línea de código:

fEditor.ShowModal;

Como resultado, se abrirá una ventana del editor y los componentes mostrarán los datos del registro actual.

Código para el botón "Eliminar":

fDM.TLichData.Delete;

Pasemos al filtrado de datos. En este filtro seleccionamos un campo de búsqueda, seleccionamos un método e ingresamos datos.

Generemos el evento OnChange para el componente Edit2.

si ((Longitud (Edit2.Text) > 0) y (Longitud (ComboBox1.Text) > 0)) entonces

fDM.TLichData.Filtered:=falso;

si RadioButton1.Checked entonces

fDM.TLichData.Filter:=Combobox1.Text + " ME GUSTA " + #39 + Edit2.Text + "%" + #39

fDM.TLichData.Filter:=Combobox1.Text + "LIKE"+ #39+ "%" + Edit2.Text + "%" + #39;

fDM.TLichData.Filtered:=verdadero;

de lo contrario fDM.TLichData.Filtered:=false;

La línea de condición del filtro significa lo siguiente: seleccione aquellos registros de la columna que comiencen con los mismos caracteres que los escritos en Edit2.Text.

La palabra clave LIKE le permite comparar cadenas usando un patrón determinado. En este caso, necesita saber lo siguiente:

símbolo "%" (porcentaje): reemplaza cualquier secuencia de caracteres.

° 39: significa el número del carácter " (comilla simple) en la tabla de códigos ASCII. El hecho es que el valor para el filtrado debe especificarse entre comillas simples y, dado que en Delphi se utilizan comillas simples para limitar las cadenas, entonces para coloque una comilla simple dentro de la cadena, debe colocarse dos veces.

Filtrar por múltiples campos. Generemos un evento OnClick para el botón Buscar.

procedimiento TfMain.Button3Click (Remitente: TObject);

fDM.TLichData.filtered:=false;

si longitud (edit4.text) > 0 entonces

filtr:= "APELLIDO COMO "+ #39 + Edit4.Text + "%" + #39;

si longitud (edit5.text) > 0 entonces

si longitud (filtro) >

filtr:=filtr + agregar + "NOMBRE COMO "+ #39 + Edit5.Text + "%" + #39;

si longitud (edit6.text) > 0 entonces

si longitud(filtr) > 0 entonces agregue:= " y " si no agregue:="";

filtr:=filtr + agregar + "teléfono ME GUSTA "+ #39 + Edit6.Text + "%" + #39;

si longitud (filtro) > 0 entonces

fDM.TLichData.Filter:= filtr;

fDM.TLichData.filtered:=true;

Showmessage("¡Todos los campos están vacíos!");

Para desactivar el filtro, haga clic en el botón "Eliminar filtro". Su código es así:

fDM.TLichData.Filter:= "";

fDM.TLichData.Filtered:= falso;

Como la aplicación es sencilla, decidí utilizar la base de datos MS Jet 4.0 (en otras palabras, la base de datos MS Access). Esta decisión se debe a que Jet (no lo confunda con MS Access) es un producto gratuito y viene con MS Windows (es decir, para que nuestro programa funcione, no es necesario instalar Access en la computadora del cliente). ). Y el editor de la base de datos es muy bueno y el kernel admite una gran cantidad de tipos de campos para satisfacer los deseos más pervertidos al almacenar datos.

Así que creemos una nueva base de datos, llamémosla Prueba y guárdela en la carpeta C:\ClientServer\Server\Data (por razones obvias, omito el proceso de creación de una nueva base de datos en Access, y solo daré la estructura de la tablas incluidas en nuestra base de datos).

1. Tabla uno, llamémosla Primera (bueno, ¡no soy escritor!)

2. La segunda tabla, y llamémosla algo inteligente - Segunda

Pues ya está, con la base y listo.

2. Programa
2.1. Servidor de aplicaciones.

Creemos una nueva aplicación y guárdela con el nombre Servidor en la carpeta C:\ClientServer\Server. Agreguemos el Módulo de datos remotos a la aplicación desde la pestaña Multinivel del repositorio (Fig. 1).

Al agregar RDM, el asistente de adición le pedirá los parámetros de este módulo; allí ingresaremos el nombre de nuestro servidor "Prueba".

Dejaremos todo lo demás sin cambios. Después de hacer clic en el botón "Aceptar", aparecerá en el proyecto un formulario similar a un módulo de datos normal llamado Prueba. Guardémoslo bajo el nombre. RDMFrm.pas.

Coloquemos sobre él los componentes ADOConnection (una pieza), ADOTable y DataSetProvider (dos piezas cada uno). Llamemos a los componentes ADOTable y DataSetProvider adotFirst, adotSecond, dspFirst y dspSecond, respectivamente. Al hacer doble clic en el componente ADOConnection, aparecerá el asistente de Cadena de conexión. Seleccione el elemento "Usar cadena de conexión" y haga clic en el botón Crear. En la ventana "Propiedades del enlace de datos" que aparece, seleccione "Proveedor OLE DB Microsoft Jet 4.0" y haga clic en el botón "Siguiente". En la pestaña "Conexión", ingrese la ruta a la base de datos, haga clic en el botón "Verificar conexión" y reciba un mensaje de que se ha completado la verificación de la conexión. Luego cierre el asistente haciendo clic en el botón Aceptar. El componente ADOConnection también tiene una propiedad llamada LoginPrompt, que estableceremos en False y Connected en True. Para los componentes de ADOTable, establezca la propiedad Conexión en ADOConnection seleccionando en la lista desplegable. Establezca la propiedad TableName en Primero y Segundo, respectivamente. La propiedad CursorType es ctDynamic, la propiedad TableDirect es True. Llame a FieldsEditor y agregue todos los campos allí.

Para componentes DataSetProvider:

En este punto, el proceso de creación de un servidor MIDAS primitivo puede considerarse completo. Para registrar un servidor en el subsistema DCOM, debe ejecutar la aplicación con el parámetro /regserver - Server.exe /regserver.
Y el toque final es la aplicación SocketServer de Borland, que se encuentra en la carpeta Delphi?/Bin/scktsvr.exe. Para que el cliente pueda ver el servidor, necesita ejecutar scktsvr.exe (si tiene Win NT/w2k/XP instalado, puede registrar esta aplicación como un servicio; para hacer esto, necesita ejecutarlo con scktsvr .exe /parámetro de instalación)

2.2. Solicitud de cliente

Creemos una nueva aplicación y guárdela en la carpeta C:\ClientServer\Client con el nombre Cliente. Coloquemos en el formulario principal dos componentes cada uno ClientDataSet (llamémoslos cdsFirst, cdsSecond), DataSource (llamémoslos dsFirst, dsSecond), DBGrid (llamémoslos dbgFirst, dbgSecond) y un componente SocetConnection.

Conexión Socet

Si hizo todo correctamente, cuando establezca la propiedad Conectado en Verdadero, la aplicación del servidor debería iniciarse.

Conjunto de datos del cliente

Iniciemos el Editor de campos (haga doble clic en el componente) y agreguemos todos los campos allí. Para componentes Conjunto de datos del cliente escribamos un controlador sdsDespués de la publicación

Y sustituirlo por procesamiento de eventos. Después de la publicación ambos ClientDataSets.

Fuente de datos

Propiedad Significado
Conjunto de datoscdsFirst y cdsSecond respectivamente

DBGrid

Propiedad Significado
Fuente de datosdsFirst y dsSecond respectivamente

Iniciemos el Editor de columnas (haga doble clic en el componente) y agreguemos todos los campos allí.
Pongamos un botón en el formulario cerca de las cuadrículas y escribámoslo en el controlador onClick.

Primero, sobre el componente del servidor. IdTCPServidor(marcador Servidores Indy). Para utilizar las capacidades del servidor, este componente debe colocarse en el formulario (componente no visualizable). Al configurar un componente, las siguientes propiedades son útiles:

  • Activo: activa o desactiva el servidor (falso predeterminado);
  • Enlaces: configura los sockets del servidor (los conecta a un puerto de computadora específico, le permite configurar un rango de direcciones IP y puertos de cliente usando el cuadro de diálogo de configuración de propiedades Vinculante;
  • ListenQueue: un valor numérico que limita el número máximo de solicitudes de conexión de clientes en la cola;
  • MaxConnections: le permite limitar la cantidad máxima de clientes conectados al servidor;

Echemos un vistazo más de cerca a la configuración de sockets de servidor utilizando la propiedad Bindings. Así, en la Fig. La Figura 1 muestra cómo utilizar el cuadro de diálogo Propiedades para Vinculante Configure el servidor para atender a clientes con cualquier dirección IP, con el socket del servidor conectado al puerto 12340.

Arroz. 1. Establecer la propiedad Vinculante.

En este punto, puede completar la configuración del servidor (aunque aquí no se utilizan todas las capacidades del componente IdTCPServer). El trabajo principal del servidor al procesar las solicitudes de los clientes se puede implementar en el controlador de eventos OnExecute. A este controlador se le pasa una referencia al objeto TIdContext: el hilo asociado con el cliente conectado al servidor.

A través de este objeto (más precisamente, su propiedad Conexión), puede recibir y enviar datos, así como recibir y configurar muchos parámetros de conexión útiles. El primer ejemplo del uso del objeto TIdContext al procesar una solicitud de cliente se muestra en el Listado 1. Ahora veamos cómo configurar el cliente (IdTCPClient - pestaña Clientes indios

) para que pueda interactuar con nuestro servidor. Para utilizar el componente del cliente TCP, simplemente colóquelo en el formulario (el componente tampoco se muestra).

  • Después de esto, como mínimo, debe configurar las siguientes propiedades (el resto se menciona según sea necesario en los ejemplos siguientes):
  • Host: nombre o dirección IP de la computadora en la que se ejecuta el servidor;

En general, no es necesario configurar ni siquiera estas propiedades en la etapa de desarrollo del formulario. La aplicación es mucho más flexible si, por ejemplo, se le da al usuario la oportunidad de seleccionar (o ingresar) el nombre o la dirección del servidor.

Fácil intercambio de datos

Al comenzar a trabajar con los componentes descritos en el apartado anterior IdTCPServidor Y IdTCPClient Consideremos la creación de una aplicación cliente-servidor simple, cuyas partes cliente y servidor realizan las siguientes funciones.

  • La aplicación cliente se conecta al servidor y le envía la cadena ingresada por el usuario, espera una respuesta, muestra el texto recibido del servidor y se desconecta del servidor.
  • La aplicación del servidor recibe una cadena de la aplicación del cliente y envía una respuesta (también texto), después de lo cual cierra la conexión. Además, se cuenta el número de clientes atendidos y se recuerda la dirección IP de la computadora desde donde provino la última solicitud.

La implementación tanto de aplicaciones de servidor como de cliente en nuestro caso es extremadamente sencilla. El proyecto de la aplicación del servidor se llama Servidor simple. La apariencia del formulario del servidor (mientras la aplicación se está ejecutando) se muestra en la Fig. 2.

Arroz. 2. Apariencia de un servidor sencillo

Campo de texto ( Editar) con el número de solicitudes procesadas se denomina txtCount y el campo de texto con la dirección de la última computadora atendida se denomina txtFrom . Todo el trabajo del servidor es procesar el evento Ejecutar para el componente. IdTCPServidor colocado en el formulario (adjunte este componente al puerto 12340 y establezca la propiedad Activa en Verdadero) (Listado 1).

Listado 1. Implementación de servidor simple

Procedimiento TForm1.FormCreate(Remitente: TObject); comenzar sección:= TCriticalSection.Create; fin; procedimiento TForm1.IdTCPServer1Execute(AContext: TIdContext); var strText: Cadena; comenzar //Recibir una cadena del cliente strText:= AContext.Connection.Socket.ReadLn;

//Responder AContext.Connection.Socket.WriteLn("Tomó la línea: " + strText); //Actualiza la información en el formulario del servidor (el servidor es multiproceso, //por eso usamos la sección de sincronización.Enter; Inc(procesado, 1); txtCount.Text:= IntToStr(procesado); txtFrom.Text:= AContext .Connection.Socket.Binding. PeerIP; sección.Dejar; //Cerrar la conexión con el usuario AContext.Connection.Disconnect; Al responder al cliente, el servidor solo repite la línea recibida con la adición de texto.

"Aceptado: " al principio de la línea., puede notar que incluso en el servidor más simple en cuestión, tuvimos que aplicar la sincronización al actualizar la apariencia del formulario usando la sección crítica (además debe agregar el nombre del módulo SyncObjs a la sección de usos).

Ahora veamos la implementación de la parte del cliente (proyecto Cliente simple). La apariencia de la aplicación cliente se muestra en la Fig. 2.

Arroz. 2. Apariencia del cliente

Naturalmente, para que la aplicación cliente funcione, se coloca una instancia del componente en el formulario IdTCPClient(su nombre es IdTCPClient1). La propiedad Puerto de este componente debe establecerse en 12340. Campo de texto ( Editar) para ingresar una cadena que se enviará a un lugar que no sea el servidor, denominada txtMessage . Campo de texto ( Editar) en el que se ingresa el nombre o la dirección del servidor se llama txtServer. Campo con líneas de respuesta ( Memorándum) tiene el nombre txtResults.

Todo el trabajo de la aplicación cliente se realiza con solo hacer clic en un botón. Proceso. El texto del controlador correspondiente se proporciona en listado 2.

Listado 2. Implementación de cliente simple

Procedimiento TForm1.Button1Click(Remitente: TObject); comenzar //Conéctese al servidor y envíele el comando ingresado IdTCPClient1.Host:= txtServer.Text;

IdTCPClient1.Conectar;

IdTCPClient1.Socket.WriteLn(txtMessage.Text);

txtMessage.Text:= "";

//Esperar una respuesta y cerrar la conexión txtResults.Lines.Append(IdTCPClient1.Socket.ReadLn); IdTCPServidor Y IdTCPClient1.Desconectar; fin; Eso es todo, ahora puede ejecutar el servidor y los clientes (en una cantidad arbitraria de computadoras) y observar los resultados de su trabajo.

Sólo recuerde iniciar el servidor antes de acceder a él mediante el programa cliente.

  • Código fuente. Hecho en Delphi XE.
  • Monitorear una computadora a través de la red (IdTCPServer, IdTCPClient)
  • Ahora veamos un ejemplo más interesante del uso de componentes de red.
  • IdTCPCLiente

, que puede ser útil para las personas involucradas en la administración de computadoras en red.

  • El programa del servidor se inicia previamente en la computadora monitoreada. En este ejemplo, el programa servidor permite que el programa cliente obtenga la siguiente información sobre la computadora en la que se está ejecutando (el programa servidor): resolución del monitor; profundidad de color del monitor; copia a tamaño completo de la pantalla;
  • una copia de la pantalla, reducida (o ampliada) al tamaño especificado.- obtener el valor de la profundidad de color configurada para el monitor (bits por punto);
  • obtener_pantalla- obtener una copia de la pantalla en tamaño completo;
  • get_screen: X, Y- obtener una copia de pantalla reducida a tamaño X x Y.

Primero, veamos la implementación del servidor (proyecto servidor espía). Todo el código que hace funcionar el servidor se coloca en el módulo. Unidad1.pas formas Formulario1.

El controlador de solicitudes del cliente, el procedimiento principal para el servidor, se muestra en el Listado 3.

Listado 3. Manejador de solicitudes de clientes

Procedimiento TForm1.IdTCPServer1Execute(AThread: TIdPeerThread); var strText: Cadena;

ancho, alto, i: Entero;

//el procedimiento toma una copia de la pantalla, lleva la //imagen resultante al tamaño especificado y envía la //imagen convertida al procedimiento del programa cliente SendScreen(width1: Integer; height1: Integer; Connection: TIdTCPServerConnection); var Copia de pantalla: TCanvas;

gr: TBitmap; corriente: TMemoryStream;.

rcDest, rcFuente: TRect; comenzar rcDest:= Rect(0,0,ancho1,alto1); //tamaño de imagen final rcSource:= Screen.DesktopRect; //tamaño de imagen inicial //crea un lienzo y lo adjunta al contexto del escritorio ScreenCopy:= TCanvas.Create; IdTCPServidor ScreenCopy.Handle:= GetDC(0);

//crea un objeto para almacenar una copia de la pantalla y copiar la imagen gr:= TBitmap.Create; gr.Altura:= altura1; gr.Ancho:= ancho1;

gr.Canvas.CopyRect(rcDest, ScreenCopy, rcSource);

ReleaseDC(0, ScreenCopy.Handle);

//guarda la imagen en el flujo de datos:= TMemoryStream.Create; gr.SaveToStream(corriente);

//enviar la imagen al cliente Connection.WriteStream(stream, true, true);

flujo.Borrar;

corriente.Gratis;

Si la conexión al servidor es exitosa, se ejecuta el controlador TForm1.IdTCPClient1Connected, preparando la aplicación cliente para solicitudes de datos periódicas del servidor (Listado 6).

Listado 6. Acciones realizadas al conectarse al servidor

Procedimiento TForm1.IdTCPClient1Connected(Remitente: TObject); comenzar txtServer.Enabled:= False;

cmbConnect.Caption:= "Desconectar";

//comenzamos a solicitar datos periódicamente del servidor Timer1.Enabled:= True;

//ejecuta la primera solicitud sin esperar a que se active el temporizador Timer1Timer(nil); fin;

Al desconectarse del servidor, también se realizan acciones que detienen las solicitudes de datos periódicas y colocan al cliente en un estado de espera de conexión (el estado inicial del programa) (Listado 7).

Listado 7. Acciones al desconectarse del servidor

Procedimiento TForm1.IdTCPClient1Disconnected(Remitente: TObject); comenzar txtServer.Enabled:= Verdadero;

El caso es que la compresión (en nuestro ejemplo, la resolución de la pantalla de la computadora monitoreada es mayor que el tamaño del componente imgScreen) en el lado del servidor requiere más tiempo de CPU de la computadora que ejecuta la aplicación del servidor para tomar una copia de la pantalla. Esto reduce la carga en la red al transmitir imágenes y también ahorra recursos en la computadora cliente. Pero la calidad de la imagen comprimida en este caso es algo peor que cuando proporcionamos el componente Imagen capacidad de escalar la imagen usted mismo.

Si no utiliza la compresión de imágenes en el servidor, la carga de la red aumenta al transferir una copia de tamaño completo de la pantalla y todo el trabajo de compresión de imágenes se asigna al componente imgScreen (es decir, se desperdicia tiempo adicional del procesador en el servidor). computadora del cliente). Si la resolución de la pantalla de la computadora monitoreada es alta (o cuando se monitorean varias computadoras a la vez), la máquina del cliente, si no es lo suficientemente potente, puede comenzar a "desacelerarse" notablemente. La calidad de la imagen comprimida es mayor.

Como solución más o menos efectiva, se puede proponer utilizar largos períodos de tiempo entre solicitudes de datos del servidor de seguimiento con escalado de imágenes en el lado del servidor (a menos que la máquina del servidor tenga muy baja potencia).

Código fuente. Realizado en Delphi 7.

Introducción

Este artículo está dedicado a la creación de aplicaciones de arquitectura cliente/servidor en Borland Delphi basadas en sockets (“sockets” - nidos). A diferencia del artículo anterior sobre el tema de los sockets, aquí veremos la creación de aplicaciones de servidor.

Cabe señalar de inmediato que para la coexistencia de aplicaciones de cliente y servidor independientes, no es necesario tener varias computadoras. Basta con tener solo uno en el que poder ejecutar simultáneamente tanto el servidor como el cliente. En este caso, debe utilizar el nombre del host como el nombre de la computadora a la que desea conectarse. servidor local 127.0.0.1 .

o dirección IP -

Entonces, comencemos con la teoría. Si es un practicante convencido (y no puede ver ningún algoritmo con sus ojos), debe omitir esta sección.

¿Qué te permite hacer un servidor socket?... ¿Bajo qué principio funciona?... Un servidor basado en el protocolo socket te permite atender a muchos clientes a la vez. Además, usted mismo puede especificar el límite de su número (o eliminar este límite por completo, como se hace de forma predeterminada). Para cada cliente conectado, el servidor abre un socket separado a través del cual puede intercambiar datos con el cliente.

Otra gran solución es crear un proceso separado (Thread) para cada conexión.

  • Veamos el diagrama con más detalle: Definición de propiedades Port y ServerType
  • - Para que los clientes puedan conectarse al servidor normalmente, es necesario que el puerto utilizado por el servidor coincida exactamente con el puerto utilizado por el cliente (y viceversa). La propiedad ServerType determina el tipo de conexión (consulte a continuación para obtener más detalles); Abrir un enchufe);
  • - abrir el enchufe y el puerto especificado. Aquí es donde automáticamente comenzamos a esperar a que los clientes se conecten (
  • Escuchar Conectar un cliente e intercambiar datos con él
  • - aquí el cliente se conecta e intercambia datos con él. Puede obtener más información sobre esta etapa a continuación en este artículo y en el artículo sobre sockets (parte del cliente); Deshabilitar un cliente

- Aquí el cliente se desconecta y se cierra su conexión de socket con el servidor;

Cerrar el servidor y el socket - Por orden del administrador, el servidor se apaga, cerrando todos los canales de socket abiertos y dejando de esperar conexiones de clientes. Cabe señalar que los puntos 3 y 4 se repiten muchas veces, es decir. Estos pasos se realizan para cada nueva conexión de cliente. Nota

: Actualmente hay muy poca documentación sobre sockets en Delphi, por lo que si desea estudiar este tema lo más profundamente posible, le aconsejo que consulte la literatura y la documentación electrónica sobre sistemas Unix/Linux.

Muy La teoría de trabajar con enchufes está bien descrita. Además, hay muchos ejemplos de aplicaciones de socket para estos sistemas operativos (aunque principalmente en C/C++ y Perl). Breve descripción del componente TServerSocket Aquí nos familiarizaremos con.

principal propiedades, métodos y eventos de un componente TServerSocket
Propiedades Métodos Eventos Enchufe ;
- la clase TServerWinSocket, a través de la cual se tiene acceso a canales de socket abiertos. A continuación consideraremos esta propiedad con más detalle, porque es, de hecho, uno de los principales. Tipo: TServerWinSocket Tipo de servidor - tipo de servidor. Puede tomar uno de dos valores: Y OnClientWrite. stThreadBloqueo- tipo asincrónico. Se crea un proceso separado (Thread) para cada canal de socket del cliente. Eventos Tipo de servidor T ;
Tamaño de caché de subprocesos - el número de procesos del cliente (Subprocesos) que el servidor almacenará en caché. Aquí debe seleccionar el valor promedio según la carga de su servidor. El almacenamiento en caché se produce para no crear un proceso separado cada vez y no eliminar un socket cerrado, sino dejarlo para su uso posterior. Eventos Entero ;
Activo - un indicador de si el servidor está activo en un momento determinado o no. Ese es, de hecho, el valor. Verdadero indica que el servidor está funcionando y listo para recibir clientes, y FALSO- el servidor está apagado. Para iniciar el servidor, simplemente necesita establecer esta propiedad en Verdadero. Eventos booleano ;
Puerto - número de puerto para establecer conexiones con clientes. Los puertos del servidor y del cliente deben ser los mismos. Se recomiendan valores de 1025 a 65535, porque de 1 a 1024 - puede ser ocupado por el sistema. Eventos Entero ;
Servicio - una cadena que define el servicio ( ftp, http, estallido, etc.) cuyo puerto se utilizará. Se trata de una especie de directorio de números de puertos correspondientes a varios protocolos estándar. Tipo: cadena ;
Abierto - Inicia el servidor. Básicamente, este comando es idéntico a asignar un valor. Verdadero propiedad Activo;
Cerca - Detiene el servidor. Básicamente, este comando es idéntico a asignar un valor. FALSO propiedad Activo.
OnClientConectar - ocurre cuando el cliente ha establecido una conexión de socket y está esperando una respuesta del servidor ( Al aceptar);
OnClientDesconectar - Ocurre cuando el cliente se ha desconectado del canal de socket;
OnClientError - ocurre cuando falla la operación actual, es decir
- tipo de servidor. Puede tomar uno de dos valores: ocurrió un error; - ocurre cuando el cliente ha pasado algunos datos al servidor. Se puede acceder a estos datos a través del parámetro pasable.;
OnClientWrite Zócalo: TCustomWinSocket
- ocurre cuando el servidor puede enviar datos al cliente a través de un socket; OnGetSocket - en el controlador de este evento puedes editar el parámetro;
ClienteSocket EnGetThread - en el controlador de este evento puede definir un proceso único (Thread) para cada canal de cliente individual asignando el parámetro Rosca
la subtarea deseada TServerClientThread; , OnThreadInicio Al final del hilo
Al aceptar - ocurre cuando se inicia o se detiene una subtarea (proceso, subproceso), respectivamente;
- ocurre cuando el servidor acepta al cliente o le niega una conexión; En escucha

- ocurre cuando el servidor entra en modo de espera para que los clientes se conecten.

Entonces, ¿cómo puede el servidor enviar datos al cliente? ¿Qué pasa con la recepción de datos? - tipo de servidor. Puede tomar uno de dos valores: Principalmente si estás trabajando a través de eventos. OnClientWrite Y

  • , luego puede comunicarse con el cliente a través del parámetro ClientSocket (TCustomWinSocket). Puede leer sobre cómo trabajar con esta clase en el artículo sobre sockets de cliente, porque enviar/enviar datos a través de esta clase es similar: métodos (Enviar/Recibir)(Texto,Buffer,Stream). Lo mismo se aplica cuando se trabaja con TServerSocket.Socket. Sin embargo, porque Aquí estamos considerando un servidor, debemos resaltar algunas propiedades y métodos útiles: (Entero Conexiones activas
  • ) - número de clientes conectados; (hilos activos Entero ) - número de procesos en ejecución; (Conexiones formación
    ): una matriz que consta de clases TClientWinSocket separadas para cada cliente conectado. Por ejemplo, este comando:
    ServerSocket1.Socket.Connections.SendText ("¡Hola!");
  • envía un mensaje de "¡Hola!" al primer cliente conectado. Comandos para trabajar con elementos de esta matriz - también (Enviar/Recibir)(Texto,Buffer, Stream); (Entero Hilos inactivos Tamaño de caché de subprocesos);
  • ) - el número de procesos libres. Estos procesos son almacenados en caché por el servidor (ver, Dirección local, Anfitrión local Puerto local
  • - respectivamente - dirección IP local, nombre de host, puerto;, Dirección remota, Host remoto Puerto remoto
  • - respectivamente - dirección IP remota, nombre de host, puerto; Métodos Y Cerrar Descubrir

- respectivamente, bloquear y desbloquear la toma.

Práctica y ejemplos

Ahora veamos lo anterior usando un ejemplo específico. Puede descargar fuentes listas para usar haciendo clic.

Entonces, veamos un muy buen ejemplo de cómo trabajar con TServerSocket (este ejemplo es la ayuda más visual para estudiar este componente). Las fuentes a continuación demuestran el registro de todos los eventos importantes del servidor, además de la capacidad de recibir y enviar mensajes de texto: Ejemplo 1.

Registro y estudio del funcionamiento del servidor, envío/recepción de mensajes mediante sockets. (...aquí va el encabezado del archivo y la definición del formulario TForm1 y su instancia Form1) (Ver fuente completa) procedimiento TForm1.Button1Click (Remitente: TObject); comenzar (Determine el puerto e inicie el servidor) ServerSocket1.Puerto:= 1025; (El método Insert inserta una cadena en la matriz en la posición especificada) Memo2.Lines.Insert(0,"Servidor iniciando"); ServerSocket1.Open; Memo2.Lines.Insert(0,"Escuchando en el puerto "+IntToStr(ServerSocket1.Port)); fin; procedimiento TForm1.ServerSocket1Accept(Remitente: TObject; Socket: TCustomWinSocket); comenzar (Aquí el servidor acepta al cliente) Memo2.Lines.Insert(0,"Conexión de cliente aceptada"); fin; procedimiento TForm1.ServerSocket1ClientConnect(Remitente: TObject; Socket: TCustomWinSocket); comenzar (Aquí el cliente se conecta) Memo2.Lines.Insert(0,"Cliente conectado"); fin; procedimiento TForm1.ServerSocket1ClientDisconnect(Remitente: TObject; Socket: TCustomWinSocket); comenzar (Aquí el cliente se desconecta) Memo2.Lines.Insert(0,"Cliente desconectado"); fin; procedimiento TForm1.ServerSocket1ClientError(Remitente: TObject; Socket: TCustomWinSocket; ErrorEvent: TErrorEvent; var ErrorCode: Integer); comenzar< "+Edit1.Text); end;

(Ocurrió un error; muestra su código)

Memo2.Lines.Insert(0,"Error del cliente. Código = "+IntToStr(ErrorCode));

Seguramente, si su servidor atenderá a muchos clientes, necesitará almacenar cierta información para cada cliente (nombre, etc.) y vincular esta información al socket de este cliente. En algunos casos, hacer todo esto manualmente (vincularse a un identificador de socket, matrices de clientes, etc.) no es muy conveniente. Por lo tanto, para cada enchufe hay una propiedad especial: Datos. De hecho, los datos son sólo un indicador. Por lo tanto, al escribir datos del cliente en esta propiedad, tenga cuidado y siga las reglas de trabajo con punteros (asignación de memoria, definición de tipo, etc.).

Envío de archivos vía socket.

Aquí veremos el envío de archivos a través de un socket (a petición de JINX) :-).

Entonces, ¿cómo se envía un archivo a través de un socket? ¡Muy sencillo! ¡Todo lo que tiene que hacer es abrir este archivo como una secuencia de archivos (TFileStream) y enviarlo a través de un socket (SendStream)! Veamos esto con un ejemplo: Cabe señalar que el método Enviar flujo utilizado no solo por el servidor, sino también por el cliente ()

ClientSocket1.Socket.SendStream(archivosrc)

¿Por qué se pueden combinar varios bloques en uno durante la transmisión?
Esto también es a petición de JINX :-). ¡Muchas gracias a él por esto! Entonces, en primer lugar, cabe señalar que los datos enviados a través de un socket no sólo pueden combinarse en un bloque, sino también separarse en varios bloques.
El hecho es que un socket es un flujo normal, pero a diferencia de, digamos, un flujo de archivos (TFileStream), transfiere datos más lentamente (comprende: red, tráfico limitado, etc.). Por eso dos comandos:
ServerSocket1.Socket.Connections.SendText("Hola, ");
ServerSocket1.Socket.Connections.SendText("¡mundo!");

completamente idéntico a un comando: ServerSocket1.Socket.Connections.SendText ("¡Hola mundo!"); Y es por eso que, si envía un archivo de, digamos, 100 KB a través de un socket, la persona a quien le envió este bloque recibirá varios bloques con tamaños que dependen del tráfico y la congestión de la línea. Además, los tamaños no serán necesariamente los mismos. De ello se deduce que para aceptar un archivo o cualquier otro dato de gran tamaño, debe aceptar bloques de datos y luego combinarlos en un todo (y guardarlos, por ejemplo, en un archivo). Una excelente solución a este problema es la misma secuencia de archivos: TFileStream (o una secuencia en la memoria: TMemoryStream). Puede recibir datos de un socket a través del evento OnRead (OnClientRead) utilizando el método universal RecibirBuf. También puede utilizar una secuencia de socket (consulte el artículo sobre TClientSocket). Y aquí hay un pequeño ejemplo (aproximado):

Cómo monitorear un enchufe

Esta cuestión es compleja y requiere una larga consideración. Por ahora, solo señalaré que siempre puedes monitorear el socket creado por tu programa :-).

Los sockets (como la mayoría de los objetos en Windows) tienen su propio identificador, escrito en la propiedad Handle. Entonces, una vez que reconozca este descriptor, podrá administrar libremente cualquier socket (incluso uno creado por el programa de otra persona). Sin embargo, lo más probable es que para controlar el socket de otra persona tenga que utilizar exclusivamente las funciones de WinAPI Sockets.

Epílogo Este artículo muestra las técnicas básicas para trabajar con el componente TServerSocket en Delphi y varias técnicas generales para intercambiar datos a través de sockets. Si tienes preguntas, envíamelas por correo electrónico:[correo electrónico protegido]

, y mejor aún: escriba en la conferencia de este sitio (Delphi. Preguntas generales) para que otros usuarios puedan ver su pregunta e intentar responderla. Karikh Nikolai ( nitro

). Región de Moscú, Zhukovsky

Enviar trabajo al sitio.

Los estudiantes, estudiantes de posgrado y jóvenes científicos que utilicen la base de conocimientos en sus estudios y trabajos le estarán muy agradecidos. Publicado en

http://www.allbest.ru/

PRUEBADesarrollo de una aplicación cliente-servidor enD

elfi

Descripción general de los componentes

Para trabajar con ADO, hay seis componentes en la pestaña Componentes de ADO: TADOConnection, TADOCommand, TADODataSet, TADOTable, TADOQuery, TADOStoredProc.

Arroz. 1. Paleta de componentes ADO

TADOConnection se utiliza para especificar la base de datos y trabajar con transacciones.

TADOTable es una tabla accesible a través de ADO.

TADOQuery: consulta a la base de datos. Puede ser una consulta que devuelve datos y bases de datos (por ejemplo, SELECT) o una consulta que no devuelve datos (por ejemplo, INSERT).

TADOStoredProc: llama a un procedimiento almacenado.

La diferencia entre ellos es que el comando ejecutado a través de TADODataSet debe devolver un conjunto de datos y este componente permite trabajar con ellos usando herramientas Delphi (por ejemplo, vinculando un componente de tipo TDataSource). Y el componente TADOCommand le permite ejecutar comandos que no devuelven un conjunto de datos, pero no tienen herramientas estándar de Delphi para el uso posterior del conjunto de datos devuelto.

Obviamente, todos los componentes deben comunicarse con la base de datos. Esto se hace de dos maneras, ya sea a través del componente TADOConnection o especificando directamente la base de datos en otros componentes. Otros componentes están vinculados a TADOConnection mediante la propiedad Connection y a la base de datos directamente a través de la propiedad ConnectionString.

algoritmo de base de datos de programación

Tabla 1. Componentes principales de la pestaña ADO

Nombre

Propiedades básicas

Comentarios

Responsable de la comunicación con la base de datos.

Cadena de conexión

Contiene configuraciones para conectarse a la base de datos.

se utiliza para especificar si se muestra un cuadro de diálogo para ingresar una identificación de usuario y contraseña al conectarse a la base de datos;

indica la actividad de la conexión: Verdadero significa que la conexión está abierta, Falso significa cerrada;

Métodos básicos

Comentarios

se utiliza para iniciar una nueva transacción y devuelve el nivel de transacciones anidadas;

cierra la conexión actualmente abierta

escribe todos los cambios realizados por la transacción actual en la base de datos y la finaliza

Se utiliza para ejecutar consultas o procedimientos almacenados. La declaración ejecutable se pasa a este método mediante un parámetro;

abre una conexión a la fuente de datos especificada en ConnectionString

descarta todos los cambios realizados desde la última llamada al método BeginTrans y finaliza la transacción sin guardar los cambios.

Propiedades básicas

Comentarios

TADOQuery Diseñado para trabajar con consultas.

Diseñado para trabajar con procedimientos almacenados

Contiene el nombre del componente ADOConnection.

Contiene el nombre del procedimiento almacenado.

Algoritmo de trabajo

1. Cree un nuevo DataModule. Seleccione el elemento del menú Archivo\Nuevo\DataModule. Lo llamamos DM.

Lanzamos los componentes ADOConnection, ADOQuery y tres ADOStoredProcedure en el DM. Consulte la Fig. 2 para ver cómo se ve.

Fig.2 Ver DM

2. Establecer las propiedades del componente

ADOConnection: consulte el manual.

Cambie el nombre de ADOQuery 1 a QVrash y escriba la consulta en la propiedad SQL:

Seleccione * de Vrash

La propiedad Conexión es ADOConnectionl.

Cree campos estáticos para QVrash.

Para el componente ADOStoredProcl configuramos las siguientes propiedades

* Nombre - ASPInsVrash

* Conexión - ADOConexión 1

* Nombre del procedimiento - MainInsert; 1

Si hace clic en la propiedad Parámetros, verá los parámetros que pasaremos al procedimiento.

Para el componente ADOStoredProc2 configuramos las siguientes propiedades

* Nombre - ASPEdVrash

* Conexión - ADOConnectionl

* Nombre del procedimiento - Edición principal; 1

Para el componente ADOStoredProc3, establezca las siguientes propiedades

* Nombre - ASPDelVrash

* Conexión - ADOConnectionl

* Nombre del procedimiento - MainDelete; 1

Coloque los componentes DBGrid, dos botones, DataSource, MainMenu en el formulario 1

Fig3. Formulario 1

Cambie el nombre de los botones según la imagen.

Para el botón Actualizar código

DM.QVrash.Cerrar; //actualización n/a

Creando un menú

Arroz. 3. Editar menú

Cree un formulario para agregar/editar: Componentes EDITAR

código de programapara elemento de menúen el formulario 1-APÉNDICE

Form3.Edit1.text:="";

Form3.Edit2.text:="";

Form3.Edit3.text:="";

Form3.Edit4.text:="";

Formulario3.showmodal;

Código de programa para el botón.en el formulario 3-INSERTAR

Bcomenzar

showmessage("No todos los campos están completos");

miDakota del Norte;

try

DM.ADOConnection1.BeginTrans;

con DM.ASPInsVrash hacer

Parámetros.ParamByName("@ID_Physician").Valor:=StrToInt(Edit1.text);

Parámetros.ParamByName("@AAAA`).Valor:=Edit2.Text;

Parámetros.ParamByName("@AAAA ").Valor:=Edit3.Text;

Parámetros.ParamByName("@AAAA ").Valor:=Edit4.text;

DM. ASPInsVrash.ExecProc;

miexcepto

DM. QVrash.Cerrar;

DM. QVrash.Abierto;

Los estudiantes, estudiantes de posgrado y jóvenes científicos que utilicen la base de conocimientos en sus estudios y trabajos le estarán muy agradecidos. Publicado en

Código de programa para el elemento del menú en el formulario 1 - EDITAR

Bcomenzar//Edición

n:=DM. QVrash.XXXXX.Valor;

DM. QVrash.Cerrar;

DM. QVrash.Abierto;

DM. QVrash.Locate(XXXX,n,);

Form3.Label6.Caption:=IntToStr(DM.QVrash.XXXXXvalue);

Form3.Edit1.text:=inttostr(DM.QVrashYYYYYY.Value);

Form3.Edit2.text:=inttostr(DM.QVrashYYYYY.Value);

Form3.Edit3.text:=floattostr(DM.QVrashYYYYY.Value);

Form3.Edit4.text:=DateToStr(DM.QVrash.YYYY.Value);

Formulario3.Showmodal;

DM. QVrash.Cerrar;

DM. QVrash.Abierto;

Código de programa para el botón en el formulario 3 - EDITAR

Bcomenzar

Si (Edit1.text="") o (Edit2.Text="") o (Edit3.Text="") o (Edit4.Text="") entonces

Bcomenzar

ShowMessage("No todos los campos están completos");

miDakota del Norte;

try

DM.ADOConnection1.BeginTrans;

con DM.ASPEdVrash hacer

Parámetros.ParamByName("@XXXX).Value:= DM.a QVrash.XXXXX.value;

Parámetros.ParamByName("@AAAA).Valor:=Edit1.text;

Parámetros.ParamByName("@YYYYY).Valor:=Edit2.Text;

Parámetros.ParamByName("@AAAA").Valor:=Edit3.Text;

Parameters.ParamByName("@AAAA).Value:=StrToDate(Edit4.text);

DM.ASPEd.ExecProc;

DM.ADOConnection1.CommitTrans;

miexcepto

DM.ADOConnection1.RollbackTrans;

ShowMessage("No se puede completar. Inténtelo de nuevo.");

DM. QVrash.Cerrar;

Código de programa para el elemento del menú en el formulario 1: BORRAR

Comenzar// Borrar

si MessageDlg("¿Está seguro de que desea eliminar la entrada?", mtConfirmation,,0)=mrYes entonces

DM.ASPDel.Parameters.ParamByName("@XXXX).Value:=DM.ADOQuery1XXXXX.Value;

try

DM.ADOConnection1.BeginTrans;

DM.ASPDelVrash.ExecProc;

DM.ADOConnection1.CommitTrans;

miexcepto

ShowMessage("¡Error al eliminar!"+#13+"¡La entrada está bloqueada o ya ha sido eliminada!");

DM.ADOConnection1.RollbackTrans;

misalir;

DM. QVrash.Cerrar;

DM. QVrash.Abierto;

Publicado en Allbest.ru

Documentos similares

    Desarrollo de un sistema de información de gestión administrativa. Elegir un lenguaje y entorno de programación. Estructura de la interacción de la información. Requisitos para el entorno de software y hardware. Crear un programa en Delphi y vincularlo a una base de datos.

    trabajo del curso, añadido el 08/10/2015

    Borland Delphi 7 como herramienta de desarrollo universal utilizada en muchas áreas de programación, funciones: agregar información sobre los solicitantes a la base de datos, generar informes. Consideración y características de los principales componentes de Delphi.

    prueba, agregada el 18/10/2012

    Desarrollo de software para trabajar con información y su procesamiento en el lenguaje de programación Delphi. Descripción de algoritmos para trabajar con una pila: agregar, eliminar elementos, editar un registro. Instrucciones para utilizar el programa.

    trabajo del curso, añadido el 06/02/2013

    Consideración de las características del entorno de programación Delphi, análisis de la versión cliente-servidor. Introducción a la biblioteca de componentes visuales. Funciones básicas del editor inteligente. Características de los requisitos de la base de datos. Funciones del programa de Maestría.

    tesis, agregada el 10/03/2013

    Características del sistema de programación. Los principales componentes de Delphi. Interfaz de la aplicación de software. Resultados del programa. Guía del operador y programador del sistema. Lenguaje de programación Delphi, entorno compilador Borland 7.0.

    trabajo del curso, añadido el 29/05/2013

    Redacción de un programa para trabajar con clientes utilizando el lenguaje Delphi, que permite ingresar, editar y eliminar información. Desarrollo de un algoritmo para la resolución del problema, descripción de variables, procedimientos auxiliares, datos de entrada y salida.

    trabajo del curso, añadido el 21/09/2010

    Características generales del sistema de programación Delphi, así como principios para la creación de sus componentes. Descripción de los valores del archivo de una aplicación creada con Delphi. Estructura y propiedades de la Biblioteca de Componentes Visuales (VCL).

    informe de práctica, añadido el 07/12/2010

    Diseño y creación de interfaz de usuario y programación visual en entorno Delphi. Sistema de gestión de bases de datos. Vistas de usuarios locales y globales. Análisis de dominio. Finalidad de formularios y componentes.

    trabajo del curso, añadido el 07/03/2014

    Historia del entorno de desarrollo integrado, versión de Delphi. Organización de una biblioteca de componentes. Página adicional, una serie de componentes de uso general de uso común. Archivo ejecutable del programa "Text File Archiver", interfaz de la aplicación.

    trabajo del curso, agregado 16/05/2017

    Desarrollo de productos de software en el lenguaje de programación Borland Delphi. Las tablas utilizadas y las relaciones entre ellas. Interfaz de usuario para trabajar con la base de datos. Algoritmo para el programa "Equipos y jugadores de fútbol". Protección contra la entrada de datos incorrecta.




Arriba