Introduzione all'India. Un esempio di lavoro con i componenti Indy UDP (server, client) in Delphi

Introduzione all'India. Un esempio di lavoro con i componenti Indy UDP (server, client) in Delphi

Componenti Indy utilizzati in Delphi 6.

Oltre ai servizi e ai protocolli Internet di base, esiste un'ampia gamma di servizi aggiuntivi, le cui capacità sono spesso utilizzate dagli sviluppatori di Internet. Inoltre, la possibilità di visualizzare le informazioni utilizzando un browser non è sempre una soluzione accettabile per le applicazioni Internet. In questo caso, è ragionevole utilizzare l'infrastruttura Internet per lo scambio di dati e fornire la visualizzazione delle informazioni attraverso applicazioni client più complesse sviluppate, ad esempio, in Delphi.

Si supponga di voler implementare una logica lato server personalizzata che non sia incorporata nei server Web standard. Per risolvere questa classe di problemi, Delphi include la libreria Internet Direct (Indy) di Nevrona Designs (http://www.nevrona.com/Indy/). Questa libreria, sviluppata appositamente per Borland Delphi, ha otto versioni, l'ultima delle quali è stata inclusa nella nuova versione di Delphi. L'insieme dei componenti è suddiviso in tre gruppi: client (Indy Client), server (Indy Server) e ausiliario (Indy Misc).

Indy Client e Indy Server

La maggior parte dei componenti di Indy Client e Indy Server sono coppie corrispondenti alle parti client e server dei protocolli e dei servizi (ad eccezione di componenti separati, principalmente server, come TunnelMaster e TunnelSlave) e consentono l'uso di protocolli come come TCP/IP, UDP, NNTP, SMTP, FTP, HTTP, così come ECHO, FINGER, WHOIS, ecc.

I componenti client di Indy sono scritti utilizzando i socket. Il socket lato client richiede una connessione al server. Se viene stabilita la comunicazione, il client e il server possono iniziare a scambiare messaggi. Questi messaggi sono di natura diversa, ma solitamente lo scambio avviene secondo un protocollo specifico (ad esempio HTTP)

TIdTCPClient e TIdTCPServer

Questi componenti sono utilizzati per supportare uno dei principali protocolli di rete - ТСР (Transmission Control Protocol), e sono anche le classi base per i componenti TIdSMTP e TIdFTP. La classe TIdTCPServer ha una proprietà ThreadMgr, che è zero per impostazione predefinita. Se ThreadMgr è nullo quando TIdTCPServer è attivato, la classe TIdThreadMgrDeafault verrà creata implicitamente. In caso contrario, viene utilizzato il gestore processi installato.

TIdUDPClient e TIdUDPServer

Questi componenti vengono utilizzati per supportare la rete UDP (User Datagram Protocol) e sono anche le classi base per una serie di altri componenti Indy.

TIdChargenServer

Il componente viene utilizzato per generare caratteri casuali, solitamente a scopo di test.

TIdDayTime e TIdDayTimeServer

I componenti vengono utilizzati per fornire un servizio temporale. Il client richiede e il server riporta la data e l'ora correnti.

TIdDNSRosolver

È un componente client che serve le richieste da un server DNS (Domain Name Service). Le query del server DNS sono progettate per sostituire il nome del computer con il relativo indirizzo IP. TIdDNSResolver eredita dalla classe TIdUDPClient.

TIdDICTServer

Il componente server che supporta il Dictionary Server Protocol (DICT) è un dizionario lato server basato su TCP che consente a un client di accedere a un dizionario in linguaggio naturale.

TIdDISCARDServer

Il componente server che supporta il server di registrazione. I record possono essere utilizzati come strumento per il debug e la misurazione. Il Servizio di Registrazione trasferisce semplicemente qualsiasi dato a chi è disposto a riceverlo.

TI dEcho e TI dECHOServer

I componenti sono progettati per fornire un servizio reattivo, in genere utilizzato per testare l'integrità di una rete. Il client invia un messaggio di testo al server, il server restituisce il messaggio al client. Se il messaggio è confuso, la rete non funziona correttamente.

TIdFinger e TIdFingerServer

I componenti sono progettati per fornire un protocollo che consente a un utente di interrogare i dati relativi alla presenza di altri utenti nel sistema. Alcuni server gestiscono tali richieste dei client. L'utilizzo di questa coppia di componenti ti consentirà di soddisfare le richieste dei client che scoprono se altri utenti sono nel sistema.

Il componente include il supporto completo per il File Transfer Protocol (FTP). Supporta il trasferimento di dati passivo e attivo, nonché operazioni come GET e PUT, eliminazione di directory, acquisizione di quote, dimensioni di file e directory. TI dFTP utilizza la classe TIdSimpleServer nel suo lavoro. Quando è in corso un trasferimento di file FTP, una connessione TCP secondaria è aperta per il trasferimento dei dati e chiusa quando i dati sono stati trasferiti. Questa connessione è chiamata "collegamento dati", che è univoco per ogni file trasferito.

TIdGopher e TIdGopherServer

Questi componenti sono progettati per fornire un protocollo di rete recentemente sostituito dal WWW (World Wide Web) dal protocollo HTTP. Il server che implementa questo protocollo fornisce un sistema di supporto del flusso di lavoro distribuito gerarchicamente. Un esempio di utilizzo di questa coppia di componenti, che si trova nelle directory demosindyGopherClient e demosindy GopherServer, dimostra come questo protocollo può essere utilizzato per fornire informazioni sulla rete locale sui file sul computer, inclusi quelli chiusi.

TIdHostNameServer

Componente del server utilizzato per passare il nome del server locale ai client.

TIdHTTP e TIdHTTPServer

I componenti vengono utilizzati per fornire il protocollo di rete HTTP (sono supportate le versioni 1.0 e 1.1, incluse le operazioni GET, POST e HEAD). Fornisce inoltre supporto per l'autenticazione e l'utilizzo di server proxy. Il componente server viene utilizzato per fornire servizi a un altro server Web che supporta questo protocollo. TIdHTTPServer semplifica l'implementazione di funzionalità come cookie, gestione dello stato e altro.

TIdIcmpClient

Un componente client progettato per fornire Internet Control Message Protocol (ICMP), che esegue il ping e la traccia della rete.

Un componente client progettato per fornire Post Office Protocol (POP), incluso il supporto per la codifica e decodifica MIME e la trasmissione di caratteri multibyte.

TIdIMAP4Server

Un componente server progettato per supportare le operazioni IMAP (Internet Message Access Protocol) su un server. Il protocollo consente di cercare messaggi di posta elettronica sul server. La differenza tra IMAP e POP è che POP richiede memoria aggiuntiva per archiviare i dati e IMAP indirizza il server anziché la macchina client. IMAP4 è stato creato per sostituire POP3, ma POP3 rimane uno standard ampiamente utilizzato fino ad oggi.

TIdIRCServer

Un componente server progettato per supportare le operazioni di servizio più comunemente utilizzate su Internet, comunemente chiamate chat. Il componente fornisce gli elementi costitutivi di base per un server IRC (Internet Relay Chat).

TIdMappedPortTCP

Componente server per la creazione di porte mappate, spesso utilizzate nei server proxy. I metodi di questo componente consentono di mappare una porta su un'altra. Ad esempio, la porta 80 può essere mappata alla porta 3000 e tutte le richieste alla prima porta (porta 80) verranno inoltrate alla seconda porta (porta 3000).

TIdNNTP e TIdNNTPServer

Questi componenti sono necessari per supportare il Network News Transfer Protocol (NNTP) utilizzato nei servizi di notizie. Il componente client include il supporto per la codifica e la decodifica MIME, nonché il supporto per caratteri multibyte e codifiche alternative. Il componente server ti consente di creare server di notizie. È importante notare che TIdNNTPServer non è un server di notizie completamente funzionante, ma un componente che fornisce le funzionalità di base per tale server.

TIdQOTD e TIdQOTDServer

I componenti vengono utilizzati per fornire un servizio Preventivo del Giorno. Il componente client si connette all'istanza del componente server per recuperare il preventivo giornaliero. Ogni istanza del server contiene un database univoco di citazioni.

Un componente client progettato per l'uso in applicazioni SMTP (Simple Mail Transfer Protocol), che fornisce supporto per autenticazione, codifica e decodifica MIME e supporto per caratteri multibyte.

Un componente client progettato per fornire Simple Network Time Protocol (SNTP), un servizio orario. Può essere utilizzato per connettersi a qualsiasi servizio orario per determinare la data e l'ora correnti.

TIdSimpleServer

Componente server che fornisce un server TCP leggero. Consente di organizzare una connessione punto-punto. Viene utilizzato per creare server con un singolo utente, ovvero può servire solo una connessione alla volta. A differenza del componente TIdTCPServer, non genera processi secondari durante l'attesa di richieste dai client e durante l'elaborazione di tali richieste. In altre parole, se il server serve una richiesta da un client e in questo momento un altro client lo contatta per connettersi, verrà bloccato fino alla fine dell'elaborazione della prima richiesta.

TIdTelnet e TIdTelnetServer

Il componente client viene utilizzato per stabilire sessioni remote su un altro computer, inclusa la negoziazione e l'autenticazione della console. Il protocollo di comunicazione presuppone la presenza di una persona che interagisce con il server in modo interattivo. Il componente client non ha il supporto per la visualizzazione e l'emulazione di terminale, ma fornisce semplicemente una connessione al lato server. In genere, il protocollo server TIdTelnetServer viene utilizzato per organizzare database remoti con un'interfaccia basata su testo per la comunicazione interattiva con i client.

TIdTime e TIdTimeServer

Il componente client è un'alternativa al componente TIdSNTP per la temporizzazione. È importante notare che i formati di questi due protocolli sono diversi. TIdTime è basato sul formato RFC 868 (restituisce l'ora nello standard del sistema operativo UNIX interno, effettuando tutte le conversioni necessarie). Il componente server è simile in funzione al server DayTime. Può essere utilizzato per implementare un servizio orario su un computer locale. Non è richiesto alcun codice aggiuntivo, è sufficiente creare un'istanza di TIdTimeServer, che restituirà l'ora dell'orologio interno del computer server.

