从网上看了很多资料 ,但是没有能真正帮助我解决TCP粘包的问题的答案。跪求各位高手 ,帮我指点一下 ,最好有源代码和算法 ,让我解决TCP粘包的问题 。谢了 。重谢。
解决方案 »
- ComboBox控件的问题
- 关于Trace输出窗口的问题
- 由键盘输入一个数字,为什么会是输入1却变成49呢
- C# 该如何处理大数据?
- 如何判断调用当前dll或方法的程序是winform还是webform?
- 如何判断 TcpClient 连接是否正常,是否可写数据至 NetworkStream?
- 请问在VS2003 ,在Windows Form程序中,DataGrid控件中怎么实现超过规定记录数目就自动分页的功能?谢谢
- 散分加求助一分组办法(顶的有分,解决成功者在加贴给分
- C# PrintDocument调用针式打印机没有反应,调用普通打印机可以打出来, 求高手指点!!!
- 如何解决C#调用cmd命令行执行exe程序,并发时失败率很高问题?
- C#方面的问题/求解
- 一个C# 调用OUTLOOK的问题。
byte[] buffers = .......
void Receive_Completed(object sender, SocketAsyncEventArgs e)
{
if (e.SocketError != SocketError.Success)
{
//关闭socket
return;
}
if (e.LastOperation != SocketAsyncOperation.Receive)
return;
if (e.BytesTransferred == 0)
{
//关闭socket
return;
}
//接收到的字节数与要接收的长度相同,说明完整接收到了包长部分或者数据部分
if (e.BytesTransferred == e.Count)
{
//数据包的长度
int len = BitConverter.ToInt16(buffers, 0);
//接收到的是长度部分
if (e.Offset < 2)
{
//重新设置缓冲区offset,以接收数据部分
e.SetBuffer(2, len - 2);
}
//接收到的是数据部分
else
{
//已经接收到一个完整的包,处理该包
//重新设置缓冲区,接收下一个包的包长部分
e.SetBuffer(0, 2);
}
}
//包长部分或者数据部分未完整接收
else
{
//设置接收缓冲区为剩余长度
e.SetBuffer(e.Offset + e.BytesTransferred, e.Count - e.BytesTransferred);
}
//进行下一次接收
socket.ReceiveAsync(e);
}
谢谢。我们不会这个项目是不会考虑用内存做的 。之前看到过一个项目是用内存处理的 ,感觉还不错 。可是如果发生TCP粘包 ,那么你接收到的也还是粘包的数据。我觉得用内存的更大意义是保证数据都可以被处理 。但是对于数据的准确性 ,还要在做处理吧 。不知道我这么看对不对 。是我个人的意见 。
1、环形缓冲接收
2、替换接收缓冲区
看来.NET里的异步完成端口现在已经很流行了!最近发现很多朋友用这个类来开发网络程序了,要用上了内存池之类的技术就更完美了!楼主朋友其实对TCP协议还不熟,所以对于处理TCP粘包问题很难上手,其实不管TCP怎么粘包数据那数据都还是在那个网络数据流里面的,要看的是楼主怎么到这个流中去取数据,就像上面的这些朋友说的定义包头标识包长度,或是定义结界符、起始符之类等等;我想楼主朋友应该还没亲身体验过“粘包”这个现象吧?如果体验过了应该会更好的了解,那自然解决之道也就出来了,楼主朋友还是多上手吧!
#region " 发送包 "
/// <summary>
///
/// </summary>
/// <param name="data">实际发送的数据</param>
/// <returns>添加包头长度的数据</returns>
private byte[] SendPack(byte[] data)
{
//data长度不能超出65535
byte[] result = new byte[data.Length + 2];
BitConverter.GetBytes((UInt16)data.Length).CopyTo(result, 0);
data.CopyTo(result, 2);
return result;
}
#endregion #region " 接收包 "
/// <summary>
///
/// </summary>
/// <param name="data">接收到的数据</param>
/// <returns>粘包的数组,实际发送的数据</returns>
private List<byte[]> BackPack(byte[] data)
{
List<byte[]> result = new List<byte[]>();
int index = 0;
do
{
int len = BitConverter.ToUInt16(data, index);
index += 2;
if (index + len <= data.Length)
{
byte[] tmp = new byte[len];
Array.Copy(data, index, tmp, 0, len);
index += len;
result.Add(tmp);
}
else
{ break; }
} while (index + 2 < data.Length);
return result;
}
#endregion给你列个最简单的代码.
发送包前.调用SendPack方法得到发送包.再发送.
接收包后,调用BackPack方法得到List<byte[]>,这个数据就是有可能粘包的数据,如果不粘包.则仅有一条数据..
这句认为包头(记录了本包长度)是在data的开始, 一般情况(即没有错误)包头都应该在data的开始, 但如果包头在中间的某个位置该如何查找到包头呢? 比如数据是这样的:
....前一个包的部分数据|包头|....数据....|包头|....后一个包的数据...
其实就是如何寻找包头的问题...