示例

以下一个简单的异步事件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. Android Studio真机测试

    本页内容 1.真机测试好处多 2.开始吧!真机测试 1.真机测试好处多 不久前才开我的Android Studio之旅,就遇上了一个大麻烦——创建的模拟器各种运行出错.尝试了各种解决方法,都没有什么结 ...

  2. .net core利用MySqlBulkLoader大数据批量导入MySQL

    最近用core写了一个数据迁移小工具,从SQLServer读取数据,加工后导入MySQL,由于数据量太过庞大,数据表都过百万,常用的dapper已经无法满足.三大数据库都有自己的大数据批量导入数据的方 ...

  3. 【转】java遍历实体类的属性和数据类型以及属性值

    和同学接了个外包的活,由于项目中很多地方要用到poi导出excel,而每次导出都要写很多相同的代码,因为poi的cell.setCellValue();每次设置的都是不同实体bean的属性值,导致代码 ...

  4. FIREDAC的TFDJSONDataSets和TFDJSONDeltas查询和提交数据

    服务端代码: uses Data.FireDACJSONReflect, FireDAC.Stan.Storage, FireDAC.Stan.StorageBin, FireDAC.Stan.Sto ...

  5. Git Note - git tag

    git tag is used to create labels, usually for version numbers. Format: git tag <TagName> <r ...

  6. TFS签入代码时,自动修改工作项的状态为“已解决”

    Visual Studio中有一个很酷的功能,就是签入代码到TFS库时,可以关联相应的工作项,实现代码与工作项(需求.任务.Bug等)的关联,从而实现代码的跟踪. 在关联工作项的过程中,如果工作项具备 ...

  7. C++不存在从std::string转换为LPCWSTR的适当函数

    LPCWSTR是什么类型呢? 看看如何定义的: typedef const wchar_t* LPCWSTR; 顾名思义就是: LPCWSTR是一个指向unicode编码字符串的32位指针,所指向字符 ...

  8. WebApi Post string 参数 为空

    用webApi做开发也有很久了 一些 细节平时可能未必很留心 今天就很奇葩 post 只接受一个string 参数的数据 但接收是一直未空 很奇怪 看了一些资料后得出以下结论

  9. sharepoint 版本信息查看

    #检查版本:# PowerShell script to display SharePoint products from the registry. Param( # decide on wheth ...

  10. Android 透明状态栏

    在 android 4 系统中可以设置透明状态栏. 但在 android 5.0 以上遇到问题.但问题是可以解决的,需要正确的设置 theme. 但是需要注意一点,5以上可以修改 status bar ...