TIdTrivialFTP e TIdTrivialFTPServer

Questi componenti sono necessari per organizzare il protocollo di trasferimento file più semplice. Il componente client di questo protocollo viene utilizzato per connettersi a un'istanza del componente server corrispondente. Il protocollo è destinato a casi privati, leggeri e locali di trasferimento di file, ad esempio nelle reti locali o per caricare (scaricare) tabelle di routing nei router. A causa delle caratteristiche indebolite di questo protocollo, il suo utilizzo non è raccomandato nel caso di utilizzo di algoritmi di autenticazione o altri meccanismi di sicurezza. Lo scopo principale di questo protocollo è trasferire file su un dispositivo hardware per modificarlo.

TIdTunnelMaster e TIdTunnelSlave

I componenti del tunnel lato server vengono utilizzati nei server proxy per organizzare più connessioni logiche su una singola connessione fisica (tunnel). Queste classi possono essere utilizzate per vari scopi, ad esempio per organizzare una connessione segreta su canali non classificati.

TIdWhois e TIdWhoIsServer

Questo componente client si connette a qualsiasi server Whois standard che fornisce informazioni sul dominio. Il componente server fornisce le funzionalità di base del server NIC.

Indy misc

La pagina della tavolozza Indy Misc (Indy Miscellaneous Components) include BASE64, UUE, Quoted Printable e altri comuni formati di comunicazione e-mail, codificatori (MD2, MD4 e MD5) per standard di crittografia, utilizzati per memorizzare password e firme elettroniche in modo irreversibile (difficile per decifrare) form, così come molti altri componenti e utilità utili che vengono spesso utilizzati nello sviluppo di applicazioni Internet.

TIdAntigelo

A causa degli algoritmi basati su blocchi nei componenti Indy, è spesso il caso che l'applicazione "si blocchi" mentre la connessione è in esecuzione. Per escludere l'uso di processi secondari (thread) durante l'organizzazione delle comunicazioni per impedire il blocco (blocco) dell'applicazione, è sufficiente posizionare il componente specificato nel modulo.

Il componente funziona analizzando le richieste dallo stack del protocollo TCP/IP e inviando messaggi all'applicazione durante il ritardo quando le connessioni esterne sono bloccate, creando l'illusione di eseguire codice. Poiché il componente interessa le connessioni bloccate solo per il processo principale, non è richiesto l'utilizzo di TIdAntiFreeze nei processi secondari dell'applicazione. Va ricordato che il componente TIdAntiFreeze rallenta il lavoro delle connessioni, poiché il lavoro del processo principale viene periodicamente interrotto per elaborare i messaggi. Quindi, ne consegue che è necessario fare attenzione che l'applicazione sviluppata non impieghi troppo tempo nell'elaborazione dei messaggi, inclusi OnClick, OnPaint, OnResize, ecc. L'utilizzo di questo componente è facoltativo, ma consente di risolvere il problema della sincronizzazione delle connessioni con l'interfaccia visiva dell'applicazione.

TIdDateTimeStamp

Una classe per eseguire operazioni matematiche su data e ora a causa del fatto che i protocolli Internet utilizzano formati di data e ora diversi; inoltre, client e server possono trovarsi in fusi orari diversi.

TIdIPWatch

È un componente basato su timer che monitora costantemente i cambiamenti nell'indirizzo IP del computer. Gli eventi del componente vengono generati quando viene rilevata una modifica. Il componente specificato viene solitamente utilizzato per rilevare il fatto che un computer è connesso a Internet oa qualsiasi altra rete. La modifica dell'indirizzo IP in questa situazione può essere dovuta all'assegnazione dell'indirizzo IP da parte del server DHCP (Dynamic Host Configuration Protocol) durante la connessione alla nuova rete.

TIdLogDebug

Lo scopo di questo componente è intercettare gli eventi di qualsiasi componente client o server e scrivere un record di evento nel file specificato. Questo componente è molto utile per il debug dei componenti di Indy.

TIdMessage

Il componente viene utilizzato in combinazione con altri componenti per decrittografare o codificare correttamente i messaggi. Questi possono essere componenti POP, SMTP e NNTP. La classe supporta la crittografia e la decrittografia MIME, i caratteri multibyte e la codifica ISO.

TIdNetworkCalculator

Uno dei pochi componenti Indy che puoi utilizzare durante la creazione di applicazioni. Il calcolatore di rete può essere utilizzato per calcoli eseguiti su indirizzi IP, incluse maschere di rete, sottoreti, classi di rete, ecc.

TIdThreadMgrDefault

Il componente fornisce la gestione dei processi secondari per impostazione predefinita. Generato quando un'istanza della classe TIdThreadManager non è definita per nessun componente Indy che supporta la gestione dei processi. Il componente fornisce solo funzionalità di base per la gestione dei processi secondari: li crea e li distrugge su richiesta.

TIdThreadMgrPool

Componente di gestione dei processi più avanzato rispetto a TIdThreadMgrDefault perché raggruppa i processi anziché crearli o eliminarli su richiesta.

TIdVCard

VCard - l'equivalente elettronico di un biglietto da visita, può contenere informazioni personali del proprietario, dati grafici.

TIdIMFDecoder

Progettato per decodificare i messaggi Internet. Eredita dalla classe TIdCoder, come tutti gli altri componenti dell'encoder. La classe TIdCoder esegue la decodifica secondo l'ARPA RFS-822 Internet Text Message Format, proposto nell'agosto 1982, e lo standard di scambio di messaggi RFC 1036 USENET, proposto nel dicembre 1987.

Il componente estende le capacità della classe TIdCoder consentendo il rilevamento del formato RFS-822 dal contesto delle intestazioni, fornendo modalità di decrittazione alla ricezione e crittografia e decrittografia MIME. Il componente TIdIMFDecoder viene utilizzato nella classe TIdMessageClient per decodificare i messaggi ricevuti e trasmessi.

TIdQuotedPrintableEncoder

QuotedPrintableEncoder consente di decifrare il testo nel formato specificato. Può fungere da componente autonomo con un tipo di codifica specificato, che consente l'invio di messaggi contenenti un nuovo tipo di codifica.

Codificatore TIdBase64

Implementa un altro algoritmo di crittografia che consente di trasferire caratteri non stampabili.

TIdUUEcoder

Implementa uno dei primi algoritmi di cifratura, la codifica UU. A volte utilizzato quando si pubblicano articoli nel servizio di notizie.

TIdXXEncoder

Questo metodo di crittografia non verrà quasi mai utilizzato. Fondamentalmente, questa è la stessa codifica UU, ma con una tabella di crittografia diversa.

TIdCoderMD2

Componenti con diverse varietà dell'algoritmo di crittografia MD (Message Digest). Tutti sono basati sullo shuffling, sono unidirezionali e non hanno algoritmi di decrittazione.

I componenti di client e server di protocollo possono essere utilizzati per sviluppare applicazioni Internet server e client, insieme o al posto dei componenti di base (ClientSocket, ServerSocket) e di altri componenti della palette Internet e Fastnet. I componenti Indy non utilizzano l'architettura WebBroker, implementando il supporto di basso livello per protocolli e servizi Internet direttamente nel loro codice sorgente (codice sorgente incluso).

TIdConnectionInterceptOpenSSL e TIdServerInterceptOpenSSL

Il protocollo Secure Sockets Layer (SSL), che garantisce la segretezza e l'affidabilità della comunicazione tra due applicazioni, ha due livelli. Al livello basso di un protocollo di trasporto a più livelli (come TCP), SSL è un protocollo di registrazione e viene utilizzato per incapsulare vari protocolli di livello superiore. Il vantaggio di SSL è che è un protocollo indipendente dall'applicazione e un protocollo di livello superiore può essere utilizzato su SSL.

