【问题标题】:PHP to C# - Socket - File corrupts randomlyPHP 到 C# - 套接字 - 文件随机损坏
【发布时间】:2011-10-07 09:52:45
【问题描述】:

我有一个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

这个流总是传输一个位图图像+一些数据。


C#

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

我在 新鲜浏览器 [新打开的] 中进行了调查,这从未失败。但是当我在同一个浏览器中使用这个创建的服务多次时,这会失败。

当我使用不同的浏览器或浏览器的新实例进行检查时,从未前几个中失败尝试。

我认为caching 有问题,但我使用headers 禁用caching,但存在同样的问题

【问题讨论】:

  • C# 与此有什么关系?还是不是? (我想知道问题是否在于 C# 中的流读取代码;人们经常会弄错)
  • 失败图像的大小是否超过 500 字节?您使用的是 TCP 还是 UDP?如果您使用 UDP,则可能是因为网络拥塞仅在几次请求后才出现 - 并且因为 HTTP 即 TCP 在与 UDP 相同的线路上造成 UDP 数据包丢失。您是否考虑过在您的 C# 应用程序中使用 HttpListener 来简化此操作?
  • @Jonathan Dickinson 实际上我使用的样本数据超过了500Bytes,我不明白HttpListener 的任何例子吗?
  • 这就是原因,您只收到前 500 个字节。至于HttpListener,请看the documentation。这样您就可以使用 PHP HTTP 方法来获取文件。另外,我给你的链接是 Google 上的第一个结果

标签: c# php sockets tcp


【解决方案1】:

您不能简单地期望一次将整个文件写入套接字,也不能期望在一次操作中从套接字读取文件。几乎所有网络编程 API(从 BSD 套接字到 WinSock 再到 .NET 网络类)的套接字读写 API 都将传输或接收数据高达所需的字节数。

如果您查看 PHP socket_write 的文档,例如:

返回成功写入套接字的字节数,失败则返回 FALSE。可以使用 socket_last_error() 检索错误代码。可以将此代码传递给 socket_strerror() 以获得错误的文本解释。

注意: socket_write() 返回零是完全有效的,这意味着没有写入任何字节。请务必使用 == 运算符检查是否为 FALSE,以防出现错误。

您通常需要选择 4096 或 16384 之类的块大小并循环发送或接收该块大小,直到获得所需的发送或接收字节数。您的代码必须检查您正在调用的发送或接收函数的返回值,并相应地调整您的文件指针。如果传输返回 0,那可能只是意味着发送缓冲区已满(不是致命的),所以继续发送(可能需要 Sleep(0) 延迟)。如果receive返回0,这通常意味着对方已经干净地关闭了连接。

简单的网络代码使用中最严重的缺陷之一是在发送文件数据之前没有发送文件的大小,因此接收方无法在发送之前知道要读取多少回复。对于像这样的简单操作,我建议只发送一个二进制 32 位整数(4 个字节)。这将是您的操作架构的一部分。因此接收器将首先读取 4 个字节,并从中知道需要读取多少字节(一次一个缓冲区大小)。接收器一直读取,直到它们有那么多字节。

我希望这会有所帮助。如果套接字代码与您尝试的用法一样简单,那就太好了,但不幸的是,事实并非如此。你必须选择一个缓冲区大小,然后继续读取或写入该大小的缓冲区,直到你得到你想要的,你必须向对方传达你计划发送多少数据。

【讨论】:

    【解决方案2】:

    您认为缓存与问题有任何关系,这意味着您发布的代码之外还有很多功能会影响结果,或者您距离理解问题还有很长的路要走。

    在不知道 bmp 文件的结构的情况下,我首先关心的是如何将文件与发送的附加信息分开。您可以尝试一些事情...

    1. 如果 '$cordinates' (sic) 是固定大小,则将其放在消息的前面,而不是后面
    2. 记录从 PHP 发送的大小和收到的大小。
    3. base64 在发送二进制文件之前对其进行编码(并在接收端解码)

    【讨论】:

      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多