上一篇文章中,我们提到使用IHttpAsyncHandler来进行UDP的收发操作。由于UDP模型比较简单,所以运行没什么问题。这一篇我主要是使用IHttpAsyncHandler来进行TCP的收发操作。由于TCP的模型比较复杂,所以在设计的时候,稍微麻烦了一些。

核心讲解

首先,我贴上代码,然后来逐一讲解:

using System;
using System.Web;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.IO; namespace SocketViaWeb
{
#region 写日志 public static class Logger
{
//写日志
public static void WriteLog(string content)
{
try
{
string timeStamp = DateTime.Now.ToString("yyyyMMdd");
string filePath = "C:\\TestLog." + timeStamp + ".txt";
string contentAll = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ") + ":" + content + Environment.NewLine;
byte[] b = Encoding.Default.GetBytes(contentAll);
using (FileStream fs = new FileStream(filePath, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))
{
fs.Write(b, , b.Length);
fs.Flush();
}
}
catch (Exception ex) { }
}
}
#endregion #region 返回异步执行结果
public class MyAsyncResult : IAsyncResult
{
public HttpContext contex;
public AsyncCallback cb;
public object extraData; public bool isCompleted = false; public MyAsyncResult(HttpContext contex, AsyncCallback cb, object extraData)
{
this.contex = contex;
this.cb = cb;
this.extraData = extraData;
} public void send(string resultStr)
{
this.contex.Response.Output.Write(resultStr);
} public object AsyncState
{
get { return null; }
} public System.Threading.WaitHandle AsyncWaitHandle
{
get { return null; }
} public bool CompletedSynchronously
{
//在网络连接或者流读取中,这里需要设置为True,否则前台是不能显示接收数据的。
get { return true; }
} public bool IsCompleted
{
get { return isCompleted; }
}
}
#endregion #region 异步执行对象
public static class myAsyncFunction
{
private static string resultResponse = string.Empty; //获取客户端数据
private static TcpListener tcpListener; private static MyAsyncResult asyncResult; //通知回传对象 // 把一个异步的请求对象传入以便于供操作
public static void Init(MyAsyncResult result,int port)
{
asyncResult = result;
if (tcpListener == null)
{
try
{
IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("192.168.0.100"),port);
tcpListener = new TcpListener(endPoint);
tcpListener.Start();
}
catch (System.Net.Sockets.SocketException ex)
{
tcpListener = null;
throw new Exception(ex.Message);
}
}
} //接收客户端数据并将数据打印到前台
public static void AcceptClients()
{
TcpClient client = tcpListener.AcceptTcpClient();
byte[] bufferResult = new byte[];
NetworkStream readStream = client.GetStream();
readStream.Read(bufferResult, , bufferResult.Length);
resultResponse = System.Text.Encoding.Default.GetString(bufferResult); Logger.WriteLog("Receiving TCP Client Message: " + resultResponse);
asyncResult.send(resultResponse);
}
}
#endregion #region 异步执行请求
public class AsyncSocketHandler : IHttpAsyncHandler
{
private static object obj = new object(); public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
lock (obj)
{
int port = Int32.Parse(context.Request.QueryString["port"].ToString());
MyAsyncResult asyncResult = new MyAsyncResult(context, cb, extraData); //实例
myAsyncFunction.Init(asyncResult, port); //接收所有传入的异步对象
myAsyncFunction.AcceptClients(); //处理所有传入的异步对象
asyncResult.isCompleted = true;
return asyncResult;
}
} public void EndProcessRequest(IAsyncResult result)
{
MyAsyncResult asyncResult = result as MyAsyncResult;
if (asyncResult != null)
{
asyncResult.send(string.Empty);
}
} public bool IsReusable
{
get { return false; }
} public void ProcessRequest(HttpContext context)
{ }
}
#endregion
}

对于WriteLog函数,我就不讲了,主要是用来写日志的。
对于MyAsyncResult类,主要是用来接收处理状态并返回,在EndProcessRequest(IAsyncResult result)中可以还原对象,然后做一些善后的工作,比如关闭数据库,清空缓存等等。

对于myAsyncFunction类,这是我们执行的主体,里面的AcceptClients函数是我们执行的核心。

对于AsyncSocketHandler类,它继承自异步handler:IHttpAsyncHandler,主要是用来进行异步处理的。

在下面的代码中:

        public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
