using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace RDavey.Net
{
public class AsyncTcpClient
{
private IPAddress[] addresses;
private int port;
private WaitHandle addressesSet;
private TcpClient tcpClient;
private int failedConnectionCount;

/// <summary>
/// Construct a new client from a known IP Address
/// </summary>
/// <param name="address">The IP Address of the server</param>
/// <param name="port">The port of the server</param>
public AsyncTcpClient(IPAddress address, int port)
: this(new[] { address }, port)
{
}

/// <summary>
/// Construct a new client where multiple IP Addresses for
/// the same client are known.
/// </summary>
/// <param name="addresses">The array of known IP Addresses</param>
/// <param name="port">The port of the server</param>
public AsyncTcpClient(IPAddress[] addresses, int port)
: this(port)
{
this.addresses = addresses;
}

/// <summary>
/// Construct a new client where the address or host name of
/// the server is known.
/// </summary>
/// <param name="hostNameOrAddress">The host name or address of the server</param>
/// <param name="port">The port of the server</param>
public AsyncTcpClient(string hostNameOrAddress, int port)
: this(port)
{
addressesSet = new AutoResetEvent(false);
Dns.BeginGetHostAddresses(hostNameOrAddress, GetHostAddressesCallback, null);
}

/// <summary>
/// Private constuctor called by other constuctors
/// for common operations.
/// </summary>
/// <param name="port"></param>
private AsyncTcpClient(int port)
{
if (port < 0)
throw new ArgumentException();
this.port = port;
this.tcpClient = new TcpClient();
this.Encoding = Encoding.Default;
}

/// <summary>
/// The endoding used to encode/decode string when sending and receiving.
/// </summary>
public Encoding Encoding { get; set; }

/// <summary>
/// Attempts to connect to one of the specified IP Addresses
/// </summary>
public void Connect()
{
if (addressesSet != null)
//Wait for the addresses value to be set
addressesSet.WaitOne();
//Set the failed connection count to 0
Interlocked.Exchange(ref failedConnectionCount, 0);
//Start the async connect operation
tcpClient.BeginConnect(addresses, port, ConnectCallback, null);
}

/// <summary>
/// Writes a string to the network using the defualt encoding.
/// </summary>
/// <param name="data">The string to write</param>
/// <returns>A WaitHandle that can be used to detect
/// when the write operation has completed.</returns>
public void Write(string data)
{
byte[] bytes = Encoding.GetBytes(data);
Write(bytes);
}

/// <summary>
/// Writes an array of bytes to the network.
/// </summary>
/// <param name="bytes">The array to write</param>
/// <returns>A WaitHandle that can be used to detect
/// when the write operation has completed.</returns>
public void Write(byte[] bytes)
{
NetworkStream networkStream = tcpClient.GetStream();
//Start async write operation
networkStream.BeginWrite(bytes, 0, bytes.Length, WriteCallback, null);
}

/// <summary>
/// Callback for Write operation
/// </summary>
/// <param name="result">The AsyncResult object</param>
private void WriteCallback(IAsyncResult result)
{
NetworkStream networkStream = tcpClient.GetStream();
networkStream.EndWrite(result);
}

/// <summary>
/// Callback for Connect operation
/// </summary>
/// <param name="result">The AsyncResult object</param>
private void ConnectCallback(IAsyncResult result)
{
try
{
tcpClient.EndConnect(result);
}
catch
{
//Increment the failed connection count in a thread safe way
Interlocked.Increment(ref failedConnectionCount);
if (failedConnectionCount >= addresses.Length)
{
//We have failed to connect to all the IP Addresses
//connection has failed overall.
return;
}
}

//We are connected successfully.
NetworkStream networkStream = tcpClient.GetStream();
byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
//Now we are connected start asyn read operation.
networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer);
}

/// <summary>
/// Callback for Read operation
/// </summary>
/// <param name="result">The AsyncResult object</param>
private void ReadCallback(IAsyncResult result)
{
int read;
NetworkStream networkStream;
try
{
networkStream = tcpClient.GetStream();
read = networkStream.EndRead(result);
}
catch
{
//An error has occured when reading
return;
}

if (read == 0)
{
//The connection has been closed.
return;
}

byte[] buffer = result.AsyncState as byte[];
string data = this.Encoding.GetString(buffer, 0, read);
//Do something with the data object here.
//Then start reading from the network again.
networkStream.BeginRead(buffer, 0, buffer.Length, ReadCallback, buffer);
}

/// <summary>
/// Callback for Get Host Addresses operation
/// </summary>
/// <param name="result">The AsyncResult object</param>
private void GetHostAddressesCallback(IAsyncResult result)
{
addresses = Dns.EndGetHostAddresses(result);
//Signal the addresses are now set
((AutoResetEvent)addressesSet).Set();
}
}
}