SSL fornisce la sicurezza delle comunicazioni, che ha tre funzioni principali: protezione di una connessione riservata; crittografia a chiave pubblica (utilizzata per confermare l'identità del destinatario); supporto per l'affidabilità della trasmissione dei dati.

  • La crittografia simmetrica viene utilizzata per crittografare i dati (ad es. DES, RC4, ecc.).
  • La firma digitale è protetta mediante crittografia a chiave pubblica asimmetrica (es. RSA, DSS, ecc.).
  • L'affidabilità della comunicazione, il trasporto del messaggio include il controllo dell'integrità del messaggio tramite codici di correzione MAC, funzioni hash sicure (ad es. SHA, MD5, ecc.) utilizzando calcoli MAC.

In combinazione con l'autenticazione HTTP e server, SSL fornisce la funzionalità di crittografia richiesta e mantiene ulteriormente la connessione stabilita verificando nuovamente l'identità del server Web, ecc. È importante capire che SSL protegge solo la comunicazione durante il trasferimento dei dati e non sostituisce altri meccanismi di sicurezza.

I componenti TIdConnectionInterceptOpenSSL e TIdServerInterceptOpenSSL forniscono la connessione sia lato client che lato server secondo il protocollo SSL. Da notare che i componenti TIdConnectionInterceptOpenSSL e TIdServerInterceptOpenSSL sono presenti solo in Delphi 6, e sono assenti in Kylix. Ciò è dovuto alla complessità del protocollo, che nel caso di un'implementazione Windows si basa sulle funzioni del sistema operativo.

Esempi di utilizzo dei componenti Indy possono essere trovati nelle directory / Delphi6 / Demos / Indy. In totale, la libreria Indy nella versione 8.0 contiene 69 componenti. Si afferma che nella versione 9.0 la libreria specificata conterrà 86 componenti. Tutti i componenti sono unificati e inclusi sia in Delphi 6 che in Kylix, il che consente loro di essere utilizzati per lo sviluppo di applicazioni multipiattaforma. Tutti i componenti di Indy supportano il multithreading.

I componenti Indy implementano quasi tutte le funzionalità disponibili nei componenti Internet e Fastnet, come chiaramente mostrato nella tabella.

Fastn e componenti Componenti Indy Scopo dei componenti
1 TserverSocket, TClientSocket TIdTCPserverSocket, TIdTCPClientSocket Interazione di due computer (client e server) utilizzando il protocollo TCP/IP
2 TNMGiornoOra TIdDayTime, TIdDayTimeServer Richiesta del server per l'ora corrente
3 TNMEcho TIdEcho, TIdEchoServer Utilizzato per comunicare con il server di risposta
4 TNMFinger TIdFinger, TIdFingerServer Utilizzato per recuperare le informazioni dell'utente da un server di ricerca su Internet
5 TNMFTP TIdFTP, TIdTrivialFTP, TIdTrivialFTPServer Fornire il trasferimento di file utilizzando il protocollo FTP
6 TNMHTTP TIdHTTP, TIdHTTPServer Usa il protocollo HTTP per scambiare dati
7 TNMMsgServ, TNMMsg Utilizzato per trasferire semplici messaggi di testo dal client al server
8 TNMNNTP TIdNNTP, TIdNNTPServer Supporta la comunicazione con il server delle notizie
9 TNMPOP3 TIdPOP3 Utilizzato per ricevere e-mail da un server di posta utilizzando il protocollo POP3
10 TNMSMTP TIdSMTP Utilizzato per inviare e-mail tramite un server di posta Internet
11 TNMStrm, TNMStrmServ Trasmettere dati binari scritti nel flusso utilizzando il protocollo TCP/IP
12 TNMUDP TIdUDP, TIdUDPServer Effettuare il trasferimento dei dati utilizzando il protocollo UDP
13 TpowerSock, TNMGeneralServer Classi incapsulate nei componenti che sono fondamentali per scrivere i propri client (Powersock) e server (NMGeneralServer)
14 TNMUUPprocessore TIdUUEcoder, TIdUUDecoder Transcodifica di file binari in formato MIME o UUENCODE
15 TNMURL Ricodifica le stringhe in formato HTML ed esegue la ricodifica inversa

Le eccezioni sono classi come TNMMsgServ, TNMMsg, TNMStrm, TNMStrmServ, TpowerSock, TNMGeneralServer, TNMURL, che implementano protocolli obsoleti o hanno funzionalità implementate in un ampio gruppo di classi alternative.

Tuttavia, a differenza dei suoi predecessori, i componenti Internet e Fastnet, Indy ha una presentazione più ricca dei componenti server e dei componenti per la transcodifica e la crittografia dei dati, nonché il supporto per l'autenticazione (palette Indy Misc). Come puoi vedere dalla tabella sopra, i protocolli ei servizi principali sono forniti non solo dal client, ma anche dal componente server. Questi sono servizi di tempo, risposta, ottenimento di informazioni sull'utente, nonché i protocolli HTTP, NNTP, UDP e persino la versione più semplice di FTP.

Alcuni esempi di utilizzo di componenti Indy

Nei componenti Indy di Delphi, l'indirizzo IP è definito nella proprietà Host, di solito solo nelle applicazioni client. I componenti ospitati dal server dispongono di metodi che consentono di avviare o interrompere il polling della porta corrispondente, ad esempio, la modifica della proprietà Active del componente IdTCPServer avvia o interrompe il polling della porta corrispondente. Una volta stabilita la comunicazione tra client e server, può iniziare il trasferimento dei dati.

I componenti Indy danno grande importanza alla sicurezza e all'affidabilità dei dati. Ad esempio, il componente IdTCPClient dispone dei metodi Connetti e Disconnetti. Applicando una tecnica di programmazione come nel codice seguente dal lato client:

Con TCPClient inizia Connect; prova lstMain.Items.Add (ReadLn); infine Disconnetti; fine; fine;

e utilizzando la proprietà Connection passata come parametro dell'istanza AThread della classe TIdPeerThread dal lato server:

Con AThread.Connection inizia WriteLn ("Ciao dal server Basic Indy Server."); Disconnetti; fine;

puoi fare affidamento sul fatto che la connessione venga eseguita normalmente o che l'errore venga gestito correttamente.

Prestare attenzione ai metodi ReadLn e WriteLn delle rispettive classi: assomigliano alle istruzioni I/O Pascal standard. Questo è un omaggio alle tecniche di programmazione UNIX, dove la maggior parte delle operazioni di sistema vengono eseguite leggendo e scrivendo nei file appropriati.

Proprio come i componenti Fastnet, le classi di componenti Indy hanno eventi che puoi utilizzare per organizzare il controllo degli eventi. Ad esempio, puoi fare in modo che un messaggio venga visualizzato su un modulo quando ti connetti a un client:

Procedura TForm1.IdECHOServer1Connect (AThread: TIdPeerThread); begin lblStatus.caption: = "[Elaborazione client]"; fine;

Indy fornisce componenti che implementano protocolli lato client e lato server che sono univoci per questa libreria. I componenti TIdGopherServer e TIdGopher, grazie ai metodi GetExtendedMenu, GetFile, GetMenu, GetTextFile lato client e ReturnGopherItem, SendDirectoryEntry lato server, aiutano a visualizzare file di vario tipo, compresi quelli contrassegnati come nascosti, nonché directory su un computer remoto (come fa il comando MS-DOS dir *. *).

Utilizzando i componenti IdSMTP e IdMessage, puoi creare facilmente la tua applicazione Web in grado di inviare posta utilizzando il protocollo SMTP.

In questo caso, la classe IdMessage (uno dei 23 componenti della pagina Indy Misc) è responsabile della generazione di un messaggio, che segue dal suo nome, e IdSMTP, dell'organizzazione di una connessione al server di posta.

La tecnologia di Indy utilizza il blocco delle operazioni di lettura e scrittura. Qualsiasi operazione di connessione utilizzata in Indy attende il completamento della connessione. Quando si lavora con i componenti client Indy, di norma, è necessario eseguire le seguenti operazioni:

  • richiedere una connessione al server;
  • effettuare richieste di lettura e scrittura al server (a seconda del tipo di server, il passaggio viene eseguito una volta o ripetuto più volte);
  • terminare la connessione al server e disconnettersi.

I componenti Indy sono progettati per fornire un altissimo livello di astrazione. Le complessità e i dettagli dello stack TCP/IP sono nascosti al programmatore in modo che possa concentrarsi sui compiti a portata di mano.

Il seguente piccolo esempio mostra una tipica sessione del componente client:

Con IndyClient inizia Host: = "zip.pbe.com"; // Host per chiamare Porta: = 6000; // Porta per chiamare il server su Connect; try // Il tuo codice va qui finalmente Disconnect; fine; fine;

Nell'esempio, anche se la connessione al server non viene stabilita, la connessione verrà terminata normalmente utilizzando l'istruzione try-finally.

I componenti di Indy Server descrivono una varietà di modelli di server che è possibile utilizzare in base alle proprie esigenze e al protocollo in uso.

TIdTCPServer è il componente server più comunemente utilizzato che crea un processo secondario indipendente dal processo dell'applicazione principale. Il processo creato attende le richieste in arrivo da potenziali clienti. Viene creato un processo secondario individuale per ogni client a cui risponde. Gli eventi che si verificano durante il processo di manutenzione sono correlati al contesto dei rispettivi processi.

In altre parole, per ogni connessione client, la classe TIdTCPServer utilizza un thread secondario univoco richiamando il gestore dell'evento OnExecute del thread. Il parametro formale del metodo OnExecute è un riferimento a un'istanza della classe Athread corrispondente al thread creato. La proprietà Connection di questa classe è un riferimento alla classe TIdTCPConnection, di cui viene creata un'istanza per elaborare una richiesta client. TIdTCPConnection supporta la lettura e la scrittura su una connessione e l'instaurazione e la chiusura di una sessione di comunicazione.

Il protocollo UDP funziona senza prima stabilire una connessione al server (ogni pacchetto inviato è un insieme indipendente di dati e non fa parte di una sessione o connessione di grandi dimensioni). Mentre TIdTCPServer genera thread separati per ogni connessione, TIdUDPServer utilizza il thread principale o un singolo thread secondario che gestisce tutte le richieste UDP. Quando TIdUDPServer è attivo, viene creato un thread per ascoltare i pacchetti UDP in entrata. Per ogni pacchetto ricevuto, viene generato l'evento OnUDPRead sul thread principale o nel contesto del thread in ascolto, a seconda del valore della proprietà ThreadedEvent. Quando ThreadedEvent è False, l'evento viene generato sul thread principale, altrimenti sul thread in ascolto. Durante l'elaborazione dell'evento, le altre operazioni del server vengono bloccate. Pertanto, è importante assicurarsi che le procedure OnUDPRead vengano eseguite il più rapidamente possibile.

Se desideri creare una nuova applicazione client client per un server esistente utilizzando il protocollo esistente, il tuo compito è esclusivamente quello di sviluppare ed eseguire il debug dell'applicazione client. Tuttavia, quando dobbiamo sviluppare applicazioni sia client che server utilizzando un protocollo esistente o nuovo, ci troviamo di fronte al classico problema "uovo e gallina". Da dove iniziare a programmare: dal client o dal server?

Ovviamente, alla fine, devono essere creati sia il client che il server. Per molte applicazioni, in particolare quelle che utilizzano un protocollo basato su testo (come HTTP), è più semplice iniziare a creare l'applicazione progettando il server. E per eseguire il debug, esiste già un comodo client. Questa è un'applicazione console Telnet disponibile sia su Windows che su UNIX.

Se si digita il comando della console telnet 127.0.0.1 80 con l'indirizzo IP del computer locale e il numero di porta 80, utilizzato per impostazione predefinita dai server Web, l'applicazione risponderà con il testo mostrato in Fig. 6 per Windows 2000 e IIS 5.0.

Per creare il server più semplice utilizzando i componenti Indy, è necessario:

Se è necessario progettare un server che non solo informi correttamente i propri client sulla disconnessione della connessione, ma fornisca anche informazioni sugli errori che si sono verificati, utilizzare l'istruzione try-eccetto invece di try-finally, ad esempio come mostrato nel seguente esempio:

Procedura TDataModule1.IdTCPServer1Execute (AThread: IdPeerThread); vars: Stringa; iniziare con AThread.Connection provare try s: = ReadLn; // Esegui l'attività del server qui // se non viene sollevata alcuna eccezione, // scrivi la risposta del server WriteLn (s); tranne su e: Eccezione inizia WriteLn (e.Message); end; // on end; // prova tranne finalmente Disconnect; end; end;

Questo piccolo esempio mostra i passaggi coinvolti nella creazione di un semplice server di testo e come eseguirne il debug.

Il server di cui sopra è un tipico esempio dell'organizzazione del moderno calcolo distribuito.

Funzionalità di creazione di applicazioni multilivello

Recentemente, sono stati sempre più utilizzati più server per soddisfare le richieste dei clienti. Un server di questo tipo, dopo aver ricevuto la richiesta di un client e preparandola parzialmente per ulteriori elaborazioni, contatta un altro server e gli invia la richiesta o le richieste trasformate. Il server di secondo livello può, a sua volta, comunicare con altri server. Quindi, possiamo parlare di un'architettura server multi-tier.

Successivamente, creeremo un server di accesso ai dati il ​​cui scopo è restituire i dati dal database. Questo server, tuttavia, non legge e scrive direttamente nei file del database. Invece, contatta il server del database alla ricerca dei dati richiesti dal client.

Quindi, iniziamo a sviluppare un'applicazione con un'architettura a tre livelli. Per creare un server di database utilizzando i componenti Indy, è necessario:

  1. Crea un nuovo progetto.
  2. Posiziona un'istanza del componente TIdTCPServer dalla palette Indy Servers nel form principale del progetto.
  3. Impostare la proprietà DefaultPort di un'istanza della classe TIdTCPServer1 su 6001 (si consiglia di impostare valori grandi per evitare numeri di porta duplicati per applicazioni diverse) e la proprietà Active su true.
  4. Aggiungi un nuovo modulo al progetto scegliendo File | Nuovo | Data Module e posizionare le istanze dei componenti SQLConnection e SQLDataSet dalla scheda dbExpress nella tavolozza dei componenti su di esso.
  5. Impostare la proprietà ConnectionName della classe SQLConnection su IBLocal e LoginPrompt su False. Se non hai configurato IBLocal sul database impiegato.gdb, segui prima questa procedura.

In poche parole, Indy è un componente per lavorare facilmente con i protocolli Internet più diffusi. Il loro principio di funzionamento si basa sull'uso di prese di blocco. Indy è interessante e conveniente perché è abbastanza astratto. E la programmazione Indy si riduce alla programmazione lineare. A proposito, un articolo tradotto è molto diffuso su Internet, in cui ci sono le parole "il regime di blocco non è il diavolo" :)) Una volta ero molto divertito da questa traduzione. L'articolo fa parte del libro di Hoover e Hariri "The Depths of Indy". In linea di principio, per lavorare con Indy, non è necessario leggerlo tutto, ma ti consiglio comunque di familiarizzare con i principi dei protocolli Internet. Quanto al regime "diabolico". Una chiamata a un socket di blocco non ritorna realmente finché non completa il suo compito. Quando vengono effettuate chiamate sul thread principale, l'interfaccia dell'applicazione potrebbe bloccarsi. Per evitare questa spiacevole situazione, gli sviluppatori indiani hanno creato il componente TIdAntiFreeze. Devi solo rilasciarlo sul modulo e l'interfaccia utente verrà ridisegnata con calma durante l'esecuzione delle chiamate di blocco.

Probabilmente hai già familiarizzato con i contenuti delle varie schede "Indy (...)" in Delphi. Ci sono molti componenti là fuori e ognuno di essi può essere utile. Io stesso non ho lavorato con tutti, poiché non vedo la necessità di studiarli senza un compito specifico.

La distribuzione di base Delphi include Indy v.9 con un centesimo. Probabilmente, è consigliabile aggiornare immediatamente a una versione più recente (ad esempio, ora ho la 10.0.76, ma ce ne sono anche di successive, come).

Esistono componenti client e server per lavorare con gli stessi protocolli. Indy semplifica davvero lo sviluppo delle applicazioni, invece di sviluppare le stesse funzionalità sui socket. Ad esempio, per comunicare con un server, è sufficiente chiamare il metodo Connect. La corretta creazione della connessione sarà contrassegnata da un ritorno dal metodo senza causare un'eccezione. Se la connessione non viene chiamata, verrà generata un'eccezione.

Esempio "accademico" (il codice non funziona, non eseguire :)):

