Oppure

Loading
17/01/11 17:09
Neo1986
Ciao a tutti!

seguendo parecchi tutorial in giro per il web, sono riuscito a realizzare una dll per la gestione della comunicazione ethernet tcp/ip, in questa ho implementato sia lato server, sia lato client.

Il mio problema è questo:

Possibile che io riesca ad inviare solamente circa 100messaggi al secondo tramite ethernet? (ogni messaggio è composto circa da 100byte).

I 2 pc interessati sono in rete ad 1gb (cavo e hub apposito)...

Avete qualche idea?

Ho provato anche a ridimensionare i buffer di lettura e scrittura in qualsiasi modo... ma niente... non cambia di una virgola.

Help ! :k:


Edit del 23/02/2011

Dopo un mese di test ho scoperto la causa, dovevo semplicemente impostare il time base, senza questo, quando si riechiede uno sleep di 1ms, il sistema operativo (non essendo real time) fa una pausetta caffè di 15ms!

Ora invio e ricevo circa 8000 parametri al secondo (stringhe al secondo)
Ultima modifica effettuata da Neo1986 23/02/11 8:07
aaa
17/01/11 17:18
HeDo

la banda teorica di una 1Gbit è di 1024 / 8 = 128 MB/sec = 131072 KB/sec = 134217728 Byte/sec

ipotizzando una banda di 3/4 a causa di latenze varie e perdita dei cavi/switch/etc.. è cmq molto di più di quanto hai rilevato.

sicuramente il problema sta nella gestione di questi pacchetti, c'è troppo overhead di gestione o lato client o lato server.
mostra il codice e partiamo da lì.
aaa
20/01/11 9:28
Neo1986
Apre la connessione e avvia i thread per la scrittura e la ricezione dei dati

Public Sub Thread_Server()
        server = Nothing
        Try

            Dim localAddr As IPAddress = IPAddress.Parse(_IndirizzoIPServer)

            server = New TcpListener(localAddr, _Porta)

            ' Start listening for client requests.
            server.Start()

            ' Enter the listening loop.
            While Connessione = True

                ' Perform a blocking call to accept requests.
                ' You could also user server.AcceptSocket() here.
                Dim client As TcpClient = server.AcceptTcpClient()
                _StatoConnessione += 1

                'creo il thread di scrittura per il client appena connesso
                ThreadScrittura = New Thread(New ParameterizedThreadStart(AddressOf Thread_Server_Write))
                ThreadScrittura.Start(client)

                'creo il thread di lettura per il client appena connesso
                ThreadLettura = New Thread(New ParameterizedThreadStart(AddressOf Thread_Server_Read))
                ThreadLettura.Start(client)

                'pausa per far lavorare gli altri thread
                Threading.Thread.Sleep(1)

            End While
        Catch e As SocketException
            '_Errore = "Eccezione Socket : " + e.ToString
        Finally
            server.Stop()
        End Try

    End Sub


Trasmette su tcp/ip il testo contenuto nella variabile DaScrivere

Public Sub Thread_Server_Write(ByVal client As Object)

        Try
            Dim ClientScrittura As TcpClient = client

            ClientScrittura.NoDelay = True
            ClientScrittura.SendBufferSize = 65536

            ' Get a stream object for reading and writing
            Dim stream As NetworkStream = ClientScrittura.GetStream()

            While ContinuaLettura = True

                If DaScrivere <> "" Then
                    Dim msg As Byte() = System.Text.Encoding.ASCII.GetBytes(_DaScrivere + vbCrLf)

                    _DaScrivere = ""

                    ' Send back a response.
                    stream.Write(msg, 0, msg.Length)

                    stream.Flush()

                End If

                'pausa per far lavorare gli altri thread
                Threading.Thread.Sleep(1)

            End While

            ClientScrittura.Close()

        Catch ex As Exception

        End Try

    End Sub


Riceve i dati da tcp/ip e li memorizza nella variabile DaLeggere

Public Sub Thread_Server_Read(ByVal client As Object)

        Dim ClientLettura As TcpClient = client

        ClientLettura.NoDelay = True
        ClientLettura.ReceiveBufferSize = 65536

        Try

            ' Buffer for reading data
            Dim bytes(65536) As Byte
            Dim data As String = Nothing

            data = Nothing

            ' Get a stream object for reading and writing
            Dim stream As NetworkStream = ClientLettura.GetStream()

            Dim i As Int32

            ' Loop to receive all the data sent by the client.
            i = stream.Read(bytes, 0, bytes.Length)

            While (i <> 0 And ContinuaLettura = True)
                ' Translate data bytes to a ASCII string.
                data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
                _DaLeggere += data

                i = stream.Read(bytes, 0, bytes.Length)

                'pausa per far lavorare gli altri thread
                Threading.Thread.Sleep(1)

            End While

            'aggiorno lo stato di connessione dei client
            _StatoConnessione = 0

            'chiudo il client attuale visto che è stato
            'disconnesso
            ClientLettura.Close()

        Catch ex As Exception
            'aggiorno lo stato di connessione dei client
            _StatoConnessione = 0

            'chiudo il client attuale visto che è stato
            'disconnesso
            ClientLettura.Close()
        End Try

    End Sub


