我正在使用C#套接字来实现我自己的基本RTSP服务器(用于学习目的).我目前正在编写服务器的逻辑,以便在DESCRIBE请求上协商媒体端口时与客户端执行握手.
客户端应用程序不是由我编写的,我无权更新软件,它是一个简单的RTSP客户端,它协商Cisco路由器上的媒体端口,然后将音频传输到连接到它的客户端.
我想要发回的有效负载是1024字节和64字节的标头,从检查我的客户端应用程序可以看到,只有400字节被传回客户端.
响应有效负载在C#中定义为:
// Build the RTSP Response string
var body = "v=0\n" +
"o=- 575000 575000 IN IP4 " + m_serverIP + "\n" +
"s=" + stream + "\n" +
"i=<No author> <No copyright>\n" +
"c= IN IP4 0.0.0.0\n"+
"t=0 0\n" +
"a=SdpplinVersion:1610641560\n" +
"a=StreamCount:integer;1\n" +
"a=control:*\n" +
"a=Flags:integer;1\n" +
"a=HasParam:integer;0\n" +
"a=LatencyMode:integer;0\n" +
"a=LiveStream:integer;1\n" +
"a=mr:intgner;0\n" +
"a=nr:integer;0\n" +
"a=sr:integer;0\n" +
"a=URL:string;\"Streams/" + stream + "\"\n" +
"a=range:npt=0-\n" +
"m=audio 0 RTP/AVP 8" + // 49170 is the RTP transport port and 8 is A-Law audio
"b=AS:90\n" +
"b=TIAS:64000\n" +
"b=RR:1280\n" +
"b=RS:640\n" +
"a=maxprate:50.000000\n" +
"a=control:streamid=1\n" +
"a=range:npt=0-\n" +
"a=length:npt=0\n" +
"a=rtpmap:8 pcma/8000/1\n" +
"a=fmtp:8" +
"a=mimetype:string;\"audio/pcma\"\n" +
"a=ASMRuleBook:string;\"marker=0, Avera**MSG 00053 TRUNCATED**\n" +
"**MSG 0053 CONTINUATION #01**geBandwidth=64000, Priority=9, timestampdelivery=true;\"\n" +
"a=3GPP-Adaptation-Support:1\n" +
"a=Helix-Adaptation-Support:1\n" +
"a=AvgBitRate:integer;64000\n" +
"a=AvgPacketSize:integer;160\n" +
"a=BitsPerSample:integer;16\n" +
"a=LiveStream:integer;1\n" +
"a=MaxBitRate:integer;64000\n" +
"a=MaxPacketSize:integer;160\n" +
"a=Preroll:integer;2000\n" +
"a=StartTime:integer;0\n" +
"a=OpaqueData:buffer;\"AAB2dwAGAAEAAB9AAAAfQAABABAAAA==\"";
var header = "RTSP/1.0 200 OK\n" +
"Content-Length: " + body.Length + "\n" +
"x-real-usestrackid:1\n" +
"Content-Type: application/sdp\n" +
"Vary: User-Agent, ClientID\n" +
"Content-Base: " + requestURI + "\n" +
"vsrc:" + m_serverIP + "/viewsource/template.html\n" +
"Set-Cookie: " + Auth.getCookie() + "\n" +
"Date: " + System.DateTime.Now + "\n" +
"CSeq: 0\n";
var response = header + body;
var byteArray = System.Text.Encoding.UTF8.GetBytes(response);
respondToClient(byteArray, socket);
Run Code Online (Sandbox Code Playgroud)
响应方法respondToClient实现为:
private static void respondToClient(byte[] byteChunk, Socket socket)
{
socket.BeginSend(byteChunk, 0, byteChunk.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
socket.BeginReceive(m_dataBuffer, 0, m_dataBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
Run Code Online (Sandbox Code Playgroud)
使用a SendCallback确定数据包何时发送到客户端:
private static void SendCallback(IAsyncResult res)
{
try
{
var socket = (Socket)res.AsyncState;
socket.EndSend(res);
}
catch (Exception e)
{
Console.Write(e.Message);
}
}
Run Code Online (Sandbox Code Playgroud)
为什么我的客户端应用程序只接收400个字节,如果是这样,我怎样才能确保我的整个数据包被发送(我正在使用TCP)?这是C#设定的硬限制吗?我咨询了MSDN,找不到任何支持这一理论的信息.
如果有关于我的服务器实现的更多详细信息,请询问.
编辑这里有一些值得思考的东西,我不知道为什么会这样,所以如果有人能够启发我会那么好...... @ Gregory A Beamer在评论中建议EndSend过早发射,这是否有可能?根据我的理解,我认为异步回调只会触发一次,并且只有一次所有字节都从服务器发送到侦听客户端套接字.
为了让我告诉客户端没有完全收到数据包,以下信息表明客户端应用程序只接收了400个字节:

由S-> C的wireshark跟踪支持

更新在早些时候与@usr谈话后,我做了一些进一步的测试,现在可以确认客户端应用程序只会从服务器收到400字节的响应.我
Jul 1 13:28:29: //-1//RTSP:/rtsp_read_svr_resp: Socket = 0
Jul 1 13:28:29: //-1//RTSP:/rtsp_read_svr_resp: NBYTES = 1384
Jul 1 13:28:29: //-1//RTSP:/rtsp_process_single_svr_resp:
Jul 1 13:28:29: rtsp_process_single_svr_resp: 400 bytes of data:
RTSP/1.0 200 OK
Content-Length: 1012
x-real-usestrackid:1
Content-Type: application/sdp
Vary: User-Agent, ClientID
Content-Base: rtsp://10.96.134.50/streams/stream01.dcw
vsrc:10.96.134.50/viewsource/template.html
Set-Cookie: cbid=aabtvqjcldwjwjbatynprfpfltxaspyopoccbtewiddxuzhsesflnkzvkwibtikwfhuhhzzz;path=/;expires=09/10/2015 14:28:38
Date: 01/07/2015 14:28:38
CSeq: 0
v=0
o=- 575000 575000 IN IP4
Run Code Online (Sandbox Code Playgroud)
这是我拨入服务器时客户端应用程序转储的日志跟踪,这里我们可以看到它接受来自客户端的1384个字节,但是它的处理缓冲区只能存储400个字节.我查看了一个现有应用程序的日志,该应用程序处理流向同一设备的流量,并且在wireshark跟踪中,它不是在一个块中发送标头,而是发回几个块,其中包含信息[TCP segment of a reassembled PDU]我不知道这意味着什么(新的网络的东西)但我假设它打破了服务器的有效负载并将其发送到几个块,然后在客户端重新组装以处理请求.
如何在我的服务器应用程序上复制此行为?我在我的响应方法中尝试了以下内容,希望它能够回送数据包并在客户端上重新组装,但是我只是继续得到上面讨论的相同错误:
private static void respondToClient(byte[] byteChunk, Socket socket)
{
// Divide the byte chunk into 300 byte chunks
if (byteChunk.Length >= 400)
{
Console.WriteLine("Total bytes: " + byteChunk.Length);
var totalBytes = byteChunk.Length;
var chunkSize = 400;
var tmp = new byte[chunkSize];
var packets = totalBytes / chunkSize;
var overflow = totalBytes % chunkSize;
Console.WriteLine("Sending " + totalBytes + " in " + packets + " packets, with an overflow packets of " + overflow + " bytes.");
for (var i = 0; i < packets * chunkSize; i+=chunkSize)
{
Console.WriteLine("Sending chunk " + i + " to " + (i + chunkSize));
tmp = byteChunk.Skip(i).Take(chunkSize).ToArray();
socket.BeginSend(tmp, 0, tmp.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
}
if (overflow > 0)
{
Console.WriteLine("Sending overflow chunk: " + overflow + " at index " + (totalBytes - overflow) + " to " + (totalBytes ));
tmp = byteChunk.Skip(byteChunk.Length - overflow).Take(overflow).ToArray();
socket.BeginSend(tmp, 0, tmp.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
}
}
else
{
socket.BeginSend(byteChunk, 0, byteChunk.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
socket.BeginReceive(m_dataBuffer, 0, m_dataBuffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
}
Run Code Online (Sandbox Code Playgroud)
这可能看起来有争议,但代码中的错误非常愚蠢,我必须将这个问题的成功归功于答案中的@Keyz182。在私下讨论后,他注意到我正在使用\n添加新的线条元素。
问题是我需要更改这些返回值\r\n并在标头和正文之间添加一个,以向客户端指示标头结束的位置和有效负载的正文信息的开始位置(将头撞到砖墙上)。
事实证明,客户端上没有400字节的缓冲区(所以我仍然很好笑为什么它谈到400字节的处理缓冲区)。感谢大家的帮助!
| 归档时间: |
|
| 查看次数: |
1015 次 |
| 最近记录: |