Con IndyClient fai
inizio
Host: = "test.com";
Porto: = 2000;
Collegare;
Provare
// lavora con i dati (leggi, scrivi...)
finalmente
Disconnetti;
fine;
fine;

Host e porta possono essere impostati nella finestra di ispezione degli oggetti o in fase di runtime.

Quindi per cosa puoi usare i componenti Indy nelle attività di analisi? L'applicazione è varia! La cosa più semplice è ottenere il contenuto della pagina (probabilmente tutti lo hanno già riscontrato) utilizzando il componente IdHTTP:

Var
rcvrdata: TMemoryStream;
idHttp1: TidHttp;
inizio
idHttp1: = TidHttp.Create (nil);
rcvrdata: = TMemoryStream.Create;
idHttp1.Request.UserAgent: = "Mozilla / 4.0 (compatibile; MSIE 5.5; Windows 98)";
idHttp1.Request.AcceptLanguage: = "ru";
idHttp1.Response.KeepAlive: = true;
idHttp1.HandleRedirect: = true;
provare
idHttp1.Get (Edit1.Text, rcvrdata);
finalmente
idHttp1.Gratuito;
fine;
se rcvrdata.Size> 0 allora inizia
ShowMessage ("Ricevuto" + inttostr (rcvrdata.Size));
rcvrdata.SaveToFile ("c: \ 111.tmp");
fine;
rcvrdata.Gratuito;
fine;

Come puoi vedere, non solo puoi ottenere il contenuto della pagina, ma anche simulare il caricamento di un documento da un client specifico. I componenti Indy sono generalmente utili per generare intestazioni e richieste POST. Maggiori informazioni su questo con esempi la prossima volta.

Per tenerti aggiornato sugli aggiornamenti del blog, puoi

Ciao a tutti!