lock (obj)
{
int port = Int32.Parse(context.Request.QueryString["port"].ToString());
MyAsyncResult asyncResult = new MyAsyncResult(context, cb, extraData); //实例
myAsyncFunction.Init(asyncResult, port); //接收所有传入的异步对象
myAsyncFunction.AcceptClients(); //处理所有传入的异步对象
asyncResult.isCompleted = true;
return asyncResult;
}
}

首先实例化MyAsyncResult对象,以便创建返回参数;然后初始化调用对象;初始化之后,开始调用我们的核心对象,也就是利用TCP接收Client的连接。最后返回执行对象。

  public void EndProcessRequest(IAsyncResult result)
{
MyAsyncResult asyncResult = result as MyAsyncResult;
if (asyncResult != null)
{
asyncResult.send(string.Empty);
}
}

当异步执行完毕之后,就会进入EndProcessRequest函数,这个函数主要通过还原MyAsyncResult对象,实现清理等操作,这里我就不再赘述。

那么如何调用呢?

调用其实很简单,通过Ajax请求这个异步Handler,然后利用其Success方法打印出获取的对象就可以了。 需要注意的是,在Success方法中,我们可以再调用Ajax请求来实现循环获取Client Sockets。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Server.aspx.cs" Inherits="SocketViaWeb.Server" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>TCP服务器端</title>
<style type="text/css">
body
{
font-size:12px;
}
</style>
<script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$("#btnListen").bind("click", function () {
//setInterval(TriggerAjax, 1000);
TriggerAjax();
});
}); var array = new Array(); var TriggerAjax = function () {
var port = $("#txtPort").val();
$.ajax({
type: "GET",
url: "AsyncSocketHandler.ashx?port=" + port,
dataType: "text",
success: function (result) {
if (result != "") {
var myDate = new Date();
var message = myDate.toLocaleString() + " : " + result;
if (!array.contains(result)) {
$("#msg").append(message).append("<br>");
}
}
TriggerAjax(); //循环调用
},
error: function (result) {
TriggerAjax(); //循环调用
}
});
} Array.prototype.contains = function (elem) {
for (var i = 0; i < this.length; i++) {
if (this[i] == elem) {
return true;
}
}
return false;
} </script>
</head>
<body>
<div style="height: 390px; width: 435px;float:left;border:1px solid #B7D6BF;">
<div style="height:30px;width:100%;float:left;background:url('images/navEx.gif') repeat-x;line-height:30px;text-align:center;"><strong>服务端接收数据</strong></div>
<div style="float:left;width:100%;height:310px;border-bottom:1px solid #B7D6BF; overflow-x:auto;" id="msg"></div>
<div style="float:left;width:100%;height:50px;text-align:right;line-height:50px;">
绑定的本机端口:<input id="txtPort" type="text" style="width:40px;border:none;border-bottom:1px solid black;" value="10004" />
<input id="btnListen" type="button" value="监听" style="border:none;background:url('images/btn.gif') no-repeat;width:50px;height:20px;color:White;" />
<input id="btnStop" type="button" value="停止" style="border:none;background:url('images/btn.gif') no-repeat;width:50px;height:20px;color:White;" onclick="return btnStop_onclick()" />
</div>
</div>
</body>
</html>

实现效果

最后看看我们实现的效果吧:

源码下载

点击这里下载源码

由于源码中有SignalR的示例,附件过大,我已经删除了相关的Signr附件,编译的时候,请首先运行 Install-Package Microsoft.AspNet.SignalR -version 1.0

来获取相关的版本。我百度网盘放了全版本的:http://pan.baidu.com/s/15SDGG

解决方案中的SocketViaWeb项目下的Server.aspx 为服务端,Client.aspx为客户端。

