(高分跪地求)c# socket 使用环形队列实例

cyljay 2010-08-04 03:07:51
环形缓冲流方法已经写好。有两个方法 Write(byte[] buffer, int offset, int count) Read(byte[] buffer, int offset, int count) 采用的是异步接收数据。
this._scoket.BeginReceive(dataBuff, 0, dataBuff.Length, SocketFlags.None, new AsyncCallback(ReceiveDataCallback), this);
现在的问题是如何进行 Write 和 Read 方法的调用,求高人指点,若有实例作参考更好。感激不尽!!!(搞了两天了,郁闷中!)
...全文
348 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
cyljay 2010-08-05
  • 打赏
  • 举报
回复
我相信肯定有人用过的
JiuchunYoung 2010-08-05
  • 打赏
  • 举报
回复
顶一下 应该有不同的方法吧 楼主用的方法 没有多少人会吧
cyljay 2010-08-05
  • 打赏
  • 举报
回复
贴一段代码上来吧
  /// <summary>
/// 接收数据包方法
/// </summary>
private void ReceivePacketData()
{
this._scoket.BeginReceive(dataBuff, 0, dataBuff.Length, SocketFlags.None,
new AsyncCallback(ReceiveDataCallback), this);
}
/// <summary>
/// 处理数据包接收回发函数
/// </summary>
/// <param name="ar">上下文对象</param>
private void ReceiveDataCallback(IAsyncResult ar)
{
ClntState cs = (ClntState)ar.AsyncState;
int recvCount = cs._scoket.EndReceive(ar, out errorCode);
if (recvCount <= 0)//这时候应该客户端关闭连接了,一般=0
{
//客户关闭连接
Console.WriteLine("客户端关闭或断开连接!");
if (this.DisConnected != null)
{ DisConnected(this, new NetEventArgs("客户关闭连接!")); }
return;
}
if (errorCode == SocketError.Success)
{

ringMem.Write(dataBuff, 0, dataBuff.Length);
th_readRinMem = new Thread(new ThreadStart(ReadPacket));
th_readRinMem.Start();

//ReadPacket();

}
else
{
if (this.DisConnected != null)
{ DisConnected(this, new NetEventArgs("接收数据失败!!!")); }
}
//重新接收包信息
ReceivePacketData();
}
/// <summary>
/// 读取包信息线程入口
/// </summary>
private void ReadPacket()
{
int leftSize = headerBuff.Length; //剩余数据包头长度
while (true) //为了保证数据完整,这里循环读取,一般一次性能读完
{
leftSize -= this.ringMem.Read(headerBuff, 0, headerBuff.Length);//读取信息头 可能要循环读取
if (leftSize <= 0)
{ break; }
}
//处理头包 并开始接收信息体
currentheader = (PacketHeaderStruct)SerializeTools.DeserializeFromBytes(headerBuff);
if (curHeader.type > 0 && ringMem != null)
{
if (msgBuff != null)
{ msgBuff = null; } //释放内存
msgBuff = new byte[curHeader.length]; //申请内存
int leftSize1 = msgBuff.Length;
while (true) //为了保证数据完整,这里循环读取,一般一次性能读完
{
leftSize1 -= this.ringMem.Read(msgBuff, 0, msgBuff.Length);//读取信息体 可能要循环读取
if (leftSize <= 0)
{ break; }
}
msgObj = SerializeTools.DeserializeFromBytes(msgBuff);
//信息头,和信息体都接收完毕,开始处理信息体,交给ServSocket处理
if (this.ReceiveData != null)
{
this.ReceiveData(this, new NetEventArgs(msgObj)); //接收到数据由ServSocket进行处理
}

}
else //如果没有信息体,继续接收下个信息头,但是也得调用信息处理
{
if (this.ReceiveData != null)
this.ReceiveData(this, new NetEventArgs("接收到信息"));
//重新接收包信息
ReceivePacketData();
}
}


红色部门是调用已写好的环形缓冲流类读写方法。这样用第一次读写数据正常,再次次通信时,到黄色部分,headerBuff 值为空,调用反序列方法时就报异常,不知道什么原因。请大侠些帮忙看看
Joe-xXx 2010-08-05
  • 打赏
  • 举报
回复
路过,环形队列的Socket管理方式还没实现过啊
cyljay 2010-08-05
  • 打赏
  • 举报
回复
应该是设计包体,不是包头
cyljay 2010-08-05
  • 打赏
  • 举报
回复
恩,我采用的方法和你有些不同。我用了一个环形流来对数据进行缓冲。接收数据时进行write操作,然后开一个线程进行read操作。但是调试总有问题,所以我不能确定我调用的方式是否正确。
还有一个问题,一般情况下我们设计包头是在同一个结构体内设计还是分成两个结构分别设计包头和包尾,发送的时候再将这两个结构体一并发送?
请叫我卷福 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 cyljay 的回复:]