Durante lo sviluppo del prossimo progetto Web, è nata l'attività: implementare il software client in Delphi, che trasmettesse i dati al server utilizzando il metodo POST. L'applicazione deve trasmettere testo e caricare file sul server web.

L'implementazione di tale invio di dati utilizzando linguaggi di sviluppo Web lato server (ad esempio PHP) è abbastanza semplice, ma se è necessario scrivere un'applicazione, un software multiutente che interagisce con il server, allora è già un po' di più complicato. Il metodo di connessione diretta al database e via FTP al server da Delphi - non esiste più. non è sicuro, non affidabile (cambia password, dati di connessione, ecc.) e crea ulteriori. problemi di compatibilità del software lato client. Per risolvere il problema, ho deciso di scrivere script in PHP (lato server) che elaboreranno le richieste POST in arrivo e restituiranno il risultato al client (applicazione Delphi). I vantaggi di questo approccio sono che tutte le connessioni e l'elaborazione dei dati avvengono sul server, il che è molto più sicuro di una "connessione" diretta.

Dopo aver iniziato a "google" sono state distribuite molte informazioni sparse, principalmente forum, ma tutto questo era a pezzi. Una cosa è certa che verrà utilizzato Indy, ovvero il componente IdHTTP con il metodo POST implementato. In effetti è tutto semplice, questo metodo accetta due parametri Url della risorsa e DataStream (data stream), in risposta restituisce il risultato in forma testuale (può essere anche il codice HTML della pagina). La cosa principale era nella corretta formazione del DataStream (il flusso di dati trasmessi), ma lungo la strada sono emerse ulteriori insidie, vale a dire la codifica russa (se non va bene). È qui che è iniziato il divertimento per alcune ore di vagabondaggio nella vastità della rete. Tutto sommato, basta con le chiacchiere, passiamo alla pratica e all'implementazione del software.

Quindi il programma è semplice. Dovrebbe inviare i dati al server utilizzando il metodo POST, i dati contengono " Intestazione " (linea), " Descrizione »(testo multilinea) e file grafico (jpg, png, gif-dati binari). Il server deve accettare questi dati, elaborarli, salvare il file grafico sul server e restituire una risposta. Come risposta, restituiamo l'applicazione Delphi, lo stesso testo solo con l'aggiunta di tag e un collegamento al file caricato. Niente di più.

Iniziamo con l'implementazione del lato server (simile all'API del sito). Apri un qualsiasi editor di testo (blocco note) e scrivici il seguente codice:

";) else (echo" Titolo: mancante "."
";) // Controlla i dati ricevuti per la presenza del campo" content "data if (! Empty ($ _ POST [" content "])) (echo" Content: ". $ _ POST [" content "]. "
";) else (echo" Contenuto: mancante "."
";) // Controlla i dati ricevuti per la presenza del file allegato" file "if (! Empty ($ _ FILES [" file "])) ($ finfo = pathinfo ($ _ FILES [" file "] [" nome "]); // ottieni informazioni sul file (nome, estensione, ecc.) // Verifica il tipo di file nell'elenco dei tipi consentiti (IMPROVISAZIONE :)) if (stripos ("jpgpnggif", $ finfo ["estensione "]) == 0) ( echo ">>>>>>> Tipo di file non valido<<<<<<<<"; exit; //Если не допустим тип, полностью останавливаем скрипт } $fname = "files/" . "testimgfile." . $finfo["extension"]; //формируем путь и новое имя файла move_uploaded_file($_FILES["file"]["tmp_name"],$fname);//сохраняем временный файл "tmp_name" в файл $fname echo "http://".$_SERVER["HTTP_HOST"]."/".$fname; //возвращаем полный путь к файлу } ?>

Nota! In fase di salvataggio (tramite blocco note), è necessario specificare la codifica "UTF-8", altrimenti ci saranno problemi con la visualizzazione dell'alfabeto cirillico!

Lo script ha cercato di fornire commenti dettagliati. Copia questo script sul tuo server Web, se non ce n'è, puoi usare il mio script per i test, si trova in: http: //api..php

Nel layout vengono utilizzati i seguenti componenti: Etichetta, Pulsante (2 pezzi), Modifica (2 pezzi), Memo (2 pezzi), CheckBox, OpenDialog, IdHTTP. Denominare i seguenti componenti (proprietà “ Nome”):

  1. Modifica (titolo) - Nome = titolo;
  2. Modifica (percorso file) Nome = file img;
  3. Promemoria (Contenuto)Nome = contenuto;
  4. Promemoria (risultato) - Nome = risposta;
  5. Pulsante (...) - Nome = chkfile;
  6. Pulsante (POST) - Nome = PostMa;
  7. OpenDialog (finestra di selezione file) - Nome = PictDialog;

Lascia IdHTTP1 e CheckBox1 invariati (stanco! :)))).

Per non accidentalmente " modificare»Percorso da modificare ( imgfile), imposta la proprietà ReadOnly su True. Inoltre, a imgfile e chkfile impostare la proprietà Enabled su false. Li attiveremo utilizzando CheckBox i.e. forniremo l'opportunità di scegliere se caricare un'immagine o meno.

Per OpenDialog ( PictDialog), è necessario impostare il filtro (la proprietà Filter) come segue:

La preparazione visiva vera e propria è finita! Iniziamo a programmare!

Nel progetto, formeremo un flusso di dati utilizzando il tipo fornito con Indy - TidMultiPartFormDataStream. Sebbene ci fossero varianti di implementazione su TStream, ma lavorando con TidMultiPartFormDataStream - Più facile!

Per rendere disponibile questo tipo al nostro progetto, è necessario aggiungere la seguente libreria a Uses: IdMultipartFormData.

Per CheckBox1, crea un evento OnClick (facendo doppio clic sull'oggetto) e aggiungi il seguente codice a questo evento:

Procedura TForm1.CheckBox1Click (Mittente: TObject); begin // attiva o disattiva il percorso del file ei pulsanti di dialogo imgfile.Enabled: = CheckBox1.Checked; chkfile.Enabled: = CheckBox1.Checked; fine;

Qui attiviamo gli oggetti imgfile echkfile a seconda della presenza di un segno di spunta (se la casella è spuntata, gli oggetti diventano attivi).

Ora organizzeremo la selezione dell'immagine. Per fare ciò, crea un evento OnClick sul pulsante chkfile(anche facendo doppio click sull'oggetto) e scrivere quanto segue:

Procedura TForm1.chkfileClick (Mittente: TObject); begin // apri la finestra di dialogo e inserisci il percorso completo del file in imgfile (TEdit) if PictDialog.Execute then imgfile.Text: = PictDialog.FileName; fine;

Questo evento attiverà una finestra di dialogo per la selezione delle immagini e se l'utente fa clic su " Aperto", quindi il percorso di questo file verrà aggiunto a imgfile.

E ora arriviamo al pulsante finale "POST". Crea un evento OnClick per questo pulsante e aggiungi il seguente codice:

Procedura TForm1.PostButClick (Mittente: TObject); var dataPost: TIdMultiPartFormDataStream; iniziare dataPost: = TIdMultiPartFormDataStream.Create; dataPost.AddFormField ("titolo", titolo.Testo, "utf-8") ContentTransfer: = "8bit"; dataPost.AddFormField ("content", content.Text, "utf-8") ContentTransfer: = "8bit"; if CheckBox1.Checked and (trim (imgfile.Text) = "") then // controlla se un file è selezionato o meno inizia ShowMessage ("Devi selezionare un file grafico!"); Uscita; fine; se CheckBox1.Checked allora dataPost.AddFile ("file", imgfile.Text, ""); // aggiungi un campo con il file response.Text: = StringReplace (idHTTP1.Post ("http: //api..php", dataPost), "
", # 13 # 10,); datapost.Free; end;

Quindi, in ordine (anche se ci sono commenti):

Datapost - oggetto di tipo TIdMultiPartFormDataStream. Consente di formare una struttura di richiesta POST composta da campi di diverso tipo.

