Передача UDP Streaming из приложения C # на веб-страницу PHP - PullRequest
1 голос
/ 02 декабря 2010

Я пытаюсь закодировать C # UDP-сервер. Он получает конкретный идентификатор от клиента и возвращает песню, связанную с ним. Клиент является веб-страницей PHP и содержит байты, полученные в файл. Прямо сейчас я делаю несколько тестов, пытаясь просто начать фальшивую лекцию песни (просто предупреждение javascript), когда передача составляет 2048 байт. Но у меня есть много ошибок ... Кажется, что страница PHP завершает передачу в файл ДО получения всех данных ... Сервер продолжает отправлять байты, но файл завершен, с хорошим весом и всем ...

Я знаю, что у меня не очень хороший английский, так что если вы что-то недооцениваете, просто спросите!

Вот код C #:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;  
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Net.Sockets;
using System.Net;
using System.Data.SQLite;

namespace cdCollector
{
public partial class Streaming : Form
{
    private static List<IPAddress> clients_ = new List<IPAddress>();

    public Streaming()
    {
        InitializeComponent();
        listen();
    }

    public class ThreadClient
    {
        private static UdpClient socket_;
        private static IPEndPoint ipepClient_;
        private static int noChanson_;
        private static SQLiteConnection connexion_;

        public void setSocket(ref UdpClient socket) { socket_ = socket; }
        public void setIpepClient(ref IPEndPoint ipepClient) { ipepClient_ = ipepClient; }
        public void setNoChanson(int noChanson) { noChanson_ = noChanson; }
        public void setConnexion(ref SQLiteConnection connexion) { connexion_ = connexion; }

        public static void send()
        {
            try
            {
                while (Thread.CurrentThread.IsAlive)
                {
                    Chanson uneChanson;
                    FileStream stream;
                    byte[] buffer = new byte[1024];
                    int read;

                    uneChanson = new Chanson(noChanson_);
                    uneChanson.load(ref connexion_);

                    stream = new FileStream("C:\\Users\\Julie\\Documents\\toune.flac", FileMode.Open, FileAccess.Read);

                    socket_.Send(Encoding.ASCII.GetBytes(stream.Length.ToString()), stream.Length.ToString().Length, ipepClient_);

                    while ((read = stream.Read(buffer, 0, buffer.Length)) > 0)
                        socket_.Send(buffer, buffer.Length, ipepClient_);

                    Console.WriteLine("finished");
                }
            }
            catch (ThreadAbortException tae)
            { }
            catch (Exception)
            {
                Thread.CurrentThread.Abort();
            }
        }
    }