基于IHttpAsyncHandler的TCP收发器的更多相关文章

  1. 基于IHttpAsyncHandler的UDP收发器

    很难把UDP和Asp.net扯到一起,但是由于最近项目中需要通过网页发送控制指令到中间件,再由中间件发送到下位机的需求.所以就研究了一下是否可以通过asp.net操控UDP Socket实现数据的收发 ...

  2. 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载

    一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...

  3. 用C#基于WCF创建TCP的Service供Client端调用

    本文将详细讲解用C#基于WCF创建TCP的Service供Client端调用的详细过程 1):首先创建一个Windows Service的工程 2):生成的代码工程结构如下所示 3):我们将Servi ...

  4. 基于.NET Socket Tcp的发布-订阅框架

    基于.NET Socket Tcp的发布-订阅框架 一.分布式消息总线 在很多MIS项目之中都有这样的需求,需要一个及时.高效的的通知机制,即比如当使用者A完成了任务X,就需要立即告知使用者B任务X已 ...

  5. 基于“泵”的TCP通讯(接上篇)

    基于“泵”的TCP通讯(接上篇) 上一篇博客中说了基于“泵”的UDP通讯,附上了一个Demo,模拟飞鸽传书的功能,功能不太完善,主要是为了说明“泵”在编程中的应用.本篇文章我再附上一个关于TCP通讯的 ...

  6. 基于libnids的TCP数据流的还原(多线程实现) .

    我们知道,libnids本身可以实现TCP数据流的重组,但是如果一个TCP流数据量比较大的时候,就会分成好多个TCP报文段,这些报文段在网络中的传播可能是乱序的,利用libnids可以帮助我们按顺序接 ...

  7. 【Java TCP/IP Socket】基于NIO的TCP通信(含代码)

    NIO主要原理及使用 NIO采取通道(Channel)和缓冲区(Buffer)来传输和保存数据,它是非阻塞式的I/O,即在等待连接.读写数据(这些都是在一线程以客户端的程序中会阻塞线程的操作)的时候, ...

  8. 基于libuv的TCP设计(三)

      基于libuv的TCP设计(一) 基于libuv的TCP设计(二)   一.第二版本的libuv_tcp已经基本可以使用.不会出错与崩溃现象,支持几百路客户端同时连接.可是有一缺陷就占用CPU非常 ...

  9. 基于Linux的TCP网络聊天室

    1.实验项目名称:基于Linux的TCP网络聊天室 2.实验目的:通过TCP完成多用户群聊和私聊功能. 3.实验过程: 通过socket建立用户连接并传送用户输入的信息,分别来写客户端和服务器端,利用 ...

随机推荐

  1. 【转】IOS开发中图片资源使用png还是jpg格式

    对于iOS本地应用程序来说最简单的答案就是始终使用PNG,除非你有非常非常好的理由不用它. 当iOS应用构建的时候,Xcode会通过一种方式优化.png文件而不会优化其它文件格式.它优化得相当的好 他 ...

  2. Android中TextView中的文字设置为不同颜色

    questionDesTextView=(TextView)findViewById(R.id.question_des); SpannableStringBuilder builder = new ...

  3. iOS开发 -- 为本地文件添加自定义属性的工具类

    前言:实际开发,我们可能会有这样的需求,就是为文件添加自定义的属性,或者是可以将文件的相关信息添加进该文件的属性中,这样可以以备下次读取利用. 那么本文就是要介绍"拓展文件属性的工具类&qu ...

  4. 介绍一种css水平垂直居中的方法(非常好用!)

    这次介绍一下一个水平垂直居中的css方法,这个方法可以说是百试百灵,废话不多说,直接附上代码: html,body{ width:100%; height:100%; } 你需要居中的元素{ posi ...

  5. 每日Scrum--No.6

    Yesterday:组内各种乱八七糟的问题,还有自己的效率问题 Today:进行小范围的测试实验 Problem:在显示各景点构成的邻接矩阵的时候,第一次编译未出现任何错误的提示,但是在程序运行时,无 ...

  6. Effective Java 44 Write doc comments for all exposed API elements

    Principle You must precede every exported class, interface, constructor, method, and field declarati ...

  7. 读书笔记——Windows环境下32位汇编语言程序设计(6)使用浮点指令进行64位除法

    罗云彬 典藏版Page192,mark下. 这段代码看不懂,手册上根本没有fdivr不带操作数的指令. .data dqTickCounter1 dq ? dqTickCounter2 dq ? dq ...

  8. 读书笔记——Windows核心编程(8)Interlocked单向链式栈

    SLists使用了无锁算法来保证原子同步,以提升系统性能,避免了诸如优先级挂和互锁的问题. 注意:所有的链表项必须对齐到MEMORY_ALLOCATION_ALIGNMENT.否则会出现奇葩的错误. ...

  9. 烂泥:通过vsphere给esxi添加本地硬盘

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 公司ESXi服务器的硬盘空间不够使用,现在新加了一块硬盘在ESxi服务器上.在服务器上添加完硬盘后,在Vsphere上是看不到新加硬盘的. 下面我们来通 ...

  10. poj 3237 Tree [LCA] (树链剖分)

    poj 3237 tree inline : 1. inline 定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换,(像宏一样展开),没有了调用的开销,效率也很高. 2. 很明显,类 ...