这是我在这个论坛发布的第一个问题,我是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);
}
在他们说要将数据分成块的论坛中,这是一个解决方案,如果是这样我怎么能这样做,我已经尝试过但它没有用!
答案 0 :(得分:2)
有许多不同的解决方案但是分块通常是一个很好的解决方案,你可以盲目地做这个,你继续填充你的临时缓冲区,然后把它放到一些状态缓冲区,直到你点击一些任意的令牌或缓冲区不完全完全,或者你可以遵守每个tcp 消息的某种合同(一条消息是要收到的整体数据)。
如果你要考虑做某种合同,那么做一些事情就像消息的前N个字节是描述符,你可以根据需要做大或小,但你的临时缓冲区只会读取这个从溪流前面开始。
典型的标题可能是:
public struct StreamHeader // 5 bytes
{
public byte MessageType {get;set;} // 1 byte
public int MessageSize {get;set;} // 4 bytes
}
所以你会读到它,如果它足够小,可以将完整的消息大小分配给临时缓冲区并全部读取,或者如果你认为它太大,将它分成几部分并继续读取直到你收到的总字节数匹配标题结构的MessageSize部分。
答案 1 :(得分: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,...);
答案 2 :(得分:0)
我怀疑你的一个问题是你没有打电话给EndConnect
。从MSDN文档:
必须通过调用EndConnect方法完成异步BeginConnect操作。
此外,等待: -
bool successNewSocket = _NewSocket.AsyncWaitHandle.WaitOne(2000,true);
可能始终为false,因为没有任何内容将事件设置为信号状态。通常,您可以为BeginConnect
函数指定一个回调函数,并在回调中调用EndConnect
并将事件的状态设置为发信号。请参阅示例代码on this MSDN page。
<强>更新强>
我想我看到了另一个问题: -
byte[] outStream = System.Text.Encoding.ASCII.GetBytes(Uimage_Data);
我不知道什么类型的Uimage_Data,但我真的不认为你想把它转换成ASCII。数据中的零可以表示数据字节的结尾(或者可能是26或其他ASCII码)。关键是,编码过程可能正在改变数据。
您能提供Uimage_Data
对象的类型吗?
答案 3 :(得分:0)
最有可能的问题是,在将所有数据传输到服务器之前,您正在关闭客户端套接字,因此它将被丢弃。
默认情况下,关闭套接字时,将丢弃所有未传输的数据(位于操作系统缓冲区中)。有几个解决方案:
[1]设置SO_LINGER(参见http://developerweb.net/viewtopic.php?id=2982) [2]让服务器向客户端发送确认,并且在收到客户端套接字之前不要关闭它。 [3]在关闭套接字之前等到客户端输出缓冲区为空(使用getsocketopt SO_SND_BUF进行测试 - 我不确定c#上的语法)。
你真的应该测试Send()的返回值。虽然理论上它应该阻塞直到它发送所有数据,但我想要实际验证,并且如果存在不匹配,至少会打印错误消息。
答案 4 :(得分:-1)
请注意:我不知道Mo是什么;但如果它超过64 KB,那么你做错了。 TCP协议本身对数据包大小有限制。最大值是64 KB但是你无法达到!那是因为不同层的数据包的最大大小不同。 “The MTU (Maximum Transmission Unit) for Ethernet, for instance, is 1500 bytes.”