简体   繁体   English

PHP 到 C# - 套接字 - 文件随机损坏

[英]PHP to C# - Socket - File corrupts randomly

I have a TCP connection, which client is PHP and server is C#我有一个TCP连接,客户端是PHP ,服务器是C#

this socket connection transfers a image to the socket server, but此套接字连接将图像传输到socket服务器,但是

randomly some times the transfer get corrupted [image hash is different]有时传输会随机损坏[图像hash不同]

PHP Client PHP 客户端

$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.此 stream 始终传输Bitmap图像 + 一些数据。


C# 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我认为这是caching的一些问题,但我使用headers禁用caching ,但存在同样的问题

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.用于几乎任何网络编程的套接字读写 API API 从 BSD sockets 到 WinSock 再到 .NET 网络类都将发送或接收数据,达到所需的字节数。

If you look at the documentation for PHP socket_write for example:如果您查看 PHP socket_write 的文档,例如:

Returns the number of bytes successfully written to the socket or FALSE on failure.返回成功写入套接字的字节数或失败时返回 FALSE。 The error code can be retrieved with socket_last_error().可以使用 socket_last_error() 检索错误代码。 This code may be passed to socket_strerror() to get a textual explanation of the error.可以将此代码传递给 socket_strerror() 以获得错误的文本解释。

Note: It is perfectly valid for socket_write() to return zero which means no bytes have been written.注意:socket_write() 返回零是完全有效的,这意味着没有写入任何字节。 Be sure to use the == operator to check for FALSE in case of an error.如果出现错误,请务必使用 == 运算符检查 FALSE。

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.您通常需要选择一个块大小,如 4096 或 16384 并循环发送或接收该块大小,直到您获得所需的发送或接收字节数。 Your code will have to check the return value of the send or receive function you're calling and adjust your file pointer accordingly.您的代码必须检查您正在调用的发送或接收 function 的返回值,并相应地调整文件指针。 If transmit returns 0, that could just mean the send buffer is full (not fatal) so continue sending (might want a Sleep(0) delay).如果传输返回 0,这可能只是意味着发送缓冲区已满(不是致命的),所以继续发送(可能需要 Sleep(0) 延迟)。 If receive returns 0, this usually means the other side has cleanly closed the connection.如果接收返回 0,这通常意味着对方已经干净地关闭了连接。

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).对于这样的简单操作,我建议只发送一个二进制 32 位 integer(4 个字节)。 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).因此接收器将首先读取 4 个字节并从中知道需要读取多少字节(一次一个缓冲区大小)。 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.你必须 select 一个缓冲区大小,然后继续读取或写入该大小的缓冲区,直到你得到你想要的,你必须向对方传达你计划发送多少数据。

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.在不知道 bmp 文件的结构的情况下,我首先关心的是如何将文件与发送的附加信息分开。 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如果 '$cordinates' (sic) 是固定大小,则将其放在消息的前面,而不是后面
  2. Log the size sent from PHP and the size received.记录从 PHP 发送的大小和收到的大小。
  3. base64 encode the binary file before sending it (and decode at the receiving end) base64 在发送之前对二进制文件进行编码(并在接收端解码)

Non of above solutions didn't work for me, but i found out that create a new instance every time after a one request will solve the problem.以上解决方案都不适用于我,但我发现每次请求后创建一个新实例都可以解决问题。 but i don't think its a reliable way.但我认为这不是一种可靠的方式。

i tried the client using ASP.NET but same results.我使用ASP.NET尝试了客户端,但结果相同。 i think its not a problem with client PHP its surely a problem of the socket server我认为客户端PHP不是问题,它肯定是套接字服务器的问题

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM