• Regolamento Macrocategoria DEV
    Prima di aprire un topic nella Macrocategoria DEV, è bene leggerne il suo regolamento. Sei un'azienda o un hosting/provider? Qui sono anche contenute informazioni per collaborare con Sciax2 ed ottenere l'accredito nella nostra community!

Guida Winsock I parte

Max090

Utente Mitico
Autore del topic
20 Dicembre 2008
6.760
88
Miglior risposta
0
Il controllo Winsock ed il protocollo TCP (Prima parte)
________________________________________
Utilizzando il controllo Winsock è possibile mettere in comunicazione due computer sfruttando il protocollo TCP o UDP.
Quale protocollo utilizzare? Citando Microsoft come fonte: "[...] Il protocollo TCP (Transfer Control Protocol) consente di creare e mantenere una connessione con un computer remoto.
Utilizzando la connessione, entrambi i computer possono inviare e ricevere dati. [...] Il protocollo TCP è un protocollo basato sulla connessione ed è analogo ad un telefono, in quanto l'utente deve stabilire una connessione prima di poter procedere [...]
Il protocollo UDP (User Datagram Protocol) è un protocollo senza connessione.
A differenza del TCP, non viene stabilita alcuna connessione tra i computer [...] e la transazione tra due computer è analoga al passaggio di un messaggio che viene inviato da un computer all'altro senza che venga stabilita una connessione esplicita tra i due computer. La dimensione massima dei dati che è possibile inviare in ciascuna trasmissione dipende della rete [...].
Le applicazioni UDP possono essere applicazioni client o server.[...]"
In particolare, prendendo TCP come protocollo di riferimento, nel momento in cui i due computer sono in comunicazione, essi ricoprono dei ruoli ben definiti.
Il computer Server invia i dati a chi ne fa richiesta utilizzando la porta specificata mentre il computer Client esegue tale richiesta.
L'operazione che avviene tra Client e Server è riassumibile in tre punti fondamentali:

1. il computer Server è in attesa di richieste di comunicazione sulla porta indicata;

2. il computer Client richiede al Server l'autorizzazione ad iniziare una comunicazione;

3. una volta accettata la richiesta del Client, il computer Server invia i dati;

4. terminato lo scambio di dati la comunicazione viene chiusa

5. il computer Server torna in uno stato di attesa di eventuali richieste di comunicazione sulla porta indicata;

Prima di tutto comunque è necessario conoscere se le impostazioni TCP/IP del proprio computer sono corrette.
Questo viene fatto più che altro per una ragione di scrupolo e di curiosità in quanto settaggi errati provocherebbero maggiori disagi rispetto alla semplice impossibilità di utilizzare il controllo Winsock in un progetto Visual Basic.
Se comunque si vuole procedere al controllo, sarà necessario aprire il prompt di Dos.
Una volta visualizzato il tipico schermo nero, scrivere la seguente linea:
Ping NomeComputer

dove NomeComputer rappresenta il nome oppure l'indirizzo IP del proprio computer.
Impostazioni TCP/IP corrette generano una risposta da parte del DOS di questo tipo:


mentre una risposta nella quale compaia il messaggio "host di destinazione non raggiungibile" e che avverta che dei pacchetti di dati inviati nessuno è tornato indietro ma sono andati tutti persi, indica naturalmente un problema di settaggio.
E'inoltre possibile ricevere un messaggio del tipo:


indica invece che è stato indicato un nome oppure un indirizzo IP non corretto del computer sul quale è stato eseguita la prova.
Nel caso in cui il nome del proprio computer o dell'indirizzo IP ci risulti del tutto sconosciuto, si può aprire un nuovo progetto EXE Standard, inserire un controllo Winsock sulla form (operazioni che verranno comunque analizzate in dettaglio poco più avanti) ed aggiungere nel modulo di codice di Form1 il seguente segmento di codice:
Private Sub Form_Load()
MsgBox Winsock1.LocalHostName
End Sub

