Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP to C# - Socket - File corrupts randomly

Tags:

c#

php

tcp

sockets

I have a TCP connection , which client is PHP and server is C#

this socket connection transfers a image to the socket server , but

randomly some times the transfer get corrupted [image hash is different]

PHP Client

$file = file_get_contents('img.bmp');
socket_write($socket,$file.$cordinates); it sends //image + sme other data
$recv = socket_read ($socket, 500, PHP_BINARY_READ) // read the server response

This stream always transfer a Bitmap image + some data .


C#

 this.DataSocket = this.Listner.Accept();
int filelength = this.DataSocket.Receive(this.buffer, this.buffer.Length, SocketFlags.None)

i investigated that in a fresh-browser [newly opened ] this never failed. but when i using this created service several times frequently in the same browser this intended to fail.

when i check with a different browser or new instance of the browser it never failed in first few attempts.

i thought it was some problem with caching but i disable caching using headers but same problem exists

like image 486
Sudantha Avatar asked Dec 17 '22 11:12

Sudantha


2 Answers

You can't simply expect to write an entire file to the socket at once, nor can you expect to read the file from the socket in one operation. The socket read and write APIs for just about any network programming API from BSD sockets to WinSock to .NET network classes are all going to transmit or receive data up to the desired byte count.

If you look at the documentation for PHP socket_write for example:

Returns the number of bytes successfully written to the socket or FALSE on failure. The error code can be retrieved with socket_last_error(). This code may be passed to socket_strerror() to get a textual explanation of the error.

Note: It is perfectly valid for socket_write() to return zero which means no bytes have been written. Be sure to use the == operator to check for FALSE in case of an error.

You will typically want to choose a block size like 4096 or 16384 and loop transmitting or receiving that block size until you get the desired number of bytes transmitted or received. Your code will have to check the return value of the send or receive function you're calling and adjust your file pointer accordingly. If transmit returns 0, that could just mean the send buffer is full (not fatal) so continue sending (might want a Sleep(0) delay). If receive returns 0, this usually means the other side has cleanly closed the connection.

One of the most critical flaws in your simple network code usage is that you're not sending the size of the file before you send the file data, so there's no way for the receiver to know how much to read before sending their response. For a simple operation like this, I'd suggest just sending a binary 32bit integer (4 bytes). This would be part of the schema for your operation. So the receiver would first read 4 bytes and from that know how many more bytes need to be read (one buffer size at a time). The receiver keeps reading until they have that many bytes.

I hope this helps. It would be great if socket code were as simple as the usage you attempted, but unfortunately it isn't. You have to select a buffer size, and then keep reading or writing buffers of that size until you get what you want, and you have to convey to the other side how much data you plan on sending.

like image 186
Jeremiah Gowdy Avatar answered Dec 19 '22 02:12

Jeremiah Gowdy


That you think caching has anything to do with the problem implies that either there is a lot of functionality outside of the code you've published which is affecting the result or that you are a very long way from understanding the problem.

Without knowing the structure of bmp files, my first concern would be how you separate the file from the additional info sent. A few things you could try...

  1. If '$cordinates' (sic) is a fixed size, then put this at the front of the message, not the back
  2. Log the size sent from PHP and the size received.
  3. base64 encode the binary file before sending it (and decode at the receiving end)
like image 24
symcbean Avatar answered Dec 19 '22 00:12

symcbean