    public static void listen()
    {
        byte[] data = new byte[1024];

        IPEndPoint ipepServer = new IPEndPoint(IPAddress.Any, 7575); // IP du serveur
        IPEndPoint ipepClient = new IPEndPoint(IPAddress.Any, 0); // IP du client;
        UdpClient socket = new UdpClient(ipepServer); // socket serveur
        int noChanson;
        SQLiteConnection connexion = new SQLiteConnection("Data Source=" + Application.StartupPath + "\\cdCollector.db");
        SQLiteCommand command = new SQLiteCommand(connexion);
        SQLiteDataReader dr;
        Thread thread;

        connexion.Open();

        while (true)
        {
            try
            {
                Console.WriteLine("Waiting for a client...");

                data = socket.Receive(ref ipepClient);

                Console.WriteLine("Message received from {0}:", ipepClient.ToString());
                Console.WriteLine(Encoding.ASCII.GetString(data, 0, data.Length));



                command.CommandText = "SELECT KeyLocale FROM AssocKeys WHERE NomTable = 'Chanson' AND KeyWeb = "
                                        + int.Parse(Encoding.ASCII.GetString(data, 0, data.Length));

                dr = command.ExecuteReader();


                if (dr.HasRows)
                {
                    dr.Read();

                    noChanson = dr.GetInt32(0);

                    dr.Close();

                    ThreadClient client = new ThreadClient();
                    client.setConnexion(ref connexion);
                    client.setIpepClient(ref ipepClient);
                    client.setNoChanson(noChanson);
                    client.setSocket(ref socket);

                    thread = new Thread(new ThreadStart(ThreadClient.send));
                    thread.Start();
                }
                else
                    socket.Send(Encoding.ASCII.GetBytes("Erreur: Chanson introuvable"), ("Erreur: Chanson introuvable").Length, ipepClient);



            }
            catch (SocketException se)
            {
                Console.WriteLine("Erreur Socket:" + se.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("Erreur: " + ex.Message);
            }

        }

        connexion.Close();
    }

}   

}

И код PHP:

<code><?php
 session_start();
$address="192.168.2.2";
$read = false;
$port = 7575;
$length = 0;
$started = false;

if (isset($port) and
($socket=socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) and
(socket_connect($socket, $address, $port)))
{
    $text =  "Connection successful on IP $address, port $port <br />";

    $from = '';
    $port = 0;
    $length = 0;

    socket_send( $socket, $_GET['no'], 1024, MSG_EOR );
    socket_recvfrom( $socket, $buf, 1024, 12, $from, $port);

    $lengthTotal = $buf;
    echo "Taille prévue du fichier: " . $lengthTotal . "<br />";

    if( file_exists( "temp" . $_SESSION['ID_Membre'] . ".flac" ) )
        unlink("temp" . $_SESSION['ID_Membre'] . ".flac");

    $file = fopen("temp" . $_SESSION['ID_Membre'] . ".flac", 'a');
    $buf = null;

    while( $length < $lengthTotal )
    {
        $length += socket_recvfrom( $socket, $buf, 1024, 12, $from, $port );
        if( $length > 2048 && !$started )
        {
            ?>
            <script type="text/javascript">
            <!--
                alert("Lecture...");
            //->
            </script>
            <?php
            $started = true;
        }

        fputs($file, $buf);

        flush();
    }

    echo "<br />" . $length . "<br />";
    fclose($file);
}
else
        $text="Unable to connect<pre>".socket_strerror(socket_last_error())."
"; echo $ text; ?>

Большое спасибо!

Ответы [ 3 ]

3 голосов
/ 02 декабря 2010

UDP является ненадежным по своей природе транспортом.Вам потребуется реализовать подтверждения, тайм-ауты, повторные передачи и порядковые номера поверх UDP, чтобы гарантировать передачу всех ваших данных в ожидаемом порядке, если только ваше клиентское приложение не может работать с отброшенными пакетами.Я бы посоветовал вам вместо этого использовать TCP-сокеты, если вам нужна гарантированная передача данных между сервером и клиентом, и вы не хотите реализовывать все эти вещи самостоятельно (для этого может потребоваться включить буферизацию на стороне клиента, чтобы переставить внепорядок дейтаграмм).Если вам нужна надежность поверх UDP, я бы посоветовал вам прочитать хороший учебник по этой теме (например, «Сетевое программирование Unix» У. Ричарда Стивенса и т. Д.).

Указатели на TCP:

Вы должны взглянуть на System.Net.Sockets.TcpClient и System.Net.Sockets.TcpListener для вещей на C # и обратиться к документации PHP для получения информации о PHP-стороне вещей.

Использование TCPсокеты не сильно отличаются друг от друга, за исключением того, что вы будете использовать send и recv (или эквиваленты C # / PHP) вместо send_to и recv_from.Настройка серверной части немного сложнее, так как вам нужно bind, listen и т. Д., Но ресурсов достаточно, например:

http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server

0 голосов
/ 02 декабря 2010

Спасибо за вашу помощь. Я изменил то, что вы мне сказали, за исключением добавления 'b' в режим fopen, потому что мой веб-сервер работает на Ubuntu. Я все еще получаю множество ошибок, чтобы сказать мне, что клиентское соединение должно было закрыться ... Похоже, PHP думает, что загрузка завершена и выходит из цикла, поэтому он закрывает соединение сокета. Кроме того, через много минут после загрузки страницы сервер все еще отправляет данные ... Я никогда не выполнял потоковую передачу, поэтому мне сложно понять, в чем проблема ...

Вот новый код PHP:

<code><?php
session_start();
$address="192.168.2.2";
$read = false;
$port = 7575;
$length = 0;
$started = false;

if (isset($port) and
($socket=socket_create(AF_INET, SOCK_DGRAM, SOL_UDP)) and
(socket_connect($socket, $address, $port)))
{
    $text =  "Connection successful on IP $address, port $port <br />";

    $from = '';
    $port = 0;
    $length = 0;

    socket_send( $socket, $_GET['no'], 1024, MSG_EOR );
    socket_recvfrom( $socket, $buf, 1024, MSG_WAITALL, $from, $port);

    $lengthTotal = $buf;
    echo "Taille prévue du fichier: " . $lengthTotal . "<br />";

    if( file_exists( "temp" . $_SESSION['ID_Membre'] . ".flac" ) )
        unlink("temp" . $_SESSION['ID_Membre'] . ".flac");

    $file = fopen("temp" . $_SESSION['ID_Membre'] . ".flac", 'a');
    $buf = null;

    while( $length !== FALSE && $length < $lengthTotal )
    {
        $length += socket_recvfrom( $socket, $buf, 1024, 12, $from, $port );
        if( $length > 2048 && !$started )
        {
            ?>
            <script type="text/javascript">
            <!--
                alert("Lecture...");
            //->
            </script>
            <?php
            $started = true;
        }

        if( $length == FALSE )
            echo "ERREUR";

        fputs($file, $buf, $length);

        flush();
    }

    echo "<br />" . $length . "<br />";
    fclose($file);
}
else
        $text="Unable to connect<pre>".socket_strerror(socket_last_error())."
"; echo $ text; ?>
0 голосов
/ 02 декабря 2010

Некоторые моменты:

1.- socket_recvfrom может вернуть FALSE, если есть какая-либо ошибка, вы можете проверить ошибку с помощью false === socket_recvfrom.2.- Если вы используете сервер Windows, добавьте b в открытый режим: $ file = fopen ("temp". $ _SESSION ['ID_Membre']. ".Flac", 'ab');(вы пишете двоичный файл).3.- Используйте в качестве третьего аргумента функции fputs значение, возвращаемое функцией socket_recvfrom (если это значение! == FALSE).4.- Вы используете значение 12 (MSG_DONTROUTE | MSG_EOR), попробуйте использовать 0 или MSG_WAITALL (конечно socket_recvfrom будет ждать получения 1024 байта).

Ваш цикл приема должен быть:

$reclen = 0;
while( ($reclen !== FALSE) && ($length < $lengthTotal) )
{
    $reclen = socket_recvfrom( $socket, $buf, 1024, 12, $from, $port );
    if ($reclen === FALSE)
    {
        echo "ERREUR";
        break;
    }
    $length += $reclen;
    if( $length > 2048 && !$started )
    {
        ?>
        <script type="text/javascript">
        <!--
            alert("Lecture...");
        //->
        </script>
        <?php
        $started = true;
    }

    fputs($file, $buf, $length);

    flush();
}

Проблема заключается в том, что вы добавляете значение, возвращаемое socket_recvfrom, к длине $, если возвращаемое значение равно ЛОЖНО, то будет добавлено от 0 к длине $, поэтому вы должны добавить дополнительную переменную ($reclength).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...