Tieni presente che i buffer sono così grandi a causa di svariate prove, sia a diminuirlo che aumentarlo la quantità di dati ricevuti non cambia...

:hail:
aaa
20/01/11 11:18
HeDo

allora, non hai specificato cosa contiene la variabile DaScrivere, da queste righe posso dedurre che è del testo:

data = System.Text.Encoding.ASCII.GetString(bytes, 0, i)
                _DaLeggere += data
 
                i = stream.Read(bytes, 0, bytes.Length)
 
                'pausa per far lavorare gli altri thread
                Threading.Thread.Sleep(1)



questi dati provengono presumibilmente da un file, giusto?
avrai da qualche parte ReadAllText di un file di testo molto grosso.

Ipotizzando tutto questo ti assicuro che non è il metodo migliore quello che stai adottando, il primo punto è su _DaLeggere += data.
il clr deve istanziare un nuovo oggetto stringa e copiarci dentro tutto il nuovo contenuto AD OGNI iterazione, è una pessima cosa per le performances e la memoria utilizzata.

Ad ogni modo è proprio tutto l'approcio è che inefficiente, il modo migliore per inviare una qualsiasi ingente mole di dati attraverso socket è appoggiarsi al metodo CopyTo della classe Stream. Mi spiego meglio.
Se vuoi inviare un file attraverso socket, la cosa migliore da fare è aprire uno stream verso il file SENZA leggerne il contenuto esplicitamente e chiamare una CopyTo sul networkstream. In una riga:

File.OpenRead("ciao.txt").CopyTo(client.GetStream())


se vuoi rendere la cosa asincrona puoi usare la nuova TaskParallelLibrary:

Parallel.Invoke(Function() File.OpenRead("ciao.txt").CopyTo(client.GetStream()))


per ricevere i dati crei uno stream in uscita verso il file che vuoi scrivere e di volta in volta ci scrivi dentro tutto il contenuto del networkstream:


Dim stream As NetworkStream = client.GetStream()
Dim writer As StreamWriter = File.OpenWrite("ciao.txt")

' Va dentro un ciclo
If stream.DataAvailable Then
	stream.CopyTo(writer)
End If



in linea di massima è sempre meglio far gestire il buffering al CLR piuttosto che provarci a mano, si elimina un layer di overhead.



aaa
20/01/11 15:22
Neo1986
Ok, allora penso di aver capito in parte quello che mi stai dicendo, però forse non ho detto tutto...

Quelle 3 sub sono contenute in una dll, la variabile : DaScrivere, è come hai detto tu una proprietà string esposta dalla dll.

Non voglio assolutamente che mi scrivi tu il codice, ma...

Come potrei fare per inviare dall'esterno, del testo alla dll in modo più efficente di quello che ho fatto io?

Praticamente vorrei utilizzare questa dll in diversi programmi, magari inviare l'intero contenuto di un file di testo, oppure semplicemente passare una frase alla variabile DaScrivere (come il mio caso attuale)....

In sostanza non capisco come fare quello che hai detto:

il clr deve istanziare un nuovo oggetto stringa e copiarci dentro tutto il nuovo contenuto AD OGNI iterazione, è una pessima cosa per le performances e la memoria utilizzata.



aaa
20/01/11 16:44
HeDo
Postato originariamente da Neo1986:

Ok, allora penso di aver capito in parte quello che mi stai dicendo, però forse non ho detto tutto...

Quelle 3 sub sono contenute in una dll, la variabile : DaScrivere, è come hai detto tu una proprietà string esposta dalla dll.

Non voglio assolutamente che mi scrivi tu il codice, ma...

Come potrei fare per inviare dall'esterno, del testo alla dll in modo più efficente di quello che ho fatto io?

Praticamente vorrei utilizzare questa dll in diversi programmi, magari inviare l'intero contenuto di un file di testo, oppure semplicemente passare una frase alla variabile DaScrivere (come il mio caso attuale)....

In sostanza non capisco come fare quello che hai detto:

il clr deve istanziare un nuovo oggetto stringa e copiarci dentro tutto il nuovo contenuto AD OGNI iterazione, è una pessima cosa per le performances e la memoria utilizzata.



se si inviano files ci vogliono procedure adatte ed ottimizzate per l'invio di files, se si inviano brevi frasi di testo ci vuole altro, se si inviano immagini ci vuole altro ancora, etc...

per ogni cosa c'è la sua procedura più o meno ottimizzata ma specifica per l'implementazione, cosa che tu, facendo così, ti perdi.

ad ogni modo se proprio proprio devi passare per una variabile che contiene il testo da inviare, puoi usare il memorystream:


MemoryStream stream = new MemoryStream(Encoding.Default.GetBytes(DaInviare));

stream.CopyTo(client.GetStream());



aaa