Avviando l'applicazione si riceverà una finestra di messaggio recante il nome del proprio computer.
La stessa cosa può essere fatta nel caso si voglia sapere l'identificativo IP:
Private Sub Form_Load()
MsgBox Winsock1.LocalIP
End Sub

Generalmente la cosa migliore è utilizzare il nome del computer più che l'indirizzo IP a meno che non sia decisamente certi che questo non cambierà mai (come nel caso dell'applicazione che andremo a sviluppare tra poco che, operando in locale, non richiede l'assegnazione di un indirizzo IP differente da quello indicato dalla finestra di messaggio aperta poco fa).
Prima di cominciare a dare un primo sguardo ad un progetto di esempio, sarà necessario premettere che le applicazioni distribuite dovranno in ogni caso fare riferimento al file MSWINSCK.OCX quindi si dovrà provvedere a fornirlo con l'applicazione se si vuole essere sicuri che tutti ne possano fare uso.
Un'ultima premessa: come si è visto dalla prova che abbiamo fatto appena sopra, non è assolutamente necessaria la presenza di due computer fisici differenti.
Client e Server possono infatti essere il medesimo computer e dunque coesistere in esso.
Dal prompt di DOS infatti non abbiamo fatto altro che inviarci dei pacchetti di dati e vedere se ed in quanto tempo ci sarebbero tornati indietro. La figura sottostante dovrebbe chiarire meglio il concetto.


E' importante anche avere un quadro generale di quali operazioni l'oggetto possa compiere per noi. Per questo motivo riassumiamo in tre tabelle le proprietà, i metodi e gli eventi che competono a Winsock e che permettono di essere manipolato in modo agevole.
Non è il caso di preoccuparsi troppo se non si riesce a comprendere in modo chiaro l'utilità di alcune caratteristiche di Winsock: andando avanti con lo sviluppo dell'applicazione che tra poco inizieremo verranno utilizzate gran parte delle funzioni di cui il controllo dispone.
Questa è la tabella delle proprietà:
Proprietà Descrizione Tipo di dato
BytesReceived Corrisponde al numero di bytes scambiati nell'operazione di comunicazione Client/Server. Rappresenta dunque le dimensioni dei pacchetti di dati scambiati. Tale proprietà è associata al metodo GetData; Long
LocalHostName Corrisponde al nome del computer sul quale opera l'applicazione contenente il controllo Winsock; String
LocalIP Corrisponde all'indirizzo del computer sul quale opera l'applicazione contenente il controllo Winsock; String
LocalPort E' il numero che identifica la porta attraverso la quale verrà effettuata la comunicazione Client/Server. E' una proprietà di lettura e scrittura anche in fase di esecuzione. In particolare:
• Per il client, questa proprietà definisce la porta locale dalla quale vengono inviati i dati. Se l'applicazione non richiede una determinata porta, specificare la porta 0. Il controllo effettuerà la selezione casuale di una porta. Dopo aver stabilito la connessione, la porta locale verrà utilizzata per la connessione TCP.
• Per il server, questa proprietà definisce la porta locale di attesa. Se viene specificata la porta 0, verrà utilizzata una porta casuale. Dopo aver richiamato il metodo Listen, la proprietà conterrà la porta selezionata; Long
Protocol E' il tipo di protocollo che verrà utilizzato. La scelta è tra TCP ed UDP. Prima di reimpostare questa proprietà è necessario chiudere il controllo utilizzando il metodo Close.
Le impostazioni di Protocol possono essere:
• sckTCPProtocol caratterizzato dalla costante 0 che indica l'utilizo (predefinito) del protocollo TCP;
• sckUDPProtocol caratterizzato dalla costante 1 che indica l'utilizo del protocollo UDP; val/cost
RemoteHost E' nome del computer al quale ci si connette per la richiesta di scambio dati; String
RemoteHostIP E' l'indirizzo IP del computer al quale ci si connette per la richiesta di scambio dati; String
RemotePort Rappresenta la porta alla quale connettersi per richiedere i dati. Quando viene impostata la proprietà Protocol, la proprietà RemotePort viene automaticamente impostata sulla porta predefinita appropriata di ciascun protocollo, ossia:
• porta 80 ->HTTP, utilizzata comunemente per le connessioni al World Wide Web;
• porta 21 ->FTP Long
SocketHandle E' un valore corrispondente all'handle di socket utilizzato dal controllo per comunicare con il livello Winsock. E' una proprietà di sola lettura e non disponibile in fase di progettazione. Tale proprietà sarà utilizzata per essere passata alle API Winsock. Long
State Restituisce lo stato del controllo Winsock nel momento in cui ne è richiesta la verifica.
I tipi di stato sono:
• sckClosed corrispondente al valore 0. E' l'impostazione predefinita che corrisponde allo stato 'chiuso' del controllo;
• sckOpen corrispondente al valore 1 ed indica lo stato 'aperto' del controllo;
• sckListening corrispondente al valore 2 ed indica lo stato 'in attesa di comunicazione' del controllo;
• sckConnectionPending corrispondente al valore 3 ed indica lo stato 'comunicazione in corso' del controllo;
• sckResolvingHost corrispondente al valore 4 ed indica lo stato 'risoluzione dell'host in corso' del controllo;
• sckHostResolved corrispondente al valore 5 ed indica lo stato 'host risolto' del controllo;
• sckConnecting corrispondente al valore 6 ed indica lo stato 'aperto' del controllo;
• sckConnected corrispondente al valore 7 ed indica lo stato 'connesso' del controllo;
• sckClosing corrispondente al valore 8 ed indica che il client sta chiudendo la comunicazione;
• sckError corrispondente al valore 9 ed indica un errore in un'operazione eseguita da Winsock; Long

