Partage
  • Partager sur Facebook
  • Partager sur Twitter

reception de video en wifi

c# xamarin

Sujet résolu
    21 avril 2019 à 14:08:24

    Bonjour,

    Je réalise un projet qui nécessite la réception d'un fichier mp4 en wifi. Pour cela je connecte un Raspberry PI 3 (RP3) et un Samsung Galaxy J4+ (SGJ4) avec un protocole TCP. Le RP3 agit en tant que serveur et contient la vidéo et un programme codé en c++. Le SGJ4+ quant à lui doit doit recevoir la vidéo à l'aide d'un code c# (j'utilise Xamarin). Hélas, tempus fugit et je ne parviens pas à recevoir la vidéo correctement. Cependant, je parviens à écrire le bon nombre d'octets. J'ai essayé de recevoir la vidéo sur mon pc pour pouvoir observer le code binaire et le comparer avec celui de la vidéo. Je ne sais pas si ça peut servir à quelque chose, mais bon. Donc si quelqu'un pouvez m'indiquer où je fais une erreur. J'ajoute à cela que j'arrive à envoyer des données du SGJ4+ au RP3. Comme vous pourrez le voir dans le code ci-dessous, le SGJ4+ envoie une chaîne de caractères au RP3.

    Programme c# du SGJ4+

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using Xamarin.Forms;
    using System.Net.Sockets;
    using System.Net;
    using System.IO;
    using static System.Environment;
    using Xamarin.Forms.PlatformConfiguration;
    
    
    namespace ApplicationTCP
    {
        public partial class MainPage : ContentPage
        {
            public MainPage()
            {
                InitializeComponent();
            }
    
            string addressIP = "10.3.141.1"; /// adresse IP du serveur RP3
    
            string data = "2000 0 1\n3000 0 0"; /// données à envoyer -> a modifier
            /*
             * Il faut organiser les donnees ainsi :
             * - retour à la ligne entre chaque instruction
             * - 1 espace entre chaque données d'une instruction
             * - ordre des donnees : durée (ms), angle(?), devant(>=1)/arret(0)/arriere(<=1)
             * ex : "2000 0 1\n3000 0 0\n5000 -25 -1"
             */
    
            /// envoi des donnees au RP3
            void sendData(object sender, EventArgs args)
            {
                try
                {
                    TcpClient client = new TcpClient(addressIP, 26000);
                    NetworkStream ns = client.GetStream();
                    byte[] bytes = Encoding.ASCII.GetBytes(data);
                    ns.Write(bytes, 0, bytes.Length);
                    client.Close();
    
                    (sender as Button).Text = "sended"; /// test
                }
                catch (Exception e)
                {
                    (sender as Button).Text = e.ToString(); /// test
                }
            }
    
            /// reception des donnees
            void receiveData(object sender, EventArgs args)
            {
                try
                {
                    TcpClient client = new TcpClient(addressIP, 13000);
    
                    NetworkStream ns = client.GetStream();
    
    
    
                    /// obtention de la taille en octets du fichier
    
                    byte[] bytesSize = new byte[1024];
                    for (int i = 0; i < bytesSize.Length; i++)
                        bytesSize[i] = 0b0;
    
                    ns.Read(bytesSize, 0, bytesSize.Length);
    
                    int size = Convert.ToInt32(Encoding.ASCII.GetString(bytesSize));
                    int packetSize = 1024 * sizeof(double); /////
    
    
                    /// reception du fichier
    
                    byte[] bytes = new byte[1024 * sizeof(double)];
                    for (int i = 0; i < bytes.Length; i++)
                        bytes[i] = 0b0;
    
                    string filePath = Path.Combine("/storage/emulated/0/DCIM/Camera", "travelling.mp4");
                    FileStream file = new FileStream(filePath, FileMode.Create);
    
    
    
                    for (int i = 0; i < size - size % packetSize; i += packetSize)
                    {
                        ns.Read(bytes, 0, bytes.Length);
                        file.Write(bytes, 0, bytes.Length);
                    }
                    ns.Read(bytes, 0, size % packetSize);
                    file.Write(bytes, 0, size % packetSize);
    
                    file.Close();
    
                    (sender as Button).Text = "received";
    
                    client.Close();
                }
                catch (Exception e)
                {
                    (sender as Button).Text = e.ToString();
                }
            }
        }
    }
    

    Programme c++ du RP3

    #include <iostream> /// test
    
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cmath>
    
    /// lib pour les sockets
    #include <unistd.h>
    #include <netinet/in.h>
    
    
    
    #include "tcp.h"
    
    
    
    using namespace std;
    
    
    void tcp(bool r)
    {
        if (r)
        {
            Socket socket = Socket(26000);
            socket.readSocket();
            socket.~Socket();
        } else {
            Socket socket = Socket(13000);
            socket.writeSocket();
            socket.~Socket();
        }
    }
    
    
    
    Socket::Socket(int port)
    {
        serverSocket = socket(AF_INET, SOCK_STREAM, 0);
    
    
        memset(&address, 0, sizeof(struct sockaddr_in));
        address.sin_family = AF_INET;
        address.sin_port = htons(port);
        address.sin_addr.s_addr = htons(INADDR_ANY);
        bind(serverSocket, (struct sockaddr*) &address, sizeof(struct sockaddr_in));
    
        listen(serverSocket, 5);
    
        size_t size = sizeof(struct sockaddr_in);
    
        cout << "connecting..." << endl; /// test
    
        clientSocket = accept(serverSocket, (struct sockaddr*)&address, &size);
    
        cout << "connected!" << endl; /// test
    }
    
    Socket::~Socket()
    {
        close(clientSocket);
        close(serverSocket);
    }
    
    
    void Socket::readSocket()
    {
        read(clientSocket, (void*)buffer, BUFFER_SIZE);
        cout << buffer << endl;
        file = fopen("data.txt", "w");
        fputs(buffer, file);
        fclose(file);
    }
    
    void Socket::writeSocket()
    {
        file = fopen("video.mp4", "rb");
    
        //long int packet[BUFFER_SIZE] = {0}; /////
        char packet[BUFFER_SIZE*sizeof(long int)] = {0};
    
        fseek(file, 0, SEEK_END);
        int size = ftell(file);
        sprintf(buffer, "%d", size);
        cout << buffer << endl;
        write(clientSocket, buffer, log10(size)+1);
    
        size_t packetSize = BUFFER_SIZE*sizeof(long int); /////
    
        fseek(file, 0, SEEK_SET);
    
        for (int i=0; i<size; i+=packetSize)
        {
            fread(packet, sizeof(char), sizeof(long int)*BUFFER_SIZE, file);
            for (int j=0; j<BUFFER_SIZE*sizeof(long int); j++) cout << (int)packet[j] << endl;
            write(clientSocket, packet, BUFFER_SIZE*sizeof(long int));
        }
    
        cout << "sended!" << endl;
    
    
        fclose(file);
    }
    
    

    Merci de votre aide.


    -
    Edité par Quentinus Prime 21 avril 2019 à 17:42:41

    • Partager sur Facebook
    • Partager sur Twitter
      25 avril 2019 à 11:20:31

      Vous n'avez pas de débogueur dans vos environnements de développement ?

      Pas de trace d'usage de "tcp(false)" dans le code posté.

      C'est quoi ce micmac avec ces 2 port socket quand un seul fait le travail.

      Le client fait une demande sur un port, attend la réponse depuis un autre.

      Le serveur, il attend une connexion sur un port et renvoie la réponse avec le même port (ce qui est le plus logique).

      C'est quoi cette embrouille entre des "long" d'un côté et des "double" de l'autre ??? Fait un flux d'octet, c'est beaucoup moins casse-gueule.

      C'est quoi le mécanisme de séparation entre l'en-tête (la taille du fichier indiqué par une chaine de caractère à la Yolo) et le corps du message ?

      C'est clairement déjà totalement bancal sur le papier, alors, c'est totalement normal que l'implémentation va dans le décor.

      Expliquez comment vous voulez que cela fonctionne concrètement, parce que là, l'implémentation, elle est totale aux fraises.

      -
      Edité par bacelar 25 avril 2019 à 14:14:48

      • Partager sur Facebook
      • Partager sur Twitter
      Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
        25 avril 2019 à 13:51:16

        Merci de la réponse,

        Désolé, je ne suis qu’un débutant donc j’imagine en effet qu’il y a pas mal d’erreurs. J’utilise 2 ports car mon programme plantait quand je tentais de me reconnecter au même port. Je ne sais pas ce qu’est un flux d’octets, merci de m’éclairer si possible. Pour la taille du fichier, je l’ai envoyé sous chaîne de caractères car je ne savais pas comment faire ça autrement à ce moment mais je vais corriger cela.

        Pour ce qui est du fonctionnement, tout ce dont j’ai besoin, c’est d’envoyer la vidéo pour l’enregistrer sur le téléphone, qu’ai-je mal expliqué ?

        • Partager sur Facebook
        • Partager sur Twitter
          25 avril 2019 à 15:27:27

          >J’utilise 2 ports car mon programme plantait quand je tentais de me reconnecter au même port

          Pire, mais très commune pour les débutant, excuse qu'il soit. Quand il y a un truc qu'on ne comprend pas, on cherche à le comprendre, pas à égorger un poulet un soir de pleine Lune, ou encore pire, en rendant le code totalement imbittable.

          Le "problème", c'est juste que vous ne fermez pas correctement les sockets, ce qui entraine que le port reste "actif" tant que les flux restent ouverts, jusqu'au déclenchement du timeout de TCP.

          Donc, on ne corrige pas un bug en faisant une usine à gaz, mais en utilisant correctement les outils fournis. Fermez systématiques les flux, les sockets et les programmes (pas de zombis).

          Supprimez toute trace de ce 2ème port et si vous avez bien tout fermé, ça marchera tout seul.

          >Je ne sais pas ce qu’est un flux d’octets,

          C'est pour ce que vous faite dans "Socket::writeSocket" comme un flux de "long int" et dans "MainPage::receiveData" sous forme d'un flux de "double".

          Ce que je vous demande, c'est d'arrêter avec ces "long int" et "double" à la con et d'utiliser un truc qui à la même signification/représentation quelque-soit le langage ou la plateforme : un octet, donc "char" en C/C++ et "byte" en C#.

          >car je ne savais pas comment faire ça autrement

          Encore une très mauvaise excuse. ;)

          Vous ne pouvez distinguer la fin de votre chaine de caractère spécifiant la "longueur" du début de la charge utile.

          Si vous avez "subi" un cours de réseau, vous avez dû apprendre comment fonctionne des en-tête de protocole réseau, et vous n'avez qu'à faire pareil :

          Soit des champs de tailles fixes soit des champs dédiés à spécifier les tailles d'autres champs en utilisant un encodage des longueurs indépendant du langage et de la plateforme.

          • Partager sur Facebook
          • Partager sur Twitter
          Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
            27 avril 2019 à 14:00:23

            J'ai essayé d'améliorer mes programmes en tenant compte de vos conseils. Voilà à quoi ils ressemblent désormais :

            RP3

            #include <iostream> /// test
            
            #include <cstdio>
            #include <cstdlib>
            #include <cstring>
            #include <cmath>
            
            /// lib pour les sockets
            #include <unistd.h>
            #include <netinet/in.h>
            
            
            
            #include "tcp.h"
            
            
            using namespace std;
            
            void tcp(bool r)
            {
                Socket socket = Socket();
                if (r) socket.readSocket();
                else socket.writeSocket();
                socket.~Socket();
            }
            
            
            
            Socket::Socket()
            {
                serverSocket = socket(AF_INET, SOCK_STREAM, 0);
            
                memset(&address, 0, sizeof(struct sockaddr_in));
                address.sin_family = AF_INET;
                address.sin_port = htons(13000);
                address.sin_addr.s_addr = htons(INADDR_ANY);
                bind(serverSocket, (struct sockaddr*) &address, sizeof(struct sockaddr_in));
            
                listen(serverSocket, 5);
                
                size_t size = sizeof(struct sockaddr_in);
                
                cout << "connecting..." << endl; /// test
            
                clientSocket = accept(serverSocket, (struct sockaddr*)&address, &size);
                
                cout << "connected!" << endl; /// test
            }
            
            Socket::~Socket()
            {
                shutdown(clientSocket, 2);
                close(clientSocket);
                shutdown(serverSocket, 2);
                close(serverSocket);
            }
            
            
            void Socket::readSocket()
            {
                read(clientSocket, (void*)buffer, BUFFER_SIZE);
                file = fopen("data.txt", "w");
                fputs(buffer, file);
                fclose(file);
            }
            
            void Socket::writeSocket()
            {
                file = fopen("video.mp4", "rb");
                
                char packet[1024*8] = {0};
                
                fseek(file, 0, SEEK_END);
                int size = ftell(file);
                write(clientSocket, &size, 1);
                
                const size_t packetSize = 1024*8;
                
                fseek(file, 0, SEEK_SET);
                
                
                for (int i=0; i<size; i+=packetSize)
                {
                    fread(packet, sizeof(char), packetSize, file);
                    write(clientSocket, packet, packetSize);
                }
            }
            
            

            SGJ4+

            using System;
            using System.Collections.Generic;
            using System.Linq;
            using System.Text;
            using System.Threading.Tasks;
            using Xamarin.Forms;
            using System.Net.Sockets;
            using System.Net;
            using System.IO;
            using static System.Environment;
            using Xamarin.Forms.PlatformConfiguration;
            
            
            namespace ApplicationTCP
            {
                public partial class MainPage : ContentPage
                {
                    public MainPage()
                    {
                        InitializeComponent();
                    }
            
                    string addressIP = "10.3.141.1"; /// adresse IP du serveur RP3
            
                    string data = "2000 0 1\n3000 0 0"; /// données à envoyer -> a modifier
                    /*
                     * Il faut organiser les donnees ainsi :
                     * - retour à la ligne entre chaque instruction
                     * - 1 espace entre chaque données d'une instruction
                     * - ordre des donnees : durée (ms), angle(?), devant(>=1)/arret(0)/arriere(<=1)
                     * ex : "2000 0 1\n3000 0 0\n5000 -25 -1"
                     */
            
                    /// envoi des donnees au RP3
                    void sendData(object sender, EventArgs args)
                    {
                        try
                        {
                            TcpClient client = new TcpClient(addressIP, 13000);
                            NetworkStream ns = client.GetStream();
                            byte[] bytes = Encoding.ASCII.GetBytes(data);
                            ns.Write(bytes, 0, bytes.Length);
                            client.Close();
            
                            (sender as Button).Text = "sended"; /// test
                        }
                        catch (Exception e)
                        {
                            (sender as Button).Text = e.ToString(); /// test
                        }
                    }
            
                    /// reception des donnees
                    void receiveData(object sender, EventArgs args)
                    {
                        try
                        {
                            TcpClient client = new TcpClient(addressIP, 13000);
            
                            NetworkStream ns = client.GetStream();
            
            
            
                            /// obtention de la taille en octets du fichier
            
                            byte[] bytesSize = new byte[1024];
                            for (int i = 0; i < bytesSize.Length; i++)
                                bytesSize[i] = 0b0;
            
                            ns.Read(bytesSize, 0, bytesSize.Length);
            
                            int size = Convert.ToInt32(Encoding.ASCII.GetString(bytesSize));
                            int packetSize = 1024 * 8; /////
            
            
                            /// reception du fichier
            
                            byte[] bytes = new byte[1024 * 8];
                            for (int i = 0; i < bytes.Length; i++)
                                bytes[i] = 0b0;
            
                            string filePath = Path.Combine("/storage/emulated/0/DCIM/Camera", "travelling.mp4");
                            FileStream file = new FileStream(filePath, FileMode.Create);
            
            
            
                            for (int i = 0; i < size - size % packetSize; i += packetSize)
                            {
                                ns.Read(bytes, 0, bytes.Length);
                                file.Write(bytes, 0, bytes.Length);
                            }
                            ns.Read(bytes, 0, size % packetSize);
                            file.Write(bytes, 0, size % packetSize);
            
                            file.Close();
            
                            (sender as Button).Text = "received";
            
                            client.Close();
                        }
                        catch (Exception e)
                        {
                            (sender as Button).Text = e.ToString();
                        }
                    }
                }
            }
            


            Lorsque je tente de recevoir la vidéo sur mon pc, il m'indique une taille de 29 octets alors que le fichier fait 12 097 301 octets. Sur mon SGJ4+, il m'affiche l'erreur input string was not in a correct format. D'ailleurs, je reçois cette erreur même lorsque le RP3 n'envoie pas de vidéo (j'ai réalisé l'expérience malencontreusement en oubliant de mettre la vidéo dans le dossier où se trouve mon programme). Quant au RP3, le programme s'arrête soudainement alors que j'ai mis une boucle infinie dans le main.

            Par contre, j'ai bien l'impression qu'il ne se fâche plus lorsque je tente de me reconnecter au même socket.

            Pour l'en-tête, je ne vois malheuresement pas de quoi il s'agit. Serait-ce là la source de ces erreurs ?

            -
            Edité par Quentinus Prime 27 avril 2019 à 14:02:50

            • Partager sur Facebook
            • Partager sur Twitter
              30 avril 2019 à 15:44:51

              >il m'indique une taille de 29 octets

              Tu m'étonnes. :lol:

              Déjà, si vous utilisez une librairie réseau C++ comme Boost.asio et pas un vieux machin socket C tout droit sortie de Berkeley du début des années 1980 (les pattes-d'eph étaient encore populaire à cette époque, bordel), vous galéreriez bien moins.

              12 097 301 % 256 = 21 because le "1" en ligne 75 de votre code C.

              Mais bon, ça colle pas après, votre "RP3", c'est du Big ou du Little Endian ?

              Question rhétorique, votre code n'a pas à dépendre de ces détails à la con.

              Si vous voulez passer une longueur via le réseau, il faut que le nombre d'octets soit en relation avec la plage de valeur possible, et l'encodage de cette longueur doit permettre aux appareils qui dialogues se comprennent. Si vous êtes nostalgique de Gloria Gaynor :

              https://beej.us/guide/bgnet/html/multi/htonsman.html

              Mais, bon, avec une bibliothèque réseau digne de ce nom, c'est pas à vous de vous faire chier avec ces détails.

              Coté .NET, le Framework est ton ami:

              https://docs.microsoft.com/en-us/dotnet/api/system.net.ipaddress.networktohostorder?redirectedfrom=MSDN&view=netframework-4.8#overloads

              Vous ne gérez pas correctement non plus les fichiers n'ayant pas une longueur multiple de la taille de votre buffer.

              La valeur de retour de cette putain d'antiquité de fread, c'est pas juste pour faire jolie.

              Idem pour le Read .NET.

              • Partager sur Facebook
              • Partager sur Twitter
              Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                5 mai 2019 à 16:12:53

                Merci pour l'aide, j'ai repéré mon erreur stupide au niveau de la taille à indiquer et il n'y a donc plus de problème à ce niveau là. Cependant, je n'ai pas réussi à tirer parti des liens que vous m'avez envoyés. De toute manière, ayant constaté que mon programme c se fermait brutalement avant l'envoi total du fichier et que les codes binaires de la vidéo d'origine et celle reçue ne divergeaient qu'au bout de quelques octets, j'ai fait la même chose, mais avec un image. J'ai réussi à envoyer une image de 114 octets à mon ordinateur et mon programme c ne s'est pas fermé. Je pense donc que le problème vient de cette fermeture. Je n'ai pas encore testé sur le SGJ4+.
                • Partager sur Facebook
                • Partager sur Twitter
                  8 mai 2019 à 23:54:27

                  Bonjour, je suis parvenu à mes fins avec vos conseils.

                  Merci bien !

                  • Partager sur Facebook
                  • Partager sur Twitter
                    9 mai 2019 à 11:29:26

                    Pouvez-vous faire un petit retour pour voir comment vous avez appliqué nos "conseils", merci. ;)
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.
                      10 mai 2019 à 19:27:15

                      J'ai tout simplement lu et traité les valeurs retournées par les fonctions de lecture.
                      • Partager sur Facebook
                      • Partager sur Twitter
                        10 mai 2019 à 19:35:43

                        Si vous ne faites pas attention à l'endianness, vous allez vous prendre une gamelle potentiellement avec chaque nouveau type d'hardware.

                        Attention au syndrome "tombé en marche".

                        • Partager sur Facebook
                        • Partager sur Twitter
                        Je recherche un CDI/CDD/mission freelance comme Architecte Logiciel/ Expert Technique sur technologies Microsoft.

                        reception de video en wifi

                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                        • Editeur
                        • Markdown