示例

以下一个简单的异步事件TCP客户端实现

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading; namespace Leestar54
{
/// <summary>
/// 自定义回调事件参数
/// </summary>
/// <typeparam name="T">泛型类返回</typeparam>
public class TEventArgs<T> : EventArgs
{
public T Result { get; private set; }
public TEventArgs(T obj)
{
this.Result = obj;
}
} class MyTcpClient
{
private string md5id;
Thread readThread;
Thread heartbeatThread;
TcpClient tcpClient;
NetworkStream ns;
//AsyncOperation会在创建他的上下文执行回调
public AsyncOperation AsyncOperation;
private static MyTcpClient singleton = null;
static readonly object lazylock = new object(); #region Event
//回调代理中处理事件
public event EventHandler Connected;
public event EventHandler<TEventArgs<JObject>> Receive;
public event EventHandler<TEventArgs<Exception>> Error; //AsyncOperation回调代理
private SendOrPostCallback OnConnectedDelegate;
private SendOrPostCallback OnReceiveDelegate;
private SendOrPostCallback OnErrorDelegate; private void OnConnected(object obj)
{
Connected?.Invoke(this, EventArgs.Empty);
} private void OnReceive(object obj)
{
Receive?.Invoke(this, new TEventArgs<JObject>((JObject)obj));
} private void OnError(object obj)
{
Error?.Invoke(this, new TEventArgs<Exception>((Exception)obj));
} #endregion /// <summary>
/// 构造函数
/// </summary>
MyTcpClient()
{
OnConnectedDelegate = new SendOrPostCallback(OnConnected);
OnReceiveDelegate = new SendOrPostCallback(OnReceive);
OnErrorDelegate = new SendOrPostCallback(OnError);
} /// <summary>
/// 单例模式
/// </summary>
/// <returns></returns>
public static MyTcpClient getInstance()
{
if (singleton == null)
{
lock (lazylock)
{
if (singleton == null)
{
singleton = new MyTcpClient();
}
}
}
return singleton;
} //当前客户端唯一id
public string Md5id
{
get
{
return md5id;
} set
{
md5id = value;
}
} /// <summary>
/// 连接服务器
/// </summary>
public void Connect()
{ try
{
tcpClient = new TcpClient("localhost", 9501);
if (tcpClient.Connected)
{
ns = tcpClient.GetStream();
//开启两个线程长连接,一个读取,一个心跳
readThread = new Thread(Read);
readThread.IsBackground = true;
readThread.Start();
heartbeatThread = new Thread(HeartBeat);
heartbeatThread.IsBackground = true;
heartbeatThread.Start();
System.Diagnostics.Debug.WriteLine("服务器连接成功");
this.SendMsg(JObject.FromObject(new
{
cmd = "connect"
}));
}
}
catch (Exception e)
{
this.AsyncOperation.Post(OnErrorDelegate, e);
Thread.Sleep(5000);
ReConnect();
}
}
/// <summary>
/// 读取接收到的数据
/// </summary>
private void Read()
{
try
{
//休眠2秒让窗口初始化
Thread.Sleep(2000);
Byte[] readBuffer = new Byte[1024];
while (true)
{
int alen = tcpClient.Available;
if (alen > 0)
{
Int32 bytes = ns.Read(readBuffer, 0, alen); string responseData = System.Text.Encoding.UTF8.GetString(readBuffer, 0, bytes);
//为了避免粘包现象,以\r\n作为分割符
string[] arr = responseData.Split("\r\n".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
foreach (var item in arr)
{
if (item != string.Empty)
{
System.Diagnostics.Debug.WriteLine("接受到消息" + item);
JObject jobj = JObject.Parse(item);
this.AsyncOperation.Post(OnReceiveDelegate, jobj);
}
}
}
Thread.Sleep(500);
}
}
catch (Exception e)
{
this.AsyncOperation.Post(OnErrorDelegate, e);
}
} /// <summary>
/// 心跳线程
/// </summary>
private void HeartBeat()
{
try
{
while (true)
{
Thread.Sleep(8000);
byte[] wb = System.Text.Encoding.UTF8.GetBytes("+h");
ns.Write(wb, 0, wb.Length);
}
}
catch (Exception e)
{
this.AsyncOperation.Post(OnErrorDelegate, e);
Thread.Sleep(5000);
ReConnect();
}
} /// <summary>
/// 心跳失败,则网络异常,重新连接
/// </summary>
public void ReConnect()
{
if (readThread != null)
{
readThread.Abort();
} Connect();
} public void SendMsg(string msg)
{
byte[] wb = System.Text.Encoding.UTF8.GetBytes(msg);
ns.Write(wb, 0, wb.Length);
} public void SendMsg(JObject json)
{
SendMsg(json.ToString(Formatting.None));
}
}
}

使用方法

MyTcpClient client = MyTcpClient.getInstance();
//保证回调函数是在创建他的上下文执行(一般是UI线程)
client.AsyncOperation = AsyncOperationManager.CreateOperation(null);
client.Error += Client_Error; ;
client.Receive += Client_Receive; ;
client.Connected += Client_Connected;
client.Connect();

参考

http://www.cnblogs.com/kex1n/p/6502002.html

https://www.codeproject.com/Articles/14265/The-NET-Framework-s-New-SynchronizationContext-Cla

http://www.cnblogs.com/leestar54/p/4591792.html

https://msdn.microsoft.com/zh-cn/library/vs/alm/system.componentmodel.asyncoperationmanager.createoperation(v=vs.85)

附件列表

C# TCPClient简单示例的更多相关文章

  1. Linux下的C Socket编程 -- server端的简单示例

    Linux下的C Socket编程(三) server端的简单示例 经过前面的client端的学习,我们已经知道了如何创建socket,所以接下来就是去绑定他到具体的一个端口上面去. 绑定socket ...

  2. C# 构建XML(简单示例)

    C# 构建XML的简单示例: var pars = new Dictionary<string, string> { {"url","https://www. ...

  3. 根据juery CSS点击一个标签弹出一个遮罩层的简单示例

    <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <m ...

  4. ACEXML解析XML文件——简单示例程序

    掌握了ACMXML库解析XML文件的方法后,下面来实现一个比较完整的程序. 定义基本结构 xml文件格式如下 <?xml version="1.0"?> <roo ...

  5. demo工程的清单文件及activity中api代码简单示例

    第一步注册一个账户,并创建一个应用.获取app ID与 app Key. 第二步下载sdk 第三步新建工程,修改清单文件,导入相关的sdk文件及调用相应的api搞定. 3.1 修改清单文件,主要是加入 ...

  6. spring-servlet.xml简单示例

    spring-servlet.xml简单示例 某个项目中的spring-servlet.xml 记下来以后研究用 <!-- springMVC简单配置 --> <?xml versi ...

  7. SignalR 简单示例

    一.什么是 SignalR ASP.NET SignalR is a library for ASP.NET developers that simplifies the process of add ...

  8. Web API 简单示例

    一.RESTful和Web API Representational State Transfer (REST) is a software architecture style consisting ...

  9. XML引入多scheme文件约束简单示例

    XML引入多scheme文件约束简单示例,用company.xsd和department.xsd来约束company.xml: company.xsd <?xml version="1 ...

随机推荐

  1. 使用electron-packager electron-builder electron-updater 打包vue项目,支持在线更新

    1.如何用electron-packager electron-builder打包vue项目,打包成桌面程序. 步骤一. 执行npm run build 打包你的vue项目. 打包成功后,生成dist ...

  2. [翻译]Writing Custom DB Engines 编写定制的DB引擎

    Writing Custom DB Engines  编写定制的DB引擎   FastReport can build reports not only with data sourced from ...

  3. Android-进程理解/进程的优先级别

    进程理解 Android系统最小的控制单元是:进程 process 应用/CPU最小的控制单元是:线程 thread 一个应用一个 process 进程 一个应用一个 package(包是唯一的) 一 ...

  4. Default style sheet for HTML 4

    http://www.w3.org/TR/CSS21/sample.html html, address, blockquote, body, dd, div, dl, dt, fieldset, f ...

  5. 编译Hadoop1.0.2历程和解决问题记录

    1.安装eclipse3.6.2, 废止3.7, 这个有很多问题 2.安装eclipse插件ivy You can install Apache IvyDE plugins from the IvyD ...

  6. mybatis 使用tips - 使用多个参数

    执行如下命令: mvn -Dmybatis.generator.overwrite=true mybatis-generator:generate 可以使用mybatis generator myba ...

  7. ADO.NET批量添加数据到SQL Server—BulkCopy使用指南

    BulkCopy位于System.Data.SqlClient命名空间,允许你使用其他源的数据有效地批量加载 SQL Server 表. 属性: BatchSize :每个批处理中的行数. 在每个批处 ...

  8. eCharts IE8兼容性问题

    使用Echart的图表柱状图,里面用了Float32Array,IE8下面会提示无法找到Float32Array,黄色叹号. 网上查找后使用如下方法解决:不明觉厉 在<head></ ...

  9. Enabling Remote Errors in SSRS

    January 18, 2011 By default the remote errors property in SQL Server Reporting Services is set to fa ...

  10. Plasma Cash合约解读

    Plasma Cash合约解读 SmartPlasma 合约解读 1. 合约代码 2. 合约文件简单介绍 3. Plasma Cash 的基础数据结构 3.1 Plasma Cash 中的资产 3.2 ...