I encountered a strange behavior when using the Socket.BeginSendFile method in a Xamarin Forms app on android.
When I run my app using the Visual Studio debugger (with an android phone connected over USB) and want to pass a large file (7 MB) over a TCP connection, only the first 2 MB of data are being sent. Transmission then stops.
The app functions as a TCP client. I checked with Wireshark and the TCP packets all look OK: The last 2 packets or a TCP ACK from my app (sending some data), followed by a TCP ACK from the server. The socket remains active.
When I run the app without the debugger (directly from a smartphone) the error doesn't seem to occur. The complete 7 MB of data is being transmitted.
I use Socket.BeginSendFile because that gives the highest throughput. When I do the exchange with 'normal' Socket.BeginSend calls (and my own file stream and reader code) the error never pops up, but throughput is bad. Transfer speed is about 40 times less than with Socket.BeginSendFile.
Is there anyone who can shed some light on this? The issue is probably in the Mono runtime since only System.Net.Sockets is being involved.
Answers
Could you please post the main code that you send a large file or a basic demo so that we can tested with it?
Thanks for the prompt feedback!
I continued testing in the mean time and observed 2 other things that might help in explaining the issue.
1. Long living TCP connections
The code I was referring to in my initial question was using the concept of a long living TCP connection; i.e. the socket to the server is only closed when the app stops. There is only 1 socket which is being reused with each file transfer.
In debug mode, this code results in a large file not always being completely sent over the socket, or sometimes sending hangs for a relatively long time (10..30 seconds) and then resumes.
When running straight on the device (without the debugger) files are correctly transferred, but I now noticed that when repeating large transfers the processor load on a Samsung S8 increases to 30% for the app and remains at that high level, even long after file transfer has stopped.
I have no idea what the reason could be for this but I suspect that it might have something to do with socket resources hanging around. I therefore changed the code to always close the socket after the files have been transferred and connect again when a new file transfer comes up. That seems to have solved the processor load issue. The hanging file transfer issue however is still there in debug mode.
This is my code now (which is almost the same as my original code, except for the creation and the disposal of the socket):
(UploadSelectedFiles runs in a seperate thread).
2. Strange callback sequence for Socket.EndSendFile
I have 2 test devices: one running android 5.1, another running 8.0.
The code shown above only runs successfully on my android 5.1 device. On android 8.0 (samsung s8) the code hangs forever on the wait handle that has to synchronize the callback to Socket.EndSendFile. In other words: EndSendFile is not called for the first file.
When I change the code to not wait on the handle (I can do that because I anyhow wait for a receipt message returned by the server) everything runs OK, but there is still a strange behaviour on android 8.0 with respect to how the EndSendFile callback should work: When I transfer 10 files the callback is never called during the transfer. It is only after all files have been sent and I close the socket that I get 10 consecutive calls to the EndSendFile callback.
I know this is quite a long explanation of what I have experienced, but hopefully it is of use. I can proceed with the new short lived TCP concept, but the issue of the wait handle of course bothers me.