3

这是我在这个论坛上发布的第一个问题,我是 c# 世界的初学者,所以这对我来说有点令人兴奋,但我在通过套接字发送大量数据时遇到了一些问题,所以这是更多细节关于我的问题:

我正在通过 TCP 套接字发送 5 Mo 的二进制图像,在接收部分我正在保存结果(接收到的数据)并且只得到 1.5 Mo ==> 数据已丢失(我比较了原始文件和生成的文件它向我展示了遗漏的部分)这是我使用的代码:

private void senduimage_Click(object sender, EventArgs e)
{
    if (!user.clientSocket_NewSocket.Connected)
    {
        Socket clientSocket_NewSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        user.clientSocket_NewSocket = clientSocket_NewSocket;
        System.IAsyncResult _NewSocket = user.clientSocket_NewSocket.BeginConnect(ip_address, NewSocket.Transceiver_TCP_Port, null, null);
        bool successNewSocket = _NewSocket.AsyncWaitHandle.WaitOne(2000, true);
     }
     byte[] outStream = System.Text.Encoding.ASCII.GetBytes(Uimage_Data);
     user.clientSocket_NewSocket.Send(outStream);
 }

在论坛中他们说将数据分成块,这是一个解决方案,如果是我该怎么做,我试过了,但它没有用!

4

4 回答 4

2

有很多不同的解决方案,但分块通常是一个很好的解决方案,您可以盲目地执行此操作,不断填充临时缓冲区,然后将其放入某个有状态的缓冲区,直到您遇到任意令牌或缓冲区未完全填满,或者您可以遵守每条 tcp消息的某种合同(消息是要接收的整体数据)。

如果你打算做某种契约,那么像消息的前 N ​​个字节是描述符,你可以根据需要做大或小,但你的临时缓冲区只会预先读取这个大小从流中。

典型的标头可能类似于:

public struct StreamHeader // 5 bytes
{
   public byte MessageType {get;set;} // 1 byte
   public int MessageSize {get;set;}  // 4 bytes
}

因此,如果它足够小,则将完整的消息大小分配给临时缓冲区并将其全部读取,或者如果您认为它太大,将其分成多个部分并继续读取,直到您收到的总字节数与 MessageSize 匹配标题结构的一部分。

于 2012-10-23T09:00:21.117 回答
0

最有可能的问题是您在所有数据都传输到服务器之前关闭了客户端套接字,因此它被丢弃了。

默认情况下,当您关闭套接字时,所有未传输的数据(位于操作系统缓冲区中)都将被丢弃。有几个解决方案:

[1] 设置 SO_LINGER(见http://developerweb.net/viewtopic.php?id=2982) [2] 让服务器向客户端发送确认,在收到之前不要关闭客户端套接字它。[3] 等到客户端的输出缓冲区为空,然后再关闭套接字(使用 getsocketopt SO_SND_BUF 进行测试 - 我不确定 c# 上的语法)。

此外,您真的应该测试 Send() 的返回值。虽然理论上它应该阻塞,直到它发送所有数据,但我想实际验证这一点,如果存在不匹配,至少打印一条错误消息。

于 2013-08-25T23:12:04.570 回答
0

可能您还没有阅读 C# 中有关套接字使用的文档。( http://msdn.microsoft.com/en-us/library/ms145160.aspx )

内部缓冲区无法存储您提供给发送方法的所有数据。您的问题的一个可能的解决方案可能是就像您所说的将数据分成块。

int totalBytesToSend = outstream.length;     int bytesSend = 0;
while(bytesSend < totalBytesToSend )
    bytesSend+= user.clientSocket_NewSocket.Send(outStream, bytesSend, totalBytesToSend - bytesSend,...);
于 2012-10-23T08:59:43.747 回答
0

我怀疑你的问题之一是你没有打电话EndConnect。从 MSDN 文档:

异步 BeginConnect 操作必须通过调用 EndConnect 方法来完成。

另外,等待:-

bool successNewSocket = _NewSocket.AsyncWaitHandle.WaitOne(2000, true);

可能总是错误的,因为没有将事件设置为信号状态。通常,您会为该函数指定一个回调函数,BeginConnect并在回调中调用EndConnect并将事件的状态设置为已发出信号。请参阅此 MSDN 页面上的示例代码。

更新

我想我看到了另一个问题:-

byte[] outStream = System.Text.Encoding.ASCII.GetBytes(Uimage_Data);

我不知道 Uimage_Data 是什么类型,但我真的不认为你想将它转换为 ASCII。数据中的零可能表示数据字节结束(或者可能是 26 或其他 ASCII 码)。关键是,编码过程很可能会改变数据。

你能提供Uimage_Data对象的类型吗?

于 2012-10-23T09:12:53.780 回答