Send more data than what can be stored in the send buffer

I use C # sockets to implement my own RTSP core server (for training). I am currently writing logic for a server to do a handshake with a client when negotiating media ports at the request of DESCRIBE.

The client application was not written by me, and I do not have access to software updates, it is a simple RTSP client that negotiates media ports on a Cisco router and then transfers audio to clients connected to it.

The payload that I want to send back is 1024 bytes and a 64-byte header, and from what I see when checking my client application, only 400 bytes are sent back to the client.

The response payload is defined in C # as:

// 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); 

The respondToClient method respondToClient implemented as:

 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); } 

Using SendCallback to determine when a packet was sent to a client:

 private static void SendCallback(IAsyncResult res) { try { var socket = (Socket)res.AsyncState; socket.EndSend(res); } catch (Exception e) { Console.Write(e.Message); } } 

Why is my client application receiving only 400 bytes, and if so, how can I make sure the whole packet is sent (I use TCP)? Is this a hard limit set by C #? I consulted with MSDN and could not find any information to support this theory.

If you need more information about the implementation of my server, please ask.

EDIT Here is some food for thought, and I don’t know why this would happen if someone could enlighten me, which would be great ... @ Gregory A Beamer suggested in the comments that EndSend might work prematurely, is this possible? In my opinion, I thought that the async callback would only work once, and only after all the bytes were sent from the server to the client socket for listening.

To indicate that the packet was not completely received by the client, the following information indicates that the client application receives only 400 bytes:

enter image description here

Supported by wire tracing from S-> C

enter image description here

UPDATE . Speaking earlier with @usr, I did some additional tests and now I can confirm that the client application will receive a 400-byte response only from the server. i h

 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 

^ This is the log trace reset by the client application when I dial the number on the server, here we see that it takes 1384 bytes back from the client, but its processing buffer can only store 400 bytes. I looked at the log for an existing application that handles streaming on the same device, and in a wirehark trace instead of sending a header in one block, sends several fragments back with information [TCP segment of a reassembled PDU] I'm not sure what this means (new to network material), but I assume that he broke the server payload and sent it in several fragments, and then reassembled it on the client to process the request.

How can I reproduce this behavior on my server application? I tried the following in my response method, hoping that it would return the package and collect it again on the client, however, I just kept getting the same error that was mentioned above:

 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); } } 
+8
c # sockets rtsp
source share
3 answers

This may seem contradictory, but the error in the code was extremely stupid, and I have to attribute the success of this question to @ Keyz182 in the answers. After discussing privately, he noticed that I used \n to add new line items.

The problem was that I needed to change these returns to \r\n and add one between the header and the body to dictate to the client where the header ended and the payload case information started (bumps its head against a brick wall).

It turns out that the client did not have a 400-byte buffer (so I'm still surprised why he talked about the 400-byte processing buffer). Thank you for your help!

+2
source share

TCP is a limitless stream of bytes. There are no packages perceived by applications. Reading / receiving calls returns any number of bytes in a non-deterministic way (at least one). In the receiver you have to deal with the fact that reading may be partial. Use the return value of Receive to determine the number of bytes received.

It's all simpler if you read synchronously and use BinaryReader because it executes this loop logic for you.

BeginSend may be started prematurely, this is an opportunity

Not.

+2
source share

A possible answer may be that the client set a certain block size for it in the request to your server (see 12.7 - https://www.ietf.org/rfc/rfc2326.txt ), This may or may not be applicable, but if you can reset the request that the client will send you and view, you can see that the block size is indicated somewhere around the 400 mark.

EDIT: Mark the answer "Alex" below for a definitive answer.

+2
source share

All Articles