La tabella dei metodi invece è la seguente:
Metodo Descrizione
BytesReceived Consente di accettare una richiesta di comunicazione da parte del client. Generalmente il metodo Accept viene utilizzato nell'evento ConnectionRequest ed in una nuova istanza del controllo Winsock anziché nel controllo in attesa;
Bind Specifica la porta locale e l'IP locale da utilizzare per le connessioni TCP.
La sintassi è la seguente:
Winsock.Bind PortaLocale, IPLocale
dove PortaLocale è la porta utilizzata per effettuare la connessione e IPLocale è l'indirizzo IP locale utilizzato per effettuare la connessione;
Close Chiude la comunicazione TCP o una socket in attesa per entrambe le applicazioni client e server;
Connect Invia una richiesta di connessione ad un computer remoto.
La sintassi è la seguente:
Winsock.Connect HostRemoto, PortaRemota
dove HostRemoto è il nome del computer server al quale ci si connette e PortaRemota è la porta utilizzata;
GetData Recupera il blocco di dati corrente e lo memorizza in una variabile di tipo Variant.
La sintassi è la seguente:
oggetto.GetData dati, [tipo,] [lunMax]
dove dati memorizza i dati recuperati dopo l'esecuzione del metodo. Se i dati non sono sufficienti per il tipo di richiesta, la variabile verrà impostato su Empty. tipo è invece il tipo di dati da recuperare. Il metodo GetData viene in genere utilizzato con l'evento DataArrival contenente l'argomento totalBytes. Se il valore di lunMax è minore del valore dell'argomento totalBytes, verrà visualizzato il messaggio di avviso 10040 in cui viene comunicato che i byte rimanenti andranno perduti.
Le possibili impostazioni di tipo sono le seguenti:
• vbByte Byte
• vbIntegerInteger
• vbLong Long
• vbSingle Single
• vbDouble Double
• vbCurrency Currency
• vbDate Date
• vbBoolean Boolean
• vbError SCODE
• vbString String
• vbArray + vbByte Byte Array
lunMax specifica la dimensione desiderata della matrice Byte o della stringa da ricevere. Se non viene specificata alcuna matrice Byte o stringa in questo argomento, verranno recuperati tutti i dati disponibili. Se viene specificato un tipo di dati diverso da una matrice Byte o una stringa, l'argomento verrà ignorato.
Listen Crea una socket e la imposta in modalità di attesa. Questo metodo può essere utilizzato solo per le connessioni TCP;
PeekData A differenza di GetData, il metodo PeekData non rimuove i dati dalla coda di input. Questo metodo può essere utilizzato solo per le connessioni TCP.
Tale metodo ha una sintassi praticamente simile a quella di GetData ossia:
Winsock.PeekData dati, [tipo,] [lunMax]
SendData Invia i dati al computer remoto.
La sintassi è del tipo:
Winsock.SendData dati
dove dati rappresenta il gruppo di dati da inviare. Per i dati binari, è necessario utilizzare una matrice Byte. Quando viene passata una stringa UNICODE, la stringa viene convertita in stringa ANSI prima di essere inviata dalla rete;

