PHP 转 C# - Socket - 文件随机损坏

4

我有一个TCP连接,客户端是PHP,服务器是C#

这个套接字连接传输一个图像socket服务器,但是随机地有时会出现传输损坏的情况 [图像hash不同]

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

这个流总是传输一个 Bitmap 图像和一些数据。

C#

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

我调查发现,在一个新打开的浏览器中,这个问题从未出现过。但是当我在同一个浏览器中频繁地多次使用这个创建的服务时,它就会出现问题。

当我尝试用不同的浏览器或者浏览器的新实例进行检查时,在前几次尝试中,它从未出现过问题。

我认为这可能是由于缓存造成的问题,但是我使用头文件禁用了缓存,但仍然存在相同的问题。


1
C# 在这里有什么关系?还是没有关系?(我想知道问题是否出在 C# 的流读取代码上;人们经常会犯这种错误) - Marc Gravell
失败的图片大小是否超过500字节?您是使用TCP还是UDP?如果您正在使用UDP,可能是由于网络拥塞,这只会在几个请求后出现 - 因为HTTP即TCP与UDP在同一线路上会对UDP数据包丢失造成破坏。您是否考虑在C#应用程序中使用HttpListener来简化此过程? - Jonathan Dickinson
@Jonathan Dickinson,实际上我使用的示例数据超过了500字节,我不明白你所说的HttpListener的概念,有没有示例? - Sudantha
这可能是原因,你只收到了前500个字节。至于HttpListener,请查看文档。这样你就可以使用PHP的HTTP方法来获取文件。另外,我给你的链接是谷歌上的第一个结果 - Jonathan Dickinson
3个回答

10
你不能指望一次性将整个文件写入套接字,也不能指望一次性从套接字中读取整个文件。无论是BSD套接字、WinSock还是.NET网络类的套接字读写API都会传输或接收到所需的字节数。例如,如果您查看PHP socket_write文档:
返回成功写入套接字的字节数,失败则返回FALSE。错误代码可以使用socket_last_error()函数检索。此代码可以通过socket_strerror()获取错误的文本说明。
注意:socket_write()返回0是完全有效的,这意味着没有任何字节被写入。请务必使用 == 运算符来检查是否有错误的FALSE。
一般来说,您需要选择一个块大小(如4096或16384),并循环传输或接收该块大小,直到获得所需的字节数为止。您的代码将需要检查正在调用的发送或接收函数的返回值,并相应地调整文件指针。如果传输返回0,则可能只是发送缓冲区已满(不致命),因此继续发送(可能需要Sleep(0)延迟)。如果接收返回0,则通常表示另一端已经干净地关闭了连接。
您简单的网络编码使用中最关键的缺陷之一是,在发送文件数据之前没有发送文件大小,因此接收方无法知道在发送其响应之前需要读取多少数据。对于这种简单的操作,建议发送二进制32位整数(4字节)。这将是您的操作配图的一部分。因此,接收方首先读取4字节,并从中知道需要读取多少字节(每次一个缓冲区大小)。接收方一直读取,直到获得了那么多字节。

希望这可以帮助你。如果套接字代码像你尝试的用法那样简单,那就太好了,但不幸的是它并不是那么简单。你需要选择一个缓冲区大小,并且一直读取或写入该大小的缓冲区,直到得到想要的数据,并且你需要告诉另一端你计划发送多少数据。


2
你认为缓存与问题有关,这意味着你发布的代码外部存在很多功能影响结果,或者你离理解问题还有很长的路要走。
不了解bmp文件的结构,我的第一个担忧是如何将文件与发送的其他信息分开。以下是一些尝试的方法:
1. 如果'$cordinates'是固定大小,请将其放在消息前面而不是后面。 2. 记录从PHP发送和接收到的大小。 3. 在发送之前对二进制文件进行base64编码(并在接收端解码)。

0

以上的解决方案都对我没用,但我发现每次请求后创建一个新实例可以解决问题。但我不认为这是一种可靠的方法。

我尝试使用ASP.NET客户端,但结果相同。我认为这不是客户端PHP的问题,而是套接字服务器的问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接