Tcp 数据对象传输接口对象设计
输入是一个对象inputObj,接口对象.Send(inputObj),对端接收之后解包成outputObj(与inputObj应相同),触发onPackageReceive事件
- 事件
public event DataServiceHandler onPackageReceived;//收包事件:
public event DataServiceHandler onPackageSent;//发包事件:
public event DataServiceHandler onPeerDisconnected;// 失连事件:
public event DataServiceHandler onSendingException;//发包异常事件;
public event DataServiceHandler onReceivingException;//收包异常时间;
public event DataServiceHandler onNotify;//对象通知事件(通知一些状态信息什么的)
- 成员
SetClient()//关联Tcp连接到数据对象传输接口,复位数据对象状态,开始接收线程,允许发
Reset()//复位数据对象状态,开始接收线程,允许发
Stop()//停止接收线程,禁止发
Send()//发送数据对象
public class draftClass
{
#region Structure
#endregion #region Fields
object locker;
TcpClient clientObj;
Messager messager=new Messager();
Thread recvThread;
#endregion #region Events
public delegate void DataServiceHandler(string msg,object sender);
public event DataServiceHandler onPackageReceived;
public event DataServiceHandler onPackageSent;
public event DataServiceHandler onPeerDisconnected;
public event DataServiceHandler onSendingException;
public event DataServiceHandler onReceivingException;
public event DataServiceHandler onNotify;
#endregion #region Functions
public void SetClient(TcpClient tc)
{
Stop();
clientObj = tc;
StartReceiving();
}
public void ReStart()
{
SetClient(this.clientObj);
}
public void Stop() { lock (recvThread) { recvThread.Abort(); } } /// <summary>
/// 打包msg和数据对象,并发送
/// </summary>
/// <param name="msg"></param>
/// <param name="o"></param>
public void Send(string msg, object o)
{
byte[] m = new byte[];
Encoding.UTF8.GetBytes(msg).CopyTo(m, );
byte[] data = ObjectToBytes(o);
byte[] d = new byte[m.Length + data.Length];
m.CopyTo(d, );
data.CopyTo(d, m.Length); Send(this.clientObj.GetStream(), d);
}
public void StartReceiving()
{
Thread t = new Thread(new ThreadStart(Receiving));
t.Name = "[DataService] Receiving Thread";
t.Start();
} private void Send(NetworkStream ns, byte[] d)
{
lock (this)
{
NetworkStream netStream = ns;
byte[] data = new byte[d.Length + ];
System.BitConverter.GetBytes(d.Length).CopyTo(data, );
d.CopyTo(data, ); netStream.Write(data, , data.Length);
}
}
private void Receiving()
{
{
Console.WriteLine("In Thread({0}),WaitingData", Thread.CurrentThread.ManagedThreadId);
NetworkStream ns = clientObj.GetStream();
while (IsOnline())
{
while (ns.DataAvailable)
{
#if DEBUG
DateTime start = DateTime.Now;
#endif
//收到的数据为2进制的原始数据,数据交给分发器处理函数
byte[] data = ReceiveByteArray(ns);
Distributor(data);
#if DEBUG
TimeSpan ts = DateTime.Now - start;
double r = data.Length * / (ts.TotalSeconds * * );
Console.WriteLine("ReceiveByteArray Length={0}\tDuring={1:f0}ms\tRate= {2:f3} Mbps", data.Length, ts.TotalMilliseconds, r);
#endif
}
//Thread.Sleep(3);
}
Console.WriteLine("In Thread({0}),clientObj Disconnect!", Thread.CurrentThread.ManagedThreadId); if (onPeerDisconnected != null)
onPeerDisconnected("Peer Disconnected",null);
Thread.CurrentThread.Abort();
}
}
//报文结构是自定义的2进制数据
//Part1:定长100字节,存放消息
//Part2:序列化了的数据对象
private void Distributor(byte[] data)
{
//解包
string msg = GetMsg(data);
object obj = GetObj(data); //msg过Messager.Paser()
if (messager.TryParser(msg, obj))
return; //如果Messager处理失败,触发onPackageReceived事件
if (onPackageReceived != null)
onPackageReceived("",data);
}
#region api
private string GetMsg(byte[] data) { return ""; }
private object GetObj(byte[] data) {return new object(); }
private byte[] ReceiveByteArray(NetworkStream stream)
{
try
{
int bufferlen = GetSize(stream);
byte[] resultbyte = new byte[bufferlen]; int offset = , bytesread = ;
while (offset < bufferlen)
{
bytesread = stream.Read(resultbyte, offset, bufferlen - offset);
if (bytesread == )
{
Console.WriteLine("?????A");
throw new Exception("网络异常断开,数据读取不完整。");
}
else
offset += bytesread;
}
return resultbyte;
}
catch (Exception)
{
Console.WriteLine("?????B");
throw;
}
}
private int GetSize(NetworkStream stream)
{
try
{
int bufferlen = ;
byte[] resultbyte = new byte[bufferlen]; int offset = , bytesread = ;
while (offset < bufferlen)
{
bytesread = stream.Read(resultbyte, offset, bufferlen - offset);
if (bytesread == )
throw new Exception("网络异常断开,数据读取不完整。");
else
offset += bytesread;
}
return System.BitConverter.ToInt32(resultbyte, );
}
catch (Exception)
{
throw;
}
}
private bool IsOnline()
{
TcpClient c = this.clientObj;
return !((c.Client.Poll(, SelectMode.SelectRead) && (c.Client.Available == )) || !c.Client.Connected);
}
/// <summary>
/// 将一个object对象序列化,返回一个byte[]
/// </summary>
/// <param name="obj">能序列化的对象</param>
/// <returns></returns>
///
private byte[] ObjectToBytes(object obj)
{
using (MemoryStream ms = new MemoryStream())
{
IFormatter formatter = new BinaryFormatter(); formatter.Serialize(ms, obj); return ms.GetBuffer();
}
}
/// <summary>
/// 将一个序列化后的byte[]数组还原
/// </summary>
/// <param name="Bytes"></param>
/// <returns></returns>
private object BytesToObject(byte[] Bytes)
{
using (MemoryStream ms = new MemoryStream(Bytes))
{
IFormatter formatter = new BinaryFormatter(); return formatter.Deserialize(ms);
}
}
#endregion
#endregion
}
DataService.cs
Tcp 数据对象传输接口对象设计的更多相关文章
- 网络TCp数据的传输设计(黏包处理)
//1.该片为引用别人的文章:http://www.cnblogs.com/alon/archive/2009/04/16/1437599.html 解决TCP网络传输"粘包"问题 ...
- TCP数据的传输过程(十)
建立连接后,两台主机就可以相互传输数据了.如下图所示: 上图给出了主机A分2次(分2个数据包)向主机B传递200字节的过程.首先,主机A通过1个数据包发送100个字节的数据,数据包的 Seq 号设置为 ...
- TCP数据的传输过程
建立连接后,两台主机就可以相互传输数据了.如下图所示: 上图给出了主机A分2次(分2个数据包)向主机B传递200字节的过程.首先,主机A通过1个数据包发送100个字节的数据,数据包的 Seq 号设置为 ...
- 4G DTU无线数据透明传输终端
4G DTU是基于4G网络的远程无线数据透明传输终端,是一种物联网无线数据传输设备,使用公用运营商的4G网络为用户提供无线远距离数据传输功能,使用工业级32位的高性能通信处理器和工业级无线模块,以嵌入 ...
- 前端H5中JS用FileReader对象读取blob对象二进制数据,文件传输
HTML5中的Blob对象只是二进制数据的容器,本身并不能操作二进制,故本篇将对其操作对象FileReader进行介绍. FileReader FileReader主要用于将文件内容读入内存,通过一系 ...
- Activity之间传递数据或数据包Bundle,传递对象,对象序列化,对象实现Parcelable接口
package com.gaojinhua.android.activitymsg; import android.content.Intent; import android.os.Bundle; ...
- DDD的实体、值对象、聚合根的基类和接口:设计与实现
1 前置阅读 在阅读本文章之前,你可以先阅读: 什么是DDD 2 实现值对象 值对象有两个主要特征:它们没有任何标识.它们是不可变的. 我们举个例子:小明是"浙江宁波"人,小红也是 ...
- HDFS对象存储--Ozone架构设计
前言 如今做云存储的公司非常多,举2个比較典型的AWS的S3和阿里云.他们都提供了一个叫做对象存储的服务,就是目标数据是从Object中进行读写的,然后能够通过key来获取相应的Object,就是所谓 ...
- 网络层、传输层、应用层、端口通信协议编程接口 - http,socket,tcp/ip 网络传输与通讯知识总结
引: http://coach.iteye.com/blog/2024511 什么是TCP和UDP,以及二者区别是什么? TCP的全称为传输控制协议.这种协议可以提供面向连接的.可靠的.点到点的通信. ...
随机推荐
- 查看kafka的group.id
kafka/config目录下的consumer.properties中可以看到
- Parser Error Message: Access is denied【转】
PRB: Access Denied Error When You Make Code Modifications with Index Services Running View products ...
- oc随笔二:组合、继承
在oc中如果没有使用ARC的话,手动管理内存一定要注意处理好“野指针”,通常我们在释放指针的指向的地址时,都要将指针赋值为nil,这样能有效的防止野指针.常用的关键字:retain.assign .s ...
- linux中的fork函数的基本用法
代码: #include <iostream> #include <string> #include <cstdio> #include <unistd.h& ...
- BestCoder Round #36 (hdu5199)Gunner(水题)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud Gunner Time Limit: 8000/4000 MS (Java/Oth ...
- Qt窗口句柄
关键字: 透明效果,异形,子窗口,控件,浮窗,同级句柄
- js delete 用法
1,对象属性删除 function fun(){ this.name = 'mm'; } var obj = new fun(); console.log(obj.name);//mm delet ...
- 【笔记】Linux 和 Unix 作业控制
Linux 和 Unix 属于多任务的操作系统,也就是说一个系统在同一时间段内能运行多重任务(进程). 作业控制不只是能够停止/挂起(stop/suspend)正在执行的进程(命令),也可以继续/唤醒 ...
- sqlserver exists和in 与exists和not in
1.exists 和 in 1.1 正常情况下exists和in的效果是一样的,如图试验 即使子查询中包含null也没有关系,依然可以正常使用 1.2 in 和 exists效率比较 先看in 由图中 ...
- head直接复制的
<script type="application/x-javascript"> addEventListener("load", function ...