一个封装不错的 TcpClient 类的更多相关文章

  1. Android开发之Toast吐司的一个封装好的工具类。带有源代码java文件,

    import android.content.Context; import android.widget.Toast; //Toast统一管理类 public class T { private T ...

  2. 一个封装的使用Apache HttpClient进行Http请求(GET、POST、PUT等)的类。

    一个封装的使用Apache HttpClient进行Http请求(GET.POST.PUT等)的类. import com.qunar.payment.gateway.front.channel.mp ...

  3. 一个封装比较完整的FTP类——clsFTP

    前几天,看见园子里面的博友写了一个支持断点续传的FTP类,一时技痒,干脆写了个更完整的clsFtp类.只是我写这个clsFtp不是支持断点续传的目的,而是为了封装FTP几个基本常用的操作接口. 功能 ...

  4. TcpClient类与TcpListener类

    TcpClient类 //构造方法1 TcpClient t = new TcpClient(); t.Connect(); //构造方法2 IPEndPoint iep = ); TcpClient ...

  5. Android RecyclerView单击、长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类

     Android RecyclerView单击.长按事件:基于OnItemTouchListener +GestureDetector标准实现(二),封装抽取成通用工具类 我写的附录文章2,介绍了 ...

  6. Redis操作Hash工具类封装,Redis工具类封装

    Redis操作Hash工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>> ...

  7. Redis操作字符串工具类封装,Redis工具类封装

    Redis操作字符串工具类封装,Redis工具类封装 >>>>>>>>>>>>>>>>>>& ...

  8. 一个漂亮的php验证码类

    一个漂亮的php验证码类(分享)   作者: 字体:[增加 减小] 类型:转载 下面小编就为大家分享一个漂亮的php验证码类.需要的朋友可以过来参考下   直接上代码: 复制代码 代码如下: //验证 ...

  9. winform网络编程之TcpClient类,TcpListener类和UdpClient类

    TcpClient类和TcpListener类 (1)TcpClient的用途: 用于在同步阻止模式下通过网络来链接.发送和接受流数据,在此情况下,必须有侦听此连接的请求,而侦听的任务就交给TcpLi ...

随机推荐

  1. Jmeter入门(压力测试)

    Jmeter介绍 Jmeter是一款使用Java开发的,开源免费的,测试工具, 主要用来做功能测试和性能测试(压力测试/负载测试). 而且用Jmeter 来测试 Restful API, 非常好用. ...

  2. 【Android】让Python在Android系统上飞一会儿

    第一节 在手机上配置Python运行环境 1.下载和安装 Scripting Layer for Android (SL4A) Scripting Layer for Android (SL4A) 是 ...

  3. jmeter访问mysql数据库

    jdbc:mysql://localhost:3306/jy?allowMultiQueries=true 如果想同时执行多条语句

  4. 强大的图片展示插件,JQuery图片预览展示插件

    只需要引入JQuery.js , viewer.css 和 viewer.js <!DOCTYPE html> <html lang="en"> <h ...

  5. 配置windows批处理脚本(.bat)文件路径 | window批处理文件配置执行路径

    以PHP的composer为例 1 . 路径D:\phpStudy\php\php-5.5.38加入环境变量 2.在路径D:\phpStudy\php\php-5.5.38新建composer.bat ...

  6. JavaSE| 泛型

    泛型 泛型:对后续所有操作的类型做约束,对后续操作起作用,对之前的不起作用: 对类型进行约束:  父 ----> 子,从范围上,父范围小,子范围大:把范围小的给范围大的, JDK1.5改写了集合 ...

  7. day23 面向对象 函数和方法区分

    最近两周内容大概回顾: # 文件操作 # # 模块:random,序列化模块,时间模块,collections,re,os,sys # 模块与包的概念和导入方法 # 写代码的规范 # 正则表达式 # ...

  8. Java实现简单计算器、抽票程序

    计算器: import java.awt.BorderLayout; import java.awt.Container; import java.awt.Font; import java.awt. ...

  9. POJ 1470 Closest Common Ancestors (模板题)(Tarjan离线)【LCA】

    <题目链接> 题目大意:给你一棵树,然后进行q次询问,然后要你统计这q次询问中指定的两个节点最近公共祖先出现的次数. 解题分析:LCA模板题,下面用的是离线Tarjan来解决.并且为了代码 ...

  10. Effective前端1---chapter 1 HTML/CSS优化

    最近在读高效前端:web高效编程与优化实践,借此本书的感受总结下前端代码与性能优化,纯属自己见解,如有错误,欢迎指出. 1.能用HTML/CSS解决的问题就不要用js 场景1:鼠标悬浮时显示 鼠标悬浮 ...