我正在尝试编写C#UDP服务器代码。它从客户端接收特定ID,并返回与其关联的歌曲。客户端是一个PHP网页,将收到的字节存入文件。现在我正在做一些测试,当传输速度为2048字节时,尝试简单地开始一个关于歌曲的假讲座(只是一个javascript警报)。但我有很多错误... 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代码:
<?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())."</pre>";
echo $text;
?>
非常感谢!
答案 0 :(得分:3)
UDP本质上是不可靠的传输。您需要在UDP之上实现确认,超时,重新传输和序列号,以确保按预期顺序传输所有数据,除非您的客户端应用程序可以使用丢弃的数据包。如果您需要在服务器和客户端之间保证数据传输并且不想自己实现所有这些内容(可能需要包括客户端缓冲以重新排列),我建议您考虑使用TCP套接字。 - 阶数据报)。如果你想要UDP之上的可靠性,我建议你阅读一本关于这个主题的好教科书(例如W. Richard Stevens等的“Unix网络编程”)。
TCP上的指针:
您应该查看System.Net.Sockets.TcpClient
和System.Net.Sockets.TcpListener
以了解C#方面的内容,并参阅PHP documentation了解有关PHP方面的信息。
除了使用send
和recv
(或C#/ PHP等价物)而不是send_to
和recv_from
之外,使用TCP套接字并没有太大的不同。设置服务器端的东西有点复杂,因为你需要bind
和listen
等,但是有很多资源,例如:
http://www.switchonthecode.com/tutorials/csharp-tutorial-simple-threaded-tcp-server
答案 1 :(得分:0)
有些观点:
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();
}
问题在于,如果返回值为FALSE,则将socket_recvfrom返回的值添加到$ length,将$ 0添加到$ length,这就是为什么必须添加其他变量($ reclength)的原因。
答案 2 :(得分:0)
感谢您的帮助。我更改了你告诉我的内容,除了将'b'添加到fopen模式,因为我的Web服务器在Ubuntu上。我仍然收到很多错误告诉我客户端连接必须关闭...似乎PHP认为下载已完成并退出循环,因此它关闭了套接字的连接。此外,在页面加载后几分钟,服务器仍在发送数据......我之前从未进行过流式处理,所以我很难看到问题出在哪里......
这是新的PHP代码:
<?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())."</pre>";
echo $text;
?>