我正在使用C#套接字实现自己的基本RTSP服务器(用于学习目的)。我目前正在编写服务器逻辑,以在与客户端协商媒体端口时执行握手。客户端应用程序不是由我编写的,我无法更新软件,它是一个简单的RTSP客户端,可在Cisco路由器上协商媒体端口,然后将音频传输到连接到该客户端的客户端。
我要发送回的有效负载为1024字节和64字节的头部。从检查我的客户端应用程序可以看出,只有400字节被传回给客户端。响应有效负载在C#中定义为:
为什么我的客户端应用程序只接收了400字节,如果是这样,如何确保整个数据包被发送(我正在使用TCP)?这是C#设置的硬限制吗?我咨询了MSDN,并没有找到任何支持这个理论的信息。
如果需要有关服务器实现的更多详细信息,请询问。
编辑:这里有一些值得思考的东西,我不知道为什么会发生这种情况,所以如果有人能启发我,那就太好了……@Gregory A Beamer在评论中建议
为了让我知道客户端没有完全接收数据包,以下信息说明客户端应用程序仅接收了400字节:
由S->C的wireshark跟踪支持
更新:在之前与@usr交谈之后,我进行了进一步的测试,现在可以确认客户端应用程序只会从服务器接收到400个字节的响应。
我要发送回的有效负载为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);
响应客户端的方法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);
}
使用SendCallback
来确定数据包何时已发送到客户端:
private static void SendCallback(IAsyncResult res)
{
try
{
var socket = (Socket)res.AsyncState;
socket.EndSend(res);
}
catch (Exception e)
{
Console.Write(e.Message);
}
}
为什么我的客户端应用程序只接收了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
^ 当我拨号到服务器时,客户端应用程序记录的日志跟踪如上所述。我们可以看到它从客户端接收了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);
}
}
a=fmtp:8
行末尾没有换行符。 - Frank Bryce