dataPost . Aggiungi campo modulo (" titolo ", titolo . Testo ," utf -8 "). ContentTransfer := " 8 po "; - aggiunge al DataPost un campo denominato "title", un valore da "title.Text", imposta la codifica dei dati trasmessi a "utf-8" (il parametro è facoltativo, ma senza la sua esplicita indicazione, l'alfabeto cirillico è trasmesso da punti interrogativi "?") E un metodo molto importante "ContentTransfer". Senza questo metodo, i dati vengono inviati al server " abracadabra". Si prega di notare che il nome del campo ("titolo") sul lato trasmittente deve corrispondere al nome specificato nello script: $ _POST ["titolo"].

I dati nel campo "contenuto" vengono passati allo stesso modo.

dataPost . Aggiungi file (" file ", imgfile . Testo ,"") - con questa riga formiamo un flusso con i dati del file.

Tutto, i dati sono formati, resta da trasferirli allo script sul server e ottenere la risposta:

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

da TMemo non comprende il tag di interruzione di riga "
", useremo la" "funzione per sostituirlo con interruzioni di riga comprensibili" # 13 # 10 ".

Al termine di tutto cancellate la memoria dall'oggetto DataPost con la riga:

datapost.Gratis;

Sebbene nel nostro esempio ciò accadrà automaticamente alla fine della procedura, ma comunque ...

Il risultato effettivo del programma sullo schermo:

Pertanto, possiamo inviare qualsiasi dato, file al server, elaborare questi dati sul server e informare l'applicazione con una risposta, il risultato dell'esecuzione dello script. Può anche essere solo 0 o 1, che segnalerà l'ulteriore reazione dell'applicazione.

Qualunque cosa. Buona fortuna a tutti. Spero che le informazioni siano state utili e che troverai un uso per questo.

Puoi scaricare l'esempio e lo script finiti.

Codice modulo completo:

Unità PostUnit; l'interfaccia utilizza Winapi.Windows, Winapi.Messages, System.SysUtils, System.Varians, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPConnection, IdTCPConnection, IdHTTP, IdMultipartFormData, Vcl.ExtDlgs; tipo TForm1 = classe (TForm) IdHTTP1: TIdHTTP; titolo: TEdit; contenuto: TMemo; PostBut: TButton; risposta: TMemo; Etichetta1: TLabel; Etichetta2: TLabel; Etichetta3: TLabel; imgfile: TEdit; chkfile: TButton; Etichetta4: TLabel; CheckBox1: TCheckBox; PictDialog: TOpenDialog; procedura PostButClick (Mittente: TObject); procedura chkfileClick (Mittente: TObject); procedura CheckBox1Click (Mittente: TObject); privato (dichiarazioni private) pubblico (dichiarazioni pubbliche) fine; var Modulo1: TForm1; implementazione ($ R * .dfm) procedura TForm1.CheckBox1Click (Sender: TObject); begin // attiva o disattiva il percorso del file ei pulsanti di dialogo imgfile.Enabled: = CheckBox1.Checked; chkfile.Enabled: = CheckBox1.Checked; fine; procedura TForm1.chkfileClick (Mittente: TObject); begin // apri la finestra di dialogo e inserisci il percorso completo del file in imgfile (TEdit) if PictDialog.Execute then imgfile.Text: = PictDialog.FileName; fine; procedura TForm1.PostButClick (Mittente: TObject); var dataPost: TIdMultiPartFormDataStream; iniziare dataPost: = TIdMultiPartFormDataStream.Create; dataPost.AddFormField ("titolo", titolo.Testo, "utf-8") ContentTransfer: = "8bit"; dataPost.AddFormField ("content", content.Text, "utf-8") ContentTransfer: = "8bit"; if CheckBox1.Checked and (trim (imgfile.Text) = "") then // controlla se un file è selezionato o meno inizia ShowMessage ("Devi selezionare un file grafico!"); Uscita; fine; se CheckBox1.Checked allora dataPost.AddFile ("file", imgfile.Text, ""); // aggiungi un campo con il file response.Text: = StringReplace (idHTTP1.Post ("http: //api..php", dataPost), "
", # 13 # 10,); datapost.Free; end; end.

Introduzione a Indy

Introduzione a Indy
Autore: Chad Z. Hower
Pagina iniziale: http://www.atozedsoftware.com
Traduzione: Anatoly Podgoretsky
introduzione
Ho scritto questo articolo quando la versione corrente era Indy 8.0. Gran parte di questo articolo è applicabile e molto utile nelle future versioni di Indy. Se ti è piaciuto questo articolo e desideri leggere articoli più dettagliati, dai un'occhiata al libro Indy in Depth.
Indy sta bloccando
Indy usa socket bloccanti. La modalità di blocco è simile alla lettura/scrittura di un file. Durante la lettura o la scrittura di dati, la funzione non ritorna fino alla fine dell'operazione. La differenza rispetto al lavoro con i file è che la chiamata potrebbe richiedere più tempo, poiché i dati richiesti non sono ancora disponibili, dipende dalla velocità con cui opera la rete o il modem.
Ad esempio, viene semplicemente eseguita una chiamata al metodo e si attende che il controllo venga restituito al punto di chiamata. Se la chiamata ha avuto successo, il controllo verrà restituito dal metodo, verrà sollevata un'eccezione in caso di errore.
La modalità di blocco non è fatale
A causa della modalità di blocco, siamo stati ripetutamente battuti dai nostri avversari, ma la modalità di blocco non è il diavolo.
Il problema è apparso dopo aver portato Winsock su Windows. In Unix, il problema veniva tipicamente risolto per biforcazione (simile a molti thread, ma a spese di processi separati invece che di thread). I client e i demoni Unix hanno dovuto eseguire il fork dei processi per eseguire e utilizzare la modalità di blocco. Windows 3.x non può essere parallelizzato e non supporta molti thread. L'utilizzo di un'interfaccia di blocco bloccherebbe l'interfaccia utente e impedirebbe ai programmi di rispondere. Pertanto, sono state aggiunte modalità non bloccanti a WinSock, consentendo a Windows 3.x, con i suoi limiti, di utilizzare Winsock senza bloccare il thread principale e unico del programma. Ciò ha richiesto una programmazione diversa, Microsoft e altri hanno denigrato appassionatamente le modalità di blocco per nascondere i difetti di Windows 3.x.
Poi è arrivato Win32, che era in grado di supportare molti thread. Ma a questo punto, il cervello era già in polvere (cioè, gli sviluppatori consideravano il blocco dei socket un prodotto del diavolo), ed era già difficile cambiare ciò che avevano fatto. Pertanto, la denigrazione dei regimi di blocco continua.
In realtà, Unix ha solo socket bloccanti. Anche i socket bloccanti hanno i loro vantaggi e sono molto migliori per molti aspetti del threading, della sicurezza e di altri. Diverse estensioni sono state aggiunte a Unix per i socket non bloccanti. Tuttavia, funzionano in modo molto diverso rispetto a Windows. Sono anche non standard e non molto comuni. I socket di blocco Unix vengono utilizzati in quasi tutti i casi e continueranno a essere utilizzati.
Vantaggi della modalità di blocco · Più facile da programmare - Le modalità di blocco sono più facili da programmare. Tutto il codice personalizzato può trovarsi in un'unica posizione ed essere eseguito in un ordine sequenziale naturale. · Più facile da portare su Unix - Poiché Unix utilizza socket bloccanti, è più facile scrivere codice portabile in questo caso. Indy usa questo fatto per scrivere codice coerente. · Meglio lavorare con i flussi: poiché i socket di blocco sono ereditati, sono molto facili da usare nei flussi.
Svantaggi della modalità di blocco · L'interfaccia utente si blocca nei client: una chiamata socket di blocco non viene restituita finché non completa la sua attività. Quando tale chiamata viene effettuata sul thread principale dell'applicazione, l'applicazione non può elaborare i messaggi dell'utente. Ciò blocca l'interfaccia utente, non aggiorna le finestre e altri messaggi non possono essere elaborati finché il controllo non viene restituito dal socket di blocco.
TIdComponente Antigelo
Indy ha un componente speciale che risolve il problema del blocco dell'interfaccia utente. Basta aggiungere un componente TIdAntiFreeze in qualsiasi punto dell'applicazione e puoi effettuare chiamate di blocco senza bloccare l'interfaccia utente.
TIdAntiFreeze viene eseguito su un timer interno esterno allo stack di chiamate e chiama Application.ProcessMessages allo scadere del timeout. Le chiamate esterne a Indy continuano a bloccarsi e quindi funzionano allo stesso modo senza utilizzare il componente TIdAntiFreeze. L'utilizzo di TIdAntiFreeze consente di ottenere tutti i vantaggi del blocco delle prese, senza gli svantaggi.
filettatura
I codestream sono quasi sempre usati con i socket bloccanti. Anche i socket non bloccanti possono utilizzare i flussi, ma ciò richiede un'elaborazione aggiuntiva e i loro vantaggi vengono persi in questo caso rispetto ai socket bloccanti.
Vantaggi dei flussi · Regolazione della priorità: è possibile configurare le priorità dei singoli flussi. Ciò consente di allocare più o meno tempo della CPU alle singole attività. · Incapsulamento - Ogni connessione può contenere una parvenza di interfaccia con un'altra connessione. · Sicurezza: ogni thread può avere attributi di sicurezza diversi. · Più processori: offre un vantaggio sui sistemi con più processori. · Nessuna serializzazione richiesta: fornisce la piena concorrenza. Senza molti thread, tutte le richieste dovrebbero essere elaborate in un singolo thread. Pertanto, ogni attività deve essere suddivisa in piccoli blocchi in modo che possa essere eseguita rapidamente. Mentre un blocco viene eseguito, tutti gli altri sono costretti ad attendere il suo completamento. Alla fine di un blocco, viene eseguito il successivo e così via. Con il multithreading, ogni attività può essere programmata come una singola unità e il sistema operativo distribuisce il tempo tra tutte le attività.
Flussi di sondaggi
La creazione e la distruzione dei thread richiedono molte risorse. Questo è particolarmente difficile per i server che hanno connessioni di breve durata. Ogni server crea un flusso, lo utilizza per un breve periodo e poi lo distrugge. Ciò porta alla creazione e all'eliminazione molto frequenti di thread. Un esempio di questo è un server Web. Viene inviata una singola richiesta e viene restituita una risposta semplice. Quando si utilizza un browser, durante la navigazione in qualsiasi sito Web, possono verificarsi centinaia di connessioni e disconnessioni
I thread di polling possono risolvere questa situazione. Invece di creare e distruggere i thread su richiesta, i thread vengono selezionati da un elenco di thread inutilizzati ma già creati dal pool. Quando il thread non è più necessario, viene restituito al pool invece di essere distrutto. I thread nel pool sono contrassegnati come non utilizzati e pertanto non consumano tempo di CPU. Per un miglioramento ancora maggiore, i flussi possono essere adattati dinamicamente alle esigenze attuali del sistema.
Indy supporta i thread di polling. Il pool di thread Indy è accessibile tramite il componente TIdThreadMgrPool.
Molti thread
Un server pesantemente caricato può richiedere centinaia o addirittura migliaia di thread. C'è una credenza comune che centinaia e migliaia di thread possano uccidere il tuo sistema. Questa è una falsa credenza.
Sulla maggior parte dei server, i thread sono in attesa di dati. Durante l'attesa di una chiamata di blocco, il thread è inattivo. In un server con 500 thread, solo 50 possono essere attivi contemporaneamente.
Il numero di thread in esecuzione sul tuo sistema potrebbe sorprenderti. Con il numero minimo di server in esecuzione e le applicazioni in esecuzione specificate, il mio sistema ha 333 thread creati, anche con 333 thread, il processore è caricato solo all'1%. Un server IIS (Microsoft Internet Information Server) pesantemente caricato può creare centinaia e migliaia di thread.
Stream e sezioni globali
Con più flussi, è necessario garantire l'integrità dei dati quando vi si accede. Questo può essere difficile per i programmatori senza thread. Ma di norma, la maggior parte dei server non ha bisogno di utilizzare dati globali. La maggior parte dei server esegue funzioni isolate. Ogni thread esegue il proprio compito isolato. Le sezioni di lettura/scrittura globali sono una caratteristica di molte applicazioni multithread, ma non sono tipiche dei server.
Metodologia Indy
Indy è diverso da qualsiasi altro componente Winsock a cui sei abituato. Se hai lavorato con altri componenti, la soluzione migliore è dimenticare come funzionano. Molti altri componenti utilizzano chiamate non bloccanti (asincrone) e funzionano in modo asincrono. Devono rispondere agli eventi, creare una macchina a stati e spesso attendere i cicli.
Ad esempio, con altri componenti, quando si chiama una connessione, è necessario attendere che si verifichi l'evento di connessione o in un ciclo attendere che la proprietà indichi che la connessione si è verificata. Con Indy, puoi chiamare il metodo Connect e attendere che ritorni. I rimborsi verranno effettuati se la connessione ha esito positivo o verrà sollevata un'eccezione in caso di problemi. Pertanto, lavorare con Indy è molto simile a lavorare con i file. Indy ti consente di mettere tutto il tuo codice in un unico posto, invece di essere macchiato su eventi diversi. Inoltre, Indy è molto semplice e il più snello.
Quanto è diversa Indy?
Panoramica · Vengono utilizzate le chiamate di blocco · Non orientate agli eventi: ci sono eventi, ma vengono utilizzati a scopo informativo e non sono realmente necessari. · Progettato per i thread - Indy è progettato per i thread, tuttavia può essere utilizzato senza thread. Programmazione sequenziale
Considerazione dettagliata
Indy non utilizza solo il blocco delle chiamate (sincrone) ma funziona anche in questo modo. Una tipica sessione di Indy si presenta così:
con IndyClient inizia
Collegare; Provare
// Fai le tue cose qui
infine Disconnetti; fine;
fine;
Con altri componenti, sembra così:
procedura TFormMain.TestOnClick (Mittente: TComponent);
inizio
con SocketComponent inizia
Collegare; provare
mentre non è connesso inizia
se IsError allora inizia
Interrompi;
fine;

OutData: = "Dati da inviare";
mentre lunghezza (OutData)> 0 inizia
Applicazione.ProcessoMessaggi;
fine;
infine Disconnetti; fine;
fine;
fine;
procedura TFormMain.OnConnectError;
inizio
IsError: = True;
fine;
procedura TFormMain.OnRead;
varia
io: numero intero;
inizio
i: = SocketComponent.Send (OutData);
OutData: = Copia (OutData, i + 1, MaxInt);
fine;
Molti componenti non fanno un ottimo lavoro nell'isolare il programmatore dallo stack. Molti componenti, invece di isolare l'utente dalle complessità dello stack, lo lasciano semplicemente da solo con lui o forniscono un involucro sopra lo stack.
Il modo speciale di Indy
Indy è progettato da zero per essere multithread. La creazione di server e client in Indy è simile alla creazione di server e client in Unix. Le applicazioni Unix di solito chiamano lo stack direttamente con un livello di astrazione minimo o nullo.
Tipicamente, i server Unix hanno uno o più listener che ascoltano le richieste dei client in arrivo. Viene creato un nuovo processo per ogni cliente che deve essere servito. Ciò semplifica la programmazione, ogni processo è per un solo cliente. Ogni processo inizia nel proprio contesto di sicurezza, che è impostato da un listener o da un processo basato su diritti esistenti, identità o altro.
I server Indy funzionano più o meno allo stesso modo. Windows, a differenza di Unix, non può replicare bene i processi, ma funziona bene con i thread. I server Indy creano un thread separato per ogni connessione client.
I server Indy designano un thread di ascolto separato dal thread di codice principale del programma. Il thread di ascolto ascolta le richieste in ingresso dai client. Per ogni client che risponde, viene creato un nuovo thread per servire il client. Gli eventi corrispondenti vengono quindi serviti nel contesto di questo thread.
Recensione del cliente Indy
Indy è progettato per fornire un livello di astrazione molto elevato. La confusione e la granularità dello stack TCP/IP sono nascoste al programmatore.In genere, una tipica sessione client in Indy si presenta così:
con IndyClient inizia
Host: = "zip.pbe.com"; // Host da chiamare
Porta: = 6000; // Porta su cui chiamare il server
Collegare; Provare
// Fai le tue cose qui
infine Disconnetti; fine;
fine;
Panoramica dei server Indy
I componenti del server Indy creano un thread di ascolto isolato dal thread di codice principale del programma. Il thread di ascolto ascolta le richieste in ingresso dai client. Per ogni client che risponde, viene creato un nuovo thread per servire il client. Gli eventi corrispondenti vengono quindi serviti nel contesto di questo thread.

Esempi pratici
I seguenti esempi dovrebbero iniziare con i componenti per un utilizzo semplice, ma per dimostrare che gli esempi sono realizzati come semplici applicazioni. Alcuni progetti sono fatti per dimostrare situazioni diverse. Questi esempi sono disponibili anche per il download come file zip.
Nota del traduttore: il link sul sito non funziona.
Esempio 1 - Controllo del codice postale
Il primo progetto è reso il più semplice possibile. Ricerca per CAP, il client chiede al server a quale città e stato appartiene il CAP specificato.
Per chi vive fuori dagli Stati Uniti e non sa cosa sia un CAP, questo è un codice postale che indica il luogo di consegna. I codici postali sono lunghi 5 cifre.
Protocollo
Il primo passo nella creazione di un server e di un client è lo sviluppo di un protocollo. Per i protocolli standard, questo è definito dalla RFC corrispondente. Per un codice postale, il protocollo è definito di seguito.
La maggior parte dei protocolli di scambio funziona in modalità testo. Scambio significa che viene trasmesso un comando e, in risposta, uno stato ed eventualmente dati. I protocolli non si limitano allo scambio, ma viene comunque utilizzato il testo normale. Anche il protocollo di determinazione del codice postale è testuale. Il testo semplice semplifica il debug dei protocolli e consente la comunicazione tra diversi linguaggi di programmazione e sistemi operativi.
Dopo la connessione, il server invia un messaggio di benvenuto, quindi riceve il comando. Questo comando può essere "ZipCode x" (dove x è il codice postale) o "Esci". In risposta al comando ZipCode, viene inviata una risposta come una singola riga con la risposta o una riga vuota se il codice non viene trovato. Il comando Quit fa sì che il server termini la connessione. Il server può accettare più comandi prima di inviare il comando Quit.
Codice sorgente del server

unità ServerPrincipale;

interfaccia

usa

genere

TformMain = classe (TForm)

IdTCPServer1: TIdTCPServer;

procedura FormCreate (mittente: TObject);

procedura FormDestroy (mittente: TObject);

procedura IdTCPServer1Connect (AThread: TIdPeerThread);

privato

ZipCodeList: TStrings;

pubblico

fine;

FormMain: TformMain;

implementazione

(R * .DFM)

procedura TformMain.IdTCPServer1Connect (AThread: TIdPeerThread);

inizio

AThread.Connection .WriteLn ("Indy CAP Server Ready.");

fine;

SComando: stringa;

inizio

SComando: = LeggiLn;

fine;

fine;

fine;

procedura TformMain.FormCreate (Mittente: TObject);

inizio

ZipCodeList: = TStringList.Create;

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

fine;

procedura TformMain.FormDestroy (Mittente: TObject);

inizio

ZipCodeList.Gratuito;

fine;

fine.

Le uniche parti specifiche di Indy nel progetto sono il componente IdTCPServer1, i metodi IdTCPServer1Connect e IdTCPServer1Execute.
Il modulo contiene il componente IdTCPServer1 del tipo TIdTCPServer. Le seguenti proprietà sono state modificate: · Active = True - Dopo l'avvio dell'applicazione, il server è in ascolto. · DefaultPort = 6000 - Valore della porta per questo progetto. Il server ascolta le richieste del client su questa porta.
Il metodo IdTCPServer1Execute è associato all'evento OnExecute del server. L'evento OnExecute viene generato dopo l'accettazione della connessione del client. L'evento OnExecute è diverso dagli altri eventi che conosci. OnExecute viene eseguito nel contesto del thread. Viene chiamato l'evento thread e gli viene passato l'argomento AThread passato al metodo. Questo è importante perché molti eventi OnExecute possono essere eseguiti contemporaneamente. In questo modo il server può funzionare senza creare un nuovo componente. Esistono anche metodi che possono essere sovrascritti durante la creazione di discendenti.
L'evento OnConnect viene chiamato dopo che la connessione è stata accettata e per essa è stato creato un thread. In questo server, viene utilizzato per inviare un messaggio di benvenuto al client. Facoltativamente, questa operazione può essere eseguita anche nell'evento OnExecute.
L'evento OnExecute può essere generato più volte fino a quando la connessione non viene disconnessa o persa. Ciò elimina la necessità di controllare la connessione per la disconnessione o la perdita del loop all'interno di un evento.
IdTCPServer1Execute utilizza due funzioni di base, ReadLn e WriteLn. ReadLn legge una stringa dalla connessione e WriteLn invia una stringa alla connessione.
sComando: = LeggiLn;
Il codice precedente prende una stringa dal client e la inserisce nella variabile stringa locale sCommand.

if SameText (sCommand, "QUIT") allora inizia

end else if SameText (Copy (sCommand, 1, 8), "ZipCode") quindi inizia

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

fine;


Successivamente, sCommand viene controllato per i comandi validi.
Se il comando è "Esci", viene eseguito Disconnetti. Nessuna lettura o scrittura è consentita dopo la disconnessione. Dopo la fine dell'evento, il thread in ascolto non lo chiama più, ma cancella il thread e termina la connessione.
Se il comando è "ZipCode", il parametro dopo il comando viene recuperato e la tabella viene scansionata per la presenza di città e stato. La città e lo stato vengono quindi passati al client oppure viene passata una stringa vuota se non c'è corrispondenza.
Quindi il metodo esce. Il server rilancia nuovamente l'evento non appena arriva un nuovo comando, consentendo al client di inviare più comandi.
Codice sorgente del cliente

unità ClientePrincipale;

interfaccia

usa

Windows, Messaggi, SysUtils, Classi, Grafica, Controlli, Moduli, Finestre di dialogo,

StdCtrls, ExtCtrls, IdAntiFreezeBase,

IdAntiFreeze, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient;

genere

TformMain = classe (TForm)

Cliente: Cliente TIdTCPC;

IdAntiFreeze1: TIdAntiFreeze;

Pannello1: TPanel;

Pannello2: TPanel;

MemoInput: TMemo;

LboxResults: TListBox;

Pannello3: TPanel;

Pulsante1: T Pulsante;

Pulsante 2: T Pulsante;

Etichetta1: TLabel;

procedura Button2Click (Mittente: TObject);

procedura Button1Click (Mittente: TObject);

privato

pubblico

fine;

FormMain: TformMain;

implementazione

(R * .DFM)

procedura TformMain.Button2Click (Mittente: TObject);

inizio

MemoInput.Clear;

LboxResults.Clear;

fine;

procedura TformMain.Button1Click (Mittente: TObject);

io: intero;

S: stringa;

inizio

ButnLookup.Enabled: = vero; provare

LboxResults.Clear;

con il cliente inizia

Collegare; provare

LboxResults.Items .Add (ReadLn);

per i: = 0 a memoInput.Lines .Count - 1 inizia

WriteLn ("CAP" + memoInput.Lines [i]);

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

S: = LeggiLn;

se s = "" allora inizia

S: = "- Nessuna voce trovata per questo codice postale.";

fine;

LboxResults.Items .Add (s);

LboxResults.Items .Add ("");

fine;

WriteLn ("Esci");

infine Disconnetti; fine;

fine;

infine butnLookup.Enabled: = true; fine;

fine;

fine.


Le uniche parti specifiche del componente client sono il metodo Button1Click.
Il componente Client di tipo TIdTCPClient si trova nel modulo. Le seguenti proprietà sono state modificate: · Host = 127.0.0.1 - Il server si trova sulla stessa macchina del client. Porta = 6000 - Porta del server
Il metodo Button1Click è associato all'evento OnClick del componente Button1. Quando si fa clic sul pulsante, viene chiamato questo metodo. La parte Indy di questo metodo può essere ridotta a quanto segue: 1. Connettersi al server (Connect;) 1. Leggere il saluto dal server. 1.Per ogni riga inserita dall'utente in TMemo: 1.Invia una richiesta al server (WriteLn ("ZipCode" + memoInput.Lines [i]);) 1.Leggi una risposta dal server (s: = ReadLn; ) 1.Inviare il comando Esci (WriteLn ("Esci");) 1.Disconnetti (Disconnetti;)
test
Questo esempio è stato testato e funziona con TCP/IP installato. Puoi cambiarlo per funzionare in rete da un computer all'altro. Avviando il server su un altro computer e modificando il nome del server o l'IP sul client.
Per testare i progetti, compilare ed eseguire il server. Quindi compilare ed eseguire il client. Inserisci il codice postale nel campo del promemoria e premi il tasto di ricerca.
Debug
I protocolli basati su testo sono molto facili da eseguire il debug in quanto possono essere verificati con Telnet. Per fare ciò, è sufficiente conoscere la porta del server. Il server di ricerca CAP è in ascolto sulla porta 6000.
Avvia nuovamente il server di ricerca del codice postale. Quindi apri una console (come una finestra Dos). Ora inserisci:
telnet 127.0.0.1 6000
Ora sei connesso al server. Alcuni server invieranno contemporaneamente un messaggio di benvenuto. Alcuni no. Non vedrai le righe che inserisci. La maggior parte dei server non echeggia per risparmiare larghezza di banda. Tuttavia, è possibile modificare le impostazioni telnet impostando il parametro "Echo On". In diversi client telnet ciò avviene in modi diversi e alcuni non hanno affatto tale opportunità. Ora inserisci:
codice postale 37642
Vedrai la risposta del server:
COLLINA DELLA CHIESA, TN
Per disconnettersi dal server, inserire:
smettere
Esempio 2: accesso a un database
Questo esempio emula un server che deve eseguire attività di blocco diverse dalle chiamate socket. Molti server sono costretti a lavorare in tali condizioni. I server che devono accedere al database, chiamate a procedure esterne o calcoli spesso non possono interrompere queste chiamate, perché si tratta di chiamate esterne o per la complessità di queste. L'accesso al database non può essere suddiviso in piccoli blocchi e lo sviluppatore deve attendere la fine dell'operazione con il database. Questa è una caratteristica non solo delle chiamate al database, ma anche di altre operazioni come compressione, calcoli e altre elaborazioni dello stesso tipo.
A scopo dimostrativo, supponiamo che il server effettui una chiamata al database che impiega 5 secondi per il completamento. Per semplicità, facciamolo con una pausa, usa la funzione Sleep (5000) per questo, invece di chiamare effettivamente.
Questo esempio richiede anche meno dettagli rispetto all'esempio precedente, poiché molti concetti non sono ancora stati compresi.
fonte

unità principale;

interfaccia

usa

Windows, Messaggi, SysUtils, Classi, Grafica, Controlli, Moduli, Finestre di dialogo,

IdBaseComponent, IdComponent, IdTCPServer;

genere

TformMain = classe (TForm)

IdTCPServer1: TIdTCPServer;

procedura IdTCPServer1Execute (AThread: TIdPeerThread);

privato

pubblico

fine;

FormMain: TformMain;

implementazione

(R * .DFM)

procedura TformMain.IdTCPServer1Execute (AThread: TIdPeerThread);

io: intero;

inizio

con AThread.Connection inizia

WriteLn ("Ciao. DB Server pronto.");

I: = StrToIntDef (ReadLn, 0);

// Sleep è sostituito da un lungo DB o da un'altra chiamata

Sonno (5000);

WriteLn (IntToStr (i * 7));

fine;

fine;

fine.

Poiché l'evento Execute si verifica nel contesto di un thread, il codice di elaborazione può essere di qualsiasi lunghezza. Ogni client ha il proprio thread e non blocca gli altri client.
test
Per testare il server DB, compilalo ed eseguilo. Connettiti a lui usando Telnet sulla porta 6001. Il server risponderà con un messaggio di saluto. Inserisci il numero. Il server "processerà" la tua richiesta e risponderà in 5 secondi.

 

 

È interessante: