惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
O
OpenAI News
W
WeLiveSecurity
Hacker News: Ask HN
Hacker News: Ask HN
Hacker News - Newest:
Hacker News - Newest: "LLM"
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
T
Troy Hunt's Blog
L
LINUX DO - 最新话题
SecWiki News
SecWiki News
Schneier on Security
Schneier on Security
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
N
News and Events Feed by Topic
TaoSecurity Blog
TaoSecurity Blog
H
Heimdal Security Blog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
P
Palo Alto Networks Blog
Project Zero
Project Zero
Attack and Defense Labs
Attack and Defense Labs
C
CXSECURITY Database RSS Feed - CXSecurity.com
T
Tor Project blog
Scott Helme
Scott Helme
T
Threat Research - Cisco Blogs
Simon Willison's Weblog
Simon Willison's Weblog
Spread Privacy
Spread Privacy
Cisco Talos Blog
Cisco Talos Blog
T
Threatpost
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
The Last Watchdog
The Last Watchdog
Google DeepMind News
Google DeepMind News
P
Privacy & Cybersecurity Law Blog
Know Your Adversary
Know Your Adversary
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
L
Lohrmann on Cybersecurity
Cloudbric
Cloudbric
I
Intezer
The Hacker News
The Hacker News
L
LINUX DO - 热门话题
AI
AI
B
Blog
S
Securelist
P
Proofpoint News Feed
量子位
Jina AI
Jina AI
V2EX - 技术
V2EX - 技术
T
The Exploit Database - CXSecurity.com
酷 壳 – CoolShell
酷 壳 – CoolShell
Recent Commits to openclaw:main
Recent Commits to openclaw:main
C
CERT Recently Published Vulnerability Notes
J
Java Code Geeks
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻

博客园 - 上午的绝缘杯

金斗云提醒用法说明 金斗云提醒软件的原理 webbrowser使用心得 向大家推荐一个谷歌浏览器笑话插件:一日一笑 企业知识管理专家:KMaster知识管理平台简介 KMaster知识管理平台功能简介 知识库如何跟其他业务系统结合 知识管理系统中的知识门户 KMaster知识库的特色功能 当前知识管理系统的焦点问题以及我的一些解决办法 企业级知识库系统KMaster推荐 ie6下的location.href错误 - 上午的绝缘杯 - 博客园 jQuery高亮插件 使用 .NET 实现 Ajax 长连接 (Part 2 - Mutex Wait & Signal) 利用Jquery实现http长连接(LongPoll) - 上午的绝缘杯 - 博客园 Comet:基于 HTTP 长连接的“服务器推”技术 非常好的进度条生成网站 火车票刷票器 学习lucene.net的好网站(不断添加)
使用 .NET 实现 Ajax 长连接 (Part 1 - Comet Web Service)
上午的绝缘杯 · 2010-02-05 · via 博客园 - 上午的绝缘杯

Ajax的长连接,或者有些人所说的Comet,就是指以XMLHttpRequest的方式连接服务器,连接后服务器并非即时写入相应并返回。服务器会保持连接并等待一个需要通知客户端的事件,该事件发生后马上将数据写入响应,这时候客户端就以相当“实时”的方式接收到事件通知。具体的通信模型,请参考这篇文章:《Comet:基于 HTTP 长连接的“服务器推”技术》,里面已经说得非常详细了,我就不再复述了。

我们接着开始讨论如何使用.NET实现这个模型。首先我们能想到的是,我们需要一个Web Service,可以是ASP.NET Web Service,也可以是WCF Web Service,ASP.NET AJAX Library两者都支持。在这里,为了简单起见,就选择大家更熟悉的ASP.NET Web Service举例。然后,我们写下以下两个函数签名:

public void Send(Message message);
public Message Wait();

其中,Send函数用来发送一个Message对象,而Wait函数用来等待一个Message对象。然后,让我们来讨论一些细节问题。

无事件导致超时

首先,长期保持连接时不行的。对于服务器和客户端来说,这不是个问题,但我们永远都要记住中间可能存在各式各样配置怪异的网关和代理,它们上面可能有各式各样的超时规则,因此Comet最好设计为定期重连。一般情况下,如果30秒没有任何事件发生,服务器端就应该通知客户端确实没有事件发生,结束掉本次请求,然后重新开始一次新的请求以便继续等待。

那么上述函数签名可否用来返回一个无事件的消息呢?这是显然可以的,我们可以选择返回null表示无事件,或者返回一个EmptyMessage常量,这视乎我们使用class还是struct来定义Message。(甚至,我们还可以做一个名为NoMessageMessage的Message派生类来做这个事情。)

定义发送目标

上述函数签名确实能用来收发消息,但是没指名发给谁。可能有人会说,发送给谁可以在Message类里面通过一个属性来定义啊。但是Wait()方法没有说明接受方是谁,服务器端依然不知道哪些消息应该让你接收。

因此,我们引入Channel的概念,Channel使用其名称来标识,相同名称的就必然是同一个Channel。在发送与接受时,通过名称指定要发送到哪个Channel,这样问题就解决了。此时,函数签名修改如下:

public void Send(string channelName, Message message);
public Message Wait(string channelName);

可靠的消息队列

想象一个可能发生的情况,服务器端向你发送一个消息,你没有成功接收,但是服务器端认为发送了就成功了,消息从队列删除了,然后这个消息就永久丢失掉了。可能有人会强调TCP多么可靠,服务器端发送的消息如果在TCP的层面发生问题了,肯定会引发Socket级别的Exception,这个Exception冒泡上来,服务器端就能截获,从而得知发送失败,然后先不删除队首消息。可是别忘了,中间是可能存在代理的,如果代理成功把消息收回去了,可是代理发送到客户端这一步失败了,服务器端就不一定会发生异常了。

因此,我们需要制定一种策略,来确保下行消息总能发送到客户端。在这里,我们选择了引入逐个ACK的机制,来确认消息的接收。也就是说,服务器端发送给客户端的消息带有一个序号,在客户端收到消息后就将该序号发回给服务器端,已确认它受到了该消息。这时候,函数签名更改如下:

public int Send(string channelName, Message message);
public Message Wait(string channelName, int sequence);

我们使用Wait()接收到的Message中,应该有一个Sequence的属性,标记它的序号。然后,再我们执行下一次Wait()时就将该序号加1的值通过sequence参数传递回去,让服务器知道我们期望下一条消息的编号是这个。例如我们收到Message,其Sequence属性为836,那么下一次调用Wait()的时候就传给服务器837。服务器端此时应该保留了编号为836的Message在对首,如果客户端继续请求836号消息,证明它上次没收到,这次仍然发送836号消息给它;如果客户端请求837号消息,证明它成功收到836号消息的,这次就发送837号消息给它。

如果都不是,那该怎么办?那意味着,这是一个错误的请求,甚至可能是攻击请求,因为正常情况下不应该出现这样的请求的,服务器端可以考虑抛个无关紧要的Exception(不要告诉攻击者你知道他在攻击了),甚至直接给个400 (bad request)的响应代号。

与Wait()类似的,Send()也可以加入ACK机制,只需要将返回类型从void改为int就可以了,这个值就专门用于传递消息编号,实现方式和Wait()是一样的,不过Send()是由客户端保存待发送消息的队列。

小结

到此为止。我们的Web Service就写好了。这就写好了?只有签名没有函数体?是的,复杂的工作留给model去做,Web Service在这里只是相当于一个view,用于将model的接口暴露出来。

posted on 2010-02-05 15:15  上午的绝缘杯  阅读(1012)  评论()    收藏  举报