Si è parlato in questa tabella di socket. Un socket, come già accennato poco fa, è un oggetto attraverso il quale un'applicazione che ne fa uso in modo specifico invia o riceve dati attraverso la rete con altri socket che fanno uso dell' IPS (Internet Protocol Suite).
I socket sono bidirezionali ossia consentono allo stesso momento un flusso di dati sia in entrata che in uscita.
Esistono due tipi di socket:
• Stream sockets che consentono un flusso di dati continuo ed illimitato con la garanzia di evitare duplicazione di dati inviati.
• Datagram sockets non garantiscono che l'ordine di ricezione dei dati sia lo stesso di quello di invio col rischio di non poter evitare duplicazione di dati (cioè stessi pacchetti di dati possono arrivare a destinazione più volte).
Questa è la tabella degli eventi:
Evento Descrizione
Close Viene generato quando il computer remoto interrompe la connessione;

Connect Viene generato nel momento in cui la connessione è stata stabilita con successo;
ConnectionRequest Viene generato nel momento in cui un computer client invia una richiesta di connessione. Il server può quindi decidere se accettare o meno la comunicazione. In caso di rifiuto, il client riceverà l'evento Close ;
DataArrival Viene generato nel momento in cui un computer client riceve dei dati. L'evento viene generato nel caso in cui tutti i nuovi dati inviati col metodo GetData siano recuperati con successo. Per evitare duplicazione di pacchetti di dati solamente i nuovi dati saranno considerati.
La sintassi è la seguente:
Winsock.DataArrival (BytesTotali As Long)
dove BytesTotali rappresenta il numero di dati che possono essere recuperati;
Error Viene generato nel caso in cui si verifichi un errore qualsiasi nel procedimento di connessione, di invio, di richiesta o di chiusura della connessione.
La sintassi è la seguente:
Winsock.Error(Numero As Integer, Descrizione As String, Scode As Long, Origine As String, HelpFile as String, HelpContext As Long, CancelDisplay As Boolean)
dove Numero indica il codice dell'errore, Descrizione la descrizione dell'errore, Scode è un valore di tipo Long SCODE, Origine descrive l'origine dell'errore, HelpFile è una stringa conente il nome del file della Guida in linea, HelpContext è il contesto della Guida in linea e CancelDisplay indica l'annullamento della visualizzazione. L'impostazione predefinita (CancelDisplay = False) permette la visualizzazione di una finestra di messaggio di errore predefinita.
Di seguito sono elencati i codici degli errori:
• sckOutOfMemory corrispondente al valore 7. Descrive un errore causato dall'esaurimento della memoria;
• sckInvalidPropertyValue corrisponde al valore 380 e descrive un valore della proprietà non valido
• sckGetNotSupported corrispondente al valore 394. Descrive un errore causato dall'impossibilità di leggere la proprietà;
• sckSetNotSupported corrispondente al valore 383. Descrive un errore causato dall'impostazione di una proprietà che è di sola lettura;
• sckBadState corrispondente al valore 40006. Protocollo o stato della connessione errato per la transazione o la richiesta;
• sckInvalidArg corrispondente al valore 40014. L'argomento passato a una funzione è in un formato errato o non è compreso nell'intervallo specificato.
• sckSuccess corrispondente al valore 40017. Connessione completata.
• sckUnsupported corrispondente al valore 40018. Indica un valore di tipo Variant non supportato
• sckInvalidOp corrispondente al valore 40020. Indica un'operazione non valida
• sckOutOfRange corrispondente al valore 40021. Indica un argomento non compreso nell'intervallo.
• sckWrongProtocol corrispondente al valore 40026. Indica che è stato usato un protocollo per cui non è consentita l'operazione che si è tentato di compiere.
• sckOpCanceled corrispondente al valore 1004. L'operazione è stata annullata.
• sckInvalidArgument corrispondente al valore 10014. Indica che il flag non è stato impostato.
• sckWouldBlock corrispondente al valore 10035. Indica che non è possibile bloccare il socket sebbene ne sia stato specificato il blocco.
• sckInProgress corrispondente al valore 10036. Indica che è in corso un'operazione Winsock di blocco.
• sckAlreadyComplete corrispondente al valore 10037. Indica che l'operazione richiesta è già stata eseguita.
• sckNotSocked corrispondente al valore 10038. Indica che non si fa riferimento ad un socket.
• sckMsgTooBig corrispondente al valore 10040. Indica un datagramma troppo grosso per essere inserito nel buffer.
• sckPortNotSupported corrispondente al valore 10043. Indica che la porta specificata non può essere utilizzata per l'operazione indicata.
• sckAddressInUse corrispondente al valore 10048. Indica un indirizzo già in uso.
• sckAddressNotAvailable corrispondente al valore 10049. Indica che l'indirizzo indicato del computer locale non è valido.
• sckNetworkSubsystemFailed corrispondente al valore 10050. Indica un errore nel sottosistema di rete.
• sckNetworkUnreachable corrispondente al valore 10051. Indica che l'host non è in grado di raggiungere la rete.
• sckNetReset corrispondente al valore 10052. Indica che la connessione è stata interrotta quando è stato impostato SO_KEEPALIVE.
• sckConnectAborted corrispondente al valore 10053. Indica una connessione fallita a causa di un timeout (tempo massimo di attesa superato) o di un altro errore.
• sckConnectionReset corrispondente al valore 10054. Indica che la connessione è stata reinviata dal computer remoto.
• sckNoBufferSpace corrispondente al valore 10055. Indica che lo spazio nel buffer è esaurito.
• sckAlreadyConnected corrispondente al valore 10056. Indica che la connessione è già stata stabilita.
• sckSocketShutdown corrispondente al valore 10058. Indica che la connessione è già stata chiusa.
• sckTimedout corrispondente al valore 10068. Indica che la connessione è stata chiusa.
• sckConnectionRefused corrispondente al valore 10061. Indica che la connessione è stata rifiutata dal computer server.
• sckNotInitalized corrispondente al valore 10093. Indica che è necessario richiamare WinsockInit per primo.
• sckHostNotFound corrispondente al valore 11001. Indica che è impossibile trovare l'host in modo definitivo.
• sckInvalidArgument corrispondente al valore 11002. Indica che è impossibile trovare l'host.
• sckNotRecoverableError corrispondente al valore 11003. Indica un errore non riconoscibile.
• sckNoData corrispondente al valore 11004. Indica che non è possibile ricevere alcun tipo di dati del tipo richiesto (quando si fa uso della specifica Winsock.GetData (tipo).
SendComplete Viene generato quando tutti i dati sono stati inviati con successo;
SendProgress Viene generato quando il processo di invio dei dati è ancora in corso;

Per cominciare aprire un nuovo progetto EXE Standard. Selezionare quindi la voce 'Componenti' dal menu 'Progetto'.
Apparirà dunque la finestra denominata 'Componenti'. Nella lista che presenta, contrassegnare col segno di spunta la casella relativa alla voce 'Microsoft Winsock Control x.0' dove la x rappresenta la versione disponibile sul proprio computer.
Come si è già detto, e com'è possibile intuire dal messaggio ricevuto dalla finestra 'Componenti', è necessaria la presenza sul proprio computer del file MSWINSCK.OCX.
Nel caso in cui detto file non si trovi nella classica cartella "C:\WINDOWS\SYSTEM", premere il pulsante 'Sfoglia' della finestra 'Componenti' per ricercare la posizione effettiva nella quale è situato il file.


Dando l'OK alla finestra dovrebbe apparire tra i controlli disponibili sulla sinistra della finestra di lavoro di Visual Basic, il pulsante recante la tipica icona di Winsock proprio come mostrato dall'immagine che segue. Questo indica che il controllo è pronto ad essere utilizzatoo e trascinato sul piano, senza però la possibilità di ridimensionarlo a piacimento.


Per simulare ciò che abbiamo fatto dal Prompt di DOS, dobbiamo rendere il nostro computer sia Client che Server, permettendogli di richiedere e scambiare dati con se stesso.
A tale scopo, possiamo pensare di rinominare Form1 come frmServer, cosa che ci ricorderà in maniera semplice che l'interfaccia ed il codice sviluppati per quella form sono relative alla funzione Server del computer.
Aggiungiamo quindi a frmServer alcuni controlli. Saranno sufficienti due controlli TextBox (le caselle di testo) ed un CommandButton (il pulsante).
Siccome come abbiamo visto, il server deve stare sempre in ascolto di eventuali richieste di comunicazione che possono pervenire da altri computer, istruiamo Winsock a compiere tale operazione sulla porta 100 all'apertura dell'applicazione ossia nell'evento Load di frmServer :
Private Sub Form_Load()
Winsock1.LocalPort = 100
Winsock1.Listen
End Sub

Notare che il valore assegnato a LocalPort può essere un qualsiasi intero. Il computer client deve però essere a conoscenza della porta sulla quale il server è in attesa. In caso contrario non ci sarà alcuna risposta ad eventuali richieste di connessione.
Nel caso dell'applicazione che stiamo sviluppando risulta particolarmente semplice mettere d'accordo client e server sulla porta comune da utilizzare in quanto essi coesistono sullo stesso computer.
Abbiamo visto l'evento Load di frmServer. Adesso addentriamoci negli eventi più propriamente legati al controllo Winsock. Innanzitutto istruiamo l'applicazione nel caso in cui si verifichi una richiesta di connessione da parte del client sulla porta comune (in questo caso la 100).
Sarà necessario chiudere un'eventuale precedente connessione del server prima di accettare la nuova richiesta da parte del client. Per far ciò dobbiamo controllare la proprietà State di Winsock. Tra tutti gli stati che Winsock può assumere scegliamo 'Chiuso' e facciamo un ragionamento del tipo 'se lo stato di Winsock è 'chiuso' allora vuol dire che non è in comunicazione con nessun computer client. In questo caso si può accettare una nuova richiesta. In caso contrario (comunicazione pendente, aperta, invio dati...) lo stato di Winsock deve tornare 'chiuso'.
Traduciamo il tutto con questo blocco di codice:
Private Sub tcpServer_ConnectionRequest(ByVal requestID As Long)
If tcpServer.State <> sckClosed Then tcpServer.Close

Non chiudiamo la sottoprocedura in quanto dobbiamo aggiungere il codice che indichi a Winsock di ricevere la richiesta nel caso in cui lo stato sia 'chiuso', cosa che faremo la prossima volta.

Un po lunghina...
Fonte:
Perfavore, Entra oppure Registrati per vedere i Link!