Wednesday 8 November 2017

Winsock Send Dati Binari Options


L'invio di dati binari Via UDP Protocol (Winsock) sto facendo un programma client che richiede i dati binari da inviare al server tramite il protocollo UDP. (Im utilizzando il controllo del Winsock) Ive stato utilizzando il seguente codice. Bytex Dim come Byte Dim X as Long Dim FileX come interger Winsock3.LocalPort 10000 Winsock3.RemoteHost 211.233.70.51 Winsock3.RemotePort 9500 FileX FreeFile Aprire App. Path udp1.dat per Binary come FileX X 1 Do Until X FileLen (App. Path udp1.dat) 1 Get FileX. X, Bytex Winsock3.SendData Bytex X X 1 Loop Chiudi FileX Quando invio dati in questo modo, esso invia 52 pacchetti contenenti 1 byte ogni anziché 1 pacchetto contenente 52 byte. Questo codice funziona correttamente per il protocollo TCP, UDP ma doesnt lavoro lo stesso. Come posso inviare i dati binari utilizzando il protocollo UDP che invieranno solo 1 pacchetto di dati che sto facendo un programma client che richiede i dati binari da inviare al server tramite il protocollo UDP. (Im utilizzando il controllo Winsock):: Ive stato utilizzando il seguente codice. :: Bytex Dim come Byte: Dim X come lungo: Dim FileX come interger:: Winsock3.LocalPort 10000: Winsock3.RemoteHost 211.233.70.51: Winsock3.RemotePort 9500:: FileX FreeFile: Aperto udp1.dat App. Path per Binary come FileX : X 1: Do Until X FileLen (App. Path udp1.dat) 1: Get FileX. X, Bytex: Winsock3.SendData Bytex: X X 1: loop: Chiudi FileX:: Quando invio dati in questo modo, esso invia 52 pacchetti contenenti 1 byte ogni anziché 1 pacchetto contenente 52 byte. Questo codice funziona correttamente per il protocollo TCP, UDP ma doesnt lavoro lo stesso. Come posso inviare i dati binari utilizzando il protocollo UDP che invieranno solo 1 pacchetto di dati: Ciao Prova questo Winsock3.Protocol sckUDPProtocol Winsock ha sckTCPProtocol di default .. purpleDont prendere la vita troppo sul serio in ogni caso si suol fuggire vivo da itpurplesending dati binari utilizzando Winsock Im mi dispiace, stai dicendo che devo usare Datagram invece di stream socket per avere questo lavoro che sto usando SOCKSTREAM in questo momento, e preferirei rimanere con esso. C'è un modo di ottenere questo ad accettare la 0x00 e di accettare i dati dopo che, pur utilizzando stream socket. Ancora una volta, grazie per tutto il vostro aiuto. mikyu Hmm, questo è strano. Ho pensato che l'argomento SOCKDGRAM dovrebbe specificare i dati binari, al contrario di SOCKSTREAM. : Il recv dovrebbe leggere oltre eventuali zeri in quel caso. : Sei sicuro che non sta acquisendo i dati in una stringa di tipo di dati che si sta stampando o la scrittura su un file o qualcosa con un uno dei STR-routine: Voglio dire, sei sicuro che sta visualizzando i dati ricevuti correttamente mi dispiace, stai dicendo che devo usare Datagram invece di stream socket per avere questo lavoro che sto usando SOCKSTREAM in questo momento, ed io preferirei rimanere con esso. C'è un modo di ottenere questo ad accettare la 0x00 e di accettare i dati dopo che, pur utilizzando stream socket. Ancora una volta, grazie per tutto il vostro aiuto. : Mikyu:. Hmm, questo è strano. Ho pensato che l'argomento SOCKDGRAM dovrebbe specificare i dati binari, al contrario di SOCKSTREAM. . Il recv dovrebbe leggere oltre eventuali zeri in quel caso. . Sei sicuro che non sta acquisendo i dati in una stringa di tipo di dati che si sta stampando o la scrittura su un file o qualcosa con un uno dei STR-routine. Voglio dire, sei sicuro che sta visualizzando correttamente i dati ricevuti: SOCKDGRAM non significa dati binari. Ciò significa che si desidera utilizzare il protocollo UDP per inviare i dati ei dati vengono inviati in datagrammi. SOCKSTREAM significa che si desidera utilizzare il protocollo TCP e inviare i dati come flusso. Presa cura doesnt che tipo di dati si sta inviando. Tutto ciò che serve è il puntatore al buffer che contiene i dati e lunghezza del buffer. Zero dati all'interno non significa nulla, è solo pari a zero. Dati isnt terminata da zero come C-stringhe sono. Presa la cura doesnt sul contenuto dei dati. Penso che ci sia qualcosa di sbagliato con riceva il codice. Forse si sta utilizzando come terminatore zero non, che è cosa molto brutta. Se si potesse inserire il codice che riceve i dati qui ho potuto cercare di scoprire che cosa è sbagliato con esso. Ecco il codice che sto usando. Ancora una volta, Sono un Winsock quindi per favore abbiate pazienza con me. Grazie codice INT del server (void) unsigned char recmsg3072 PRESA serverfd, clientfd ascolto su sockfd, nuova connessione sul newfd SOCKADDRIN SERVERADDR SOCKADDRIN clientaddr int len ​​int j int msgsize 0 char domanda WSADATA WSAData unsigned short verrequest FILE mike LINGER LingVar verrequest MAKEWORD (2,2 ) if (WSAStartup (verrequest ampwsadata,) -1) printf (Couldnt trovare un DLL Winsock utilizzabile) uscita (1) if ((presa serverfd (AFINET, SOCKSTREAM, 0)) -1) perror (SERVER SIDE: zoccolo non può aprire) LingVar. lonoff TRUE LingVar. llinger 0 if (setsockopt (serverfd, SOLSOCKET, SOOOBINLINE, (char FAR) ampLingVar, sizeof (LingVar)) -1) perror (SERVER SIDE: non può eseguire setsockopt) uscita (1) serveraddr. sinfamily AFINET SERVERADDR. sinport htons (SERVERPORT) serveraddr. sinaddr. saddr htonl (INADDRANY) memset (amp (serveraddr. sinzero), 8) if (bind (serverfd, (struct sockaddr) ampserveraddr, sizeof (SERVERADDR)) -1) perror (SERVER SIDE: non si può associare la porta) di uscita (1) se (ascolta (serverfd, PACKETQUEUE) -1) (Server Side perror: non può ascoltare la presa), uscita (1) memset (recmsg, 0x0, 3072), mentre (1) printf (Do si desidera continuare (YN)) domanda getchar () se (domanda) domanda getchar () se (domanda n domanda n) return 0 printf (Server Side: in attesa di dati sulla porta) len sizeof (clientaddr) clientfd accetta (serverfd, (struct sockaddr) ampclientaddr, amplen) se (clientfd -1) perror (Server Side: non può accettare il collegamento) di ritorno ERROR printf (Server Side: ha ricevuto connessione da: s, inetntoa (clientaddr. sinaddr)) msgsize readline (recmsg, clientfd, clientaddr) se (msgsize ERROR) printf (Server Side: Impossibile leggere il messaggio) coutltltthis è la dimensione del messaggio: fwrite ltltmsgsizeltltendl (recmsg, sizeof (short int), 10, Mike) per (J0 jlt10 j) printf (- c, recmsgj ) closesocket (clientfd) se (WSACleanup () -1) perror (Problemi con WSACleanup) uscita (1) int readline (char buf, PRESA sd, SOCKADDRIN clientaddr) char segMAXDATA int compensare 0 int res 1 int cliLen memset (seg, 0x0, MAXDATA) cliLen sizeof (clientaddr) while ((res recvfrom (sd, seg, MAXDATA, 0, (struct sockaddr) ampclientaddr, ampcliLen)) Errore socket) if (resEOFresWSAECONNRESETresWSAECONNABORTED) lato 0Altre cessa a conn printf (client terminato connessione) compensato ritorno memcpy (bufoffset, seg, res) compensato res memset (seg, 0x0, MAXDATA) codice di ritorno ERROR: SOCKDGRAM dati non significa binari. Ciò significa che si desidera utilizzare il protocollo UDP per inviare i dati ei dati vengono inviati in datagrammi. SOCKSTREAM significa che si desidera utilizzare il protocollo TCP e inviare i dati come flusso. :: Socket cura doesnt che tipo di dati si sta inviando. Tutto ciò che serve è il puntatore al buffer che contiene i dati e lunghezza del buffer. :: Zero all'interno dei dati non significa nulla, è solo pari a zero. Dati isnt terminata da zero come C-stringhe sono. Presa la cura doesnt sul contenuto dei dati. :: Penso che ci sia qualcosa di sbagliato con riceva il codice. Forse si sta utilizzando come terminatore zero non, che è cosa molto brutta. Se si potesse inserire il codice che riceve i dati qui ho potuto cercare di scoprire che cosa è sbagliato con esso. : Un intro a Windows presa di programmazione con C Cosa abbiamo in questo capitolo 1 parte 4 Trasmissione Dati send () e WSASend () WSASendDisconnect () Out-of-Band dati recv () e WSARecv () WSARecvDisconnect () Stream Protocolli Scatter - Gather IO Rompere il closesocket arresto Connection () () TCP ReceiverServer con select () Esempio Trasmissione dati send () e WSASend () WSASendDisconnect () out-of-band dati recv () e WSARecv () la richiesta completerà ricevere solo quando si verifica uno dei seguenti eventi: il buffer fornito dal chiamante è completamente pieno. La connessione è stata chiusa. La domanda è stata ritirata o verificato un errore. Si noti che se il trasporto sottostante non supporta MSGWAITALL, o se la presa è in una modalità non-bloccante, allora la chiamata sarà sicuro con WSAEOPNOTSUPP. Inoltre, se MSGWAITALL è specificato con MSGOOB, MSGPEEK o MSGPARTIAL, allora questa chiamata non riuscirà con WSAEOPNOTSUPP. Questo flag non è supportato su datagram socket o socket CO orientati ai messaggi. Naturalmente, 0 specifica senza azioni speciali. MSGPEEK provoca i dati che sono disponibili da copiare nel buffer di ricezione. ma questi dati non viene rimosso dal buffer sistemi. Il numero di byte in sospeso viene anche restituito. Sbirciare messaggio è male. Non solo degradare le prestazioni, come è ora necessario effettuare due chiamate di sistema (uno per sbirciare e una senza la bandiera MSGPEEK per rimuovere effettivamente i dati), ma è anche poco affidabile in determinate circostanze. I dati restituiti potrebbero non riflettere l'intero importo disponibile. Inoltre, lasciando i dati nei buffer di sistema, il sistema ha meno spazio per contenere i dati in ingresso. Come risultato, il sistema riduce la dimensione della finestra TCP per tutti i mittenti. Questo impedisce l'applicazione di raggiungere la velocità massima possibile. La cosa migliore da fare è quella di copiare tutti i dati possibili nella propria buffer e manipolarlo lì. Ci sono alcune considerazioni quando si usa recv () su un socket messaggio - o datagramma basati come UDP, che descriveremo in seguito. Se l'attesa dei dati è più grande del buffer fornito, il buffer viene riempito con quanti più dati conterrà. In tal caso, la chiamata recv () genera il WSAEMSGSIZE errore. Si noti che il messaggio di errore di dimensioni si verifica con i protocolli orientati ai messaggi. protocolli flusso come dati in ingresso del buffer TCP e tornerà quanti più dati l'applicazione richiede, anche se la quantità di dati in attesa è maggiore. Così, per i protocolli di streaming non incontrerete l'errore WSAEMSGSIZE. La funzione WSARecv () aggiunge alcune nuove funzionalità oltre recv (), come sovrapposte IO e notifiche datagramma parziali. La definizione di WSARecv () è: Parametro s è il socket connesso. Il secondo e il terzo parametro sono i buffer per ricevere i dati. Il parametro lpBuffers è un array di strutture WSABUF, e dwBufferCount indica il numero di strutture WSABUF nella matrice. Il parametro lpNumberOfBytesReceived indica il numero di byte ricevuti da questa chiamata se l'operazione di ricezione completato immediatamente. Il parametro lpFlags può essere uno dei valori MSGPEEK, MSGOOB o MSGPARTIAL, o un bit per bit o una combinazione di questi valori. Il flag MSGPARTIAL ha diversi significati diversi a seconda di dove viene utilizzato o rilevato. Per i protocolli orientati ai messaggi che supportano i messaggi parziale (come AppleTalk), questo flag è impostato al ritorno da WSARecv () (se l'intero messaggio non può essere restituito in questa chiamata a causa di spazio buffer insufficiente). In questo caso, la successiva WSARecv () chiama impostato questo flag fino a quando l'intero messaggio viene restituito, quando si cancella il flag MSGPARTIAL. Se viene passato questo flag come parametro di input, l'operazione di ricezione deve completare non appena i dati sono disponibili, anche se è solo una parte dell'intero messaggio. La bandiera MSGPARTIAL viene utilizzato solo con i protocolli orientati ai messaggi, non con lo streaming quelli. Inoltre, non tutti i protocolli supportano i messaggi parziali. La voce di protocollo per ogni protocollo contiene un flag che indica se supporta questa funzionalità. I parametri lpOverlapped e lpCompletionRoutine sono utilizzati in operazioni di IO sovrapposti, discusso nel capitolo altro. C'è un altro specializzato riceve la funzione si dovrebbe essere a conoscenza di: WSARecvDisconnect (). WSARecvDisconnect () Questa funzione è l'opposto di WSASendDisconnect () ed è definito come segue: int WSARecvDisconnect (PRESA s, LPWSABUF lpInboundDisconnectData) Come la sua controparte invio, i parametri di WSASendDisconnect () sono la maniglia socket connesso e una struttura WSABUF valida con il i dati da ricevere. I dati ricevuti possono essere solo dati scollegando che viene inviato da un WSASendDisconnect () sul lato opposto non può essere utilizzato per ricevere dati normali. Inoltre, una volta ricevuti i dati, questa funzione disabilita la ricezione dalla postazione remota, che equivale a chiamare la funzione di arresto () (descritta in seguito) con SDRECEIVE. Protocolli flusso Poiché la maggior parte di comunicazione orientata alla connessione, come TCP, in streaming protocolli, ben descrivere brevemente qui. Un protocollo di streaming è quella che il mittente e il destinatario possono rompere o fondersi dati in gruppi più piccoli o più grandi. Figura seguente descrive brevemente il flusso di pacchetti TCP tra client e server lati. La cosa principale da tenere presente con qualsiasi funzione che invia o riceve dati su un socket di flusso è che non sono garantiti per leggere o scrivere la quantità di dati è richiesta. Diciamo che avere un buffer di caratteri con 2048 byte di dati che si desidera inviare con la funzione di invio. Il codice per inviare questa è: int nBytes 2048 Fill sendbuff con 2048 byte di dati supponga s è un valido, socket di flusso collegato ret send (s, sendbuff, nBytes, 0) è possibile inviare per tornare aver inviato meno di 2048 byte . La variabile ret viene impostato al numero di byte inviati perché il sistema alloca una certa quantità di spazio di buffer per ogni zoccolo per inviare e ricevere dati. Nel caso di invio di dati, i buffer interni tengono dati da trasmettere fino a quando i dati possono essere immessi sul filo. Diverse situazioni comuni possono causare questo. Ad esempio, è sufficiente la trasmissione di una quantità enorme di dati farà sì che questi buffer di diventare riempita rapidamente. Inoltre, per TCPIP, non v'è ciò che è noto come la dimensione della finestra (finestra scorrevole demo). La fine di ricevere regolerà questa dimensione della finestra per indicare la quantità di dati può ricevere. Se il ricevitore viene inondato di dati, potrebbe impostare le dimensioni della finestra a 0 al passo con i dati in sospeso. Questo costringerà il mittente di fermarsi fino a quando non riceve una nuova dimensione della finestra maggiore di 0. Nel caso della nostra chiamata di invio, ci potrebbe essere spazio di buffer per contenere solo 1024 byte, nel qual caso si avrebbe a ripresentare i restanti 1024 byte. Il codice seguente modo tutte le byte vengono inviati: int nBytes 2048, Nleft, IDX Fill sendbuff con 2048 byte di dati, mentre (Nleft gt 0) Si supponga s è una valida, collegati presa flusso cose si fanno un po 'complicato se le dimensioni dei messaggi variano . E 'necessario imporre il proprio protocollo di lasciare che il ricevente sa quanto è grande il prossimo messaggio sarà. Ad esempio, i primi quattro byte scritti al ricevitore sarà sempre la dimensione in byte intero del prossimo messaggio. Il ricevitore inizierà ogni letto guardando i primi quattro byte, convertendoli in un intero, e determinare il numero di byte aggiuntivi che comprende il messaggio. Scatter-Raccogliere IO scatter-gather supporto è un concetto originariamente introdotta in Berkeley Sockets con le funzioni recv e writev. Questa funzione è disponibile con le funzioni WSARecv Winsock 2 (), WSARecvFrom (), WSASend (), e WSASendTo (). E 'più utile per le applicazioni che inviano e ricevono dati formattati in un modo molto specifico. Ad esempio, i messaggi da un client a server possono sempre essere composti da un'intestazione 32-byte fisso specificando qualche operazione, seguito da un blocco di dati di 64 byte e terminato con un rimorchio 16 byte. In questo esempio, WSASend () può essere chiamato con una serie di tre strutture WSABUF, ciascuna corrispondente ai tre tipi di messaggi. Sul lato ricevente, WSARecv () viene chiamato con tre strutture WSABUF, ciascuna contenente i buffer di dati di 32 byte, 64 byte e 16 byte. Quando si usano stream socket-based, scatter-gather operazioni semplicemente trattano i buffer di dati forniti nelle strutture WSABUF come un buffer contiguo. Inoltre, la chiamata riceverà potrebbe tornare prima di tutti i buffer sono pieni. Sui socket basati sui messaggi, ogni chiamata a un'operazione di ricezione riceve un singolo messaggio fino alla dimensione buffer fornito. Se lo spazio del buffer è insufficiente, la chiamata genera WSAEMSGSIZE ei dati vengono troncati per adattarsi allo spazio disponibile. Naturalmente, con i protocolli che supportano i messaggi parziali, la bandiera MSGPARTIAL può essere usato per prevenire la perdita di dati. Rompere il collegamento Una volta che si è finito con una connessione socket, è necessario chiuderlo e liberare tutte le risorse associate a tale handle di socket. Per effettivamente rilasciare le risorse associate con una maniglia socket aperto, utilizzare la chiamata closesocket (). Essere consapevoli, tuttavia, che closesocket () può avere alcuni effetti negativi, a seconda di come viene chiamato, che può portare alla perdita di dati. Per questo motivo, una connessione deve essere gentilmente terminato con la funzione di arresto () prima di una chiamata alla funzione closesocket (). Queste due funzioni API sono discussi successivo. shutdown () Per assicurare che tutti i dati inviati da un'applicazione viene ricevuto dal peer, un'applicazione ben scritta deve notificare al ricevitore che non più dati da trasmettere. Allo stesso modo, il peer dovrebbe fare lo stesso. Questo è noto come una chiusura regolare e viene eseguito dalla funzione di spegnimento (), definito come: int arresto (PRESA s, int come) Il come parametro può essere SDRECEIVE, SDSEND o SDBOTH. Per SDRECEIVE, chiamate successive a qualsiasi ricevono funzione della presa sono consentiti. Ciò non ha alcun effetto sui livelli di protocollo inferiori. E per socket TCP, se i dati è in coda per ricevere o se i dati arrivano in seguito, il collegamento viene ripristinato. Tuttavia, il socket UDP dati in ingresso viene ancora accettata e coda (perché l'arresto () non ha alcun significato per protocolli senza connessione). Per SDSEND, le successive chiamate a qualsiasi funzione di invio non sono consentite. Per i socket TCP, questo provoca un pacchetto FIN da generare dopo tutti i dati vengono inviati e riconosciuto dal ricevitore. Infine, specificando SDBOTH disabilita sia invia e riceve. Si noti che non tutti i protocolli orientati alla connessione supportano chiusura grazia, che è ciò che i shutdown () esegue API. Per questi protocolli (come ATM), solo closesocket () deve essere chiamato per terminare la sessione. Un flag che descrive il tipo di funzionamento è riassunto nella seguente tabella. I valori possibili per questo flag sono elencati nel file di intestazione Winsock2.h. Una volta che la funzione di arresto () viene chiamata per disattivare inviare, ricevere, o entrambi, non v'è alcun metodo per riattivare inviare o ricevere per la connessione socket esistente. Un'applicazione non dovrebbe fare affidamento sul fatto di poter riutilizzare una presa dopo che è stato chiuso. In particolare, un fornitore di Windows Sockets non è tenuto a sostenere l'uso di connect () su un socket che è stato arrestato. Se un'applicazione vuole riutilizzare una presa, allora la funzione DisconnectEx () dovrebbe essere chiamato con le dwFlags parametro impostato TFREUSESOCKET chiudere una connessione su un socket e preparare la maniglia presa per essere riutilizzato. Quando la richiesta DisconnectEx () completa, la maniglia presa può essere passato alla funzione AcceptEx () o ConnectEx (). Se un'applicazione vuole riutilizzare una presa, il TransmitFile () o TransmitPackets () possono essere chiamati con il parametro dwFlags impostato con TFDISCONNECT e TFREUSESOCKET di disconnessione dopo tutti i dati sono stati coda per la trasmissione e preparare la maniglia presa per essere riutilizzato. Quando la richiesta TransmitFile () completa, la maniglia presa può essere passato alla chiamata di funzione precedentemente utilizzato per stabilire la connessione, ad esempio AcceptEx () o ConnectEx (). Quando la funzione TransmitPackets () completa, la maniglia presa può essere passato alla funzione AcceptEx (). Notare che la disconnessione livello di socket è soggetta al comportamento del trasporto sottostante. Ad esempio, un socket TCP può essere soggetto allo stato TCP TIMEWAIT, causando il DisconnectEx (), TransmitFile (), o TransmitPackets () per essere ritardata. closesocket () La funzione closesocket () chiude un socket ed è definito come: int closesocket (PRESA s) Se si verifica alcun errore, closesocket () restituisce zero. In caso contrario, viene restituito un valore di Errore socket, e di un codice di errore specifico può essere recuperato chiamando WSAGetLastError (). La presa è contrassegnato come non bloccante, ma il membro Lonoff della struttura indugiare è impostato diverso da zero e il membro llinger della struttura indugiare è impostata su un valore di timeout diverso da zero. Chiamata closesocket () rilascia il descrittore di socket ed eventuali ulteriori chiamate utilizzando la presa non con WSAENOTSOCK. Se non ci sono altri riferimenti a questa presa, tutte le risorse associate con il descrittore vengono rilasciati. Questo include qualsiasi scartando i dati in coda. In attesa di chiamate sincrone emessi da qualsiasi thread in questo processo vengono annullate senza inviare alcun messaggio di notifica. In attesa di operazioni sovrapposte vengono anche annullati. Qualsiasi porta evento, routine di completamento, o il completamento che è associato con l'operazione sovrapposta viene eseguita ma con l'errore WSAOPERATIONABORTED. Inoltre, un altro fattore influenza il comportamento di closesocket (): se il Solinger opzione socket è stato impostato. Un'applicazione deve sempre avere una chiamata corrispondente a closesocket () per ogni chiamata con successo alla presa di restituire tutte le risorse di socket al sistema. TCP ReceiverServer con select () Esempio 1. Mentre in C IDE di Visual, fare clic sul menu File Menu gt Progetto sub per creare un nuovo progetto. 2. Selezionare Win32 per i tipi di progetto: e Win32 applicazione console per i modelli. Mettere il nome del progetto e la soluzione. Regolare la posizione del progetto, se necessario, e fare clic su OK. 3. Fare clic su Avanti per la pagina Win32 Application Wizard Panoramica. Provvederemo a rimuovere tutti gli elementi del progetto inutili. 4. Nella pagina Applicazione, selezionare Progetto vuoto per le opzioni aggiuntive. Lasciare gli altri come dato e fare clic su Fine. 5. Quindi, abbiamo bisogno di aggiungere nuovo file sorgente. Fare clic sul menu Progetto gt Aggiungi Nuovo Voce sub o selezionare la cartella di progetto in Solution Explorer gt Seleziona Aggiungi menù GT Scegliere Nuovo Voce sub. 6. Selezionare C File (cpp) per i modelli. Inserire il nome del file di origine e fare clic su Aggiungi. Anche se l'estensione è cpp, Visual C IDE riconoscerà che il codice sorgente utilizzato si basa sul C Compile l'opzione C Code (TC) che sarà impostato nella pagina delle proprietà del progetto in seguito come. 7. A questo punto, aggiungere il codice sorgente come indicato di seguito. Un campione della select recvTimeOutTCP () valore restituito int (presa PRESA, lungo sec, lungo usec)

No comments:

Post a Comment