上一篇文章中,我们提到使用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常用的系统文件目录介绍

    iOS常用目录整理说明是本文要介绍的内容,虽然不同API全面,也算是在编程中常用到的存放目录,所以是必备文档,不多说,来看详细内容讲解. 1.[/Applications] 常用软件的安装目录 内建软 ...

  2. jquery miniui , 普加甘特图,流程管理

    http://www.miniui.com/docs/quickstart/index.html 普加 甘特图 流程管理 http://www.plusgantt.com/project/demo/P ...

  3. Eclipse Svn 取消某些文件或文件夹的版本控制

    SVN提交时,我们有时候需要将一些文件忽略掉,例如:maven项目中的target文件夹,可以将这些文件或文件夹设置成ignore来忽略这些文件或文件夹 1. 将文件夹或文件从Eclipse中删除.记 ...

  4. 从1.5k到18k, 一个程序员的5年成长之路

    昨天收到了心仪企业的口头offer, 回首当初什么都不会开始学编程, 到现在恰好五年. 整天在社区晃悠, 看了不少的总结, 在这个时间点, 我也写一份自己的总结吧. 我一直在社区分享, 所以, 这篇总 ...

  5. android之apk反编译

    今天就来详细的讲一讲apk的反编译过程,之前自己一直没彻底搞清楚. 一.准备工作 反编译首先要准备三个工具.这三个工具都是可以百度下载的.就是下图所示的三个工具. 这三个工具是有各自作用的: (1)a ...

  6. ASP.NET Session的共享

    注: 在ashx文件中使用Session 首先添加引用 using System.Web.SessionState; 实现接口 public class XXXX: IHttpHandler ==&g ...

  7. LightSpeed 的Left Join Bug解决方案

    在使用LightSpeed对数据库进行Left Join或Right Join操作时,经常会报一些匪夷所思的异常. 明明表没有问题,表面上语句写的也没问题,可总是报错.看分析器里的SQL就知道了,是L ...

  8. 处理 InterruptedException——Brian Goetz

    本文转自Brian Goetz大师在IBM的developerWorks中发布的文章: 中文地址:http://www.ibm.com/developerworks/cn/java/j-jtp0523 ...

  9. hdu 4856 Tunnels (记忆化搜索)

    Tunnels Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su ...

  10. android去掉顶部标题栏

    在清单文件(manifest.xml)里面实现 <application> <activity android:name="cn.ui.activity.UserRegAc ...