问一下楼上,你的 recvBuffer 默认设置的大小是多少。我设计的包头和包尾是两个不同的结构体,在发送端用两个send方法发送的,接收时,我只用一次BeginReceive来接收可以吗?
[/Quote]
recvBuffer 我设置为1024 其实可以任意设置 不一定要1024
楼主还没有明白 用缓冲区的作用 既然用了缓冲区 就没有必要规定 代码中接受缓冲区(本例中为recvBuffer)的大小 因为就算你设置了recvBuffer为1024 程序运行时 也不是当recvBuffer接受到了1024byte之后 Socket.EndReceive才返回 他可能在接受到了10 byte就返回了 也可能接受到100byte就返回了 正因为这样不容易接受到一个完整的包 所以我们采用缓冲区啊....
cyljay 2010-08-04
  • 打赏
  • 举报
回复
问一下楼上,你的 recvBuffer 默认设置的大小是多少。我设计的包头和包尾是两个不同的结构体,在发送端用两个send方法发送的,接收时,我只用一次BeginReceive来接收可以吗?
cyljay 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 xiaozhi_5638 的回复:]
又见楼主发帖了
消息流 MessageStream 类 上次已经贴出来了...
以下是接受数据的代码 即调用Write 和 ReadMessage 的代码

(以下为异步接受数据代码的 一部分 各种消息处理 函数 没有写出)

C# code


/// <summary>
/// 格式化后的消息类
/// </summary>
class ……
[/Quote]

呵呵,又见你回帖了,非常感谢!问题还没解决,所以又来了。
请叫我卷福 2010-08-04
  • 打赏
  • 举报
回复
又见楼主发帖了
消息流 MessageStream 类 上次已经贴出来了...
以下是接受数据的代码 即调用Write 和 ReadMessage 的代码

(以下为异步接受数据代码的 一部分 各种消息处理 函数 没有写出)


/// <summary>
/// 格式化后的消息类
/// </summary>
class Message
{
public byte Head;
public Int32 Length;
public byte[] Content;
}

/// <summary>
/// 异步接受数据时的回调方法
/// </summary>
/// <param name="ar"></param>
private void OnReceive(IAsyncResult ar) //
{
Socket clientSocket = (Socket)ar.AsyncState;
int real = clientSocket.EndReceive(ar);

if (DealData(clientSocket, real)) //处理接受到的 byte 数据 注意,此时的数据为byte类型
{
clientSocket.BeginReceive(recvBuffer, 0, 1024, SocketFlags.None, new AsyncCallback(OnReceive), clientSocket);//循环接受数据
}
else //服务器关闭socket
{
UpdateForServerExit(); //更新窗体信息
clientSocket.Close();
}
}

/// <summary>
/// 处理接收到的数据
/// </summary>
/// <param name="client"></param>
/// <param name="real"></param>
/// <returns></returns>
private bool DealData(Socket client, int real) //处理接受到的byte类型的数据
{
messageStream.Write(recvBuffer, 0, real);//先将接受到的字节流 写入messageStream缓冲区 这儿是调用Write的地方~~~~~~~~~~~~~~~~~~~~~~~~~~
Message msg = new Message();

while (messageStream.ReadMessage(out msg)) //循环读取消息 调用ReadMessage的地方~~~~~~~~~~~
{
switch (msg.Head) //消息类型
{
case 0: //消息类型为 0
{
// 调用相应 消息处理 函数
break;
}
case 1: //消息类型为 1
{
//调用相应 消息处理 函数
break;
}
case 2: // 消息类型为3
{
//调用相应 消息处理 函数
break;
}
//...............

}

if (msg.Head == 0) //如果服务器端关闭socket(消息类型为 0),那么就返回false
{
return false;
}
}
return true;//对方没有关闭socket,返回true
}
cyljay 2010-08-04
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 hwbox 的回复:]
dataBuff,不就是缓冲区么?为什么还要弄个缓冲区?
[/Quote]
它的作用就是把dataBuff 通过写指针写进我定义好的环形缓冲流。然后读指针读取这个流,进行解包,用这个技术的目的就是较好地解决通信丢包,粘包的问题,让程序容错性更强。
myhope88 2010-08-04
  • 打赏
  • 举报
回复
没弄过,帮顶下
hwbox 2010-08-04
  • 打赏
  • 举报
回复
dataBuff,不就是缓冲区么?为什么还要弄个缓冲区?
cyljay 2010-08-04
  • 打赏
  • 举报
回复
顶一个。请大家帮帮忙。

110,546

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