通过TCP套接字发送大量数据

这是我在这个论坛上发布的第一个问题,我是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); } 

在他们说要将数据分成块的论坛中,这是一个解决方案,如果是这样我怎么能这样做,我已经尝试但是它没有用!

有很多不同的解决方案但是分块通常是一个很好的解决方案,你可以盲目地做这个,你继续填充你的临时缓冲区,然后把它放到一些有状态的缓冲区,直到你遇到一些任意的令牌或缓冲区没有完全填满,或者你可以遵守每个tcp 消息的某种合同(一条消息是要接收的整体数据)。

如果你要看某种合同,那么做一些事情就像消息的前N个字节是描述符,你可以根据需要做大或小,但你的临时缓冲区只能在前面读取这个大小从溪流。

典型的标题可能是这样的:

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

所以你会读到它,如果它足够小就将完整的消息大小分配给临时缓冲区并全部读取,或者如果你认为它太大,将它分成几部分并继续读取,直到你收到的总字节数与MessageSize相匹配标题结构的一部分。

可能你还没有在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,...); 

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

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

还有,等待: –

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

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

UPDATE

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

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

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

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

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

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

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

你真的应该测试Send()的返回值。 虽然理论上它应该阻塞直到它发送所有数据,但我想要实际validation,并且如果存在不匹配,至少会打印错误消息。

请注意:我不知道Mo是什么; 但如果它超过64 KB,那么你做错了。 TCP协议本身对数据包大小有限制。 最大值是64 KB但是你无法达到! 那是因为不同层的数据包的最大大小不同。 “ 例如,以太网的MTU(最大传输单元)为1500字节。 ”