内存中的 P2P 聊天






4.71/5 (6投票s)
本文描述了一个低资源消耗的 P2P 聊天系统的设计。
引言
如果有一个可以提供 100% 隐私的聊天门户怎么样? 是的,实际上这是不可能的,但至少我们能不能设法不在服务器中存储用户的个人聊天消息?
本文试图设计这样一个聊天系统。 我使用了所有想到的语言功能,所以请记住,还有更好和其他合适的选择。
解决方案设计
需求:一个非常简单的聊天程序,允许个人相互聊天,同时不将他们的个人消息保存在数据库中。
解决方案:将消息临时保存在内存对象中,直到它传递给其他用户或直到特定的时间延迟到期,例如 2 分钟。
技术详情
这里,使用静态 List<> 来临时存储消息。 浏览器将以定义的间隔(例如:3 秒)异步地从该对象中提取消息并在浏览器中显示。 一旦消息从对象中读取,这些消息将立即被删除。 列表中孤立的消息也会以定义的间隔删除,以便变量内存消耗保持在最低水平。
示例应用程序中使用的技术和特性有
- HTML5 和 CSS
- jQuery - 版本:1.10.2
- 基于 .NET Framework 4.5 的带有 C# 的 ASP.NET
在此示例中,没有使用任何复杂的像 WebAPI 这样的技术,因此该功能可以很容易地以任何语言实现。
P2P 聊天涉及两个人之间的聊天。 让我把他们称为你和一个陌生人。
使用代码
客户端代码
以下是用 jQuery 编写的 PUSH 和 PULL 聊天消息处理程序。
$(function () {
$("#t").focus();
$("#s").click(function () { // PUSH
if ($("#t").val().trim() != "") {
u1 = $("#u1").val();
u2 = $("#u2").val();
$.ajax({
url: "e.aspx",
type: "POST",
data: { c: "p", u1: u1, u2: u2, t: escape($("#t").val()) }
});
// Pushes new message along with user1 (you) and user2 (stranger)'s usernames
}
$("#t").val("").focus();
});
});
function pull() { // PULL - check server to see if any new messages available
u1 = $("#u1").val();
u2 = $("#u2").val();
if (u1.trim() == "" || u2.trim() == "") return;
$.ajax({
url: "e.aspx",
type: "POST",
data: { c: "g", u1: u1, u2:u2 }
})
.done(function (d) {
$.each($.parseJSON(d), function (k, v) {
var cls = "cu";
var me = v.wu;
if (v.wu == u1) {
cls = "cu1";
}
$("#c").html($("#c").html() + " <span class='" + cls + "'>" + me + ": " + v.msg + "</span><br />");
$("#c").scrollTop(1000000);
});
});
}
并且,pull() 每 X 秒执行一次,例如
setInterval(pull, 1000);
服务器端代码
以下代码显示了如何处理从浏览器触发的 PULL 和 PUSH 命令。
首先,聊天消息记录看起来像这样
public class REC
{
public string user1 { get; set; } // your nick
public string user2 { get; set; } // stranger's nick
public string msg { get; set; } // chat message
public string wu { get; set; } // prointer to which user's message
public DateTime dt { get; set; } // datetime details of message for the use of removing orphen messages
}
以下是我们内存存储对象的声明
public static List<REC> data;
接下来是 PUSH 和 PULL 处理程序。
string ret = null;
u1 = Request["u1"].ToString().ToLower();
u2 = Request["u2"].ToString().ToLower();
switch (Request["c"])
{
case "p": // PUSH
var t = Uri.UnescapeDataString(Request["t"].ToString());
DateTime dt = DateTime.UtcNow;
data.Add(new REC(u1, u2, t, u1, dt));
data.Add(new REC(u2, u1, t, u1, dt));
ret = "1";
break;
case "g": // PULL
var z = data.Where(x => (x.user1.Contains(u1)));
ret = new JavaScriptSerializer().Serialize(z);
data.RemoveAll(x => (x.user1.Contains(u1)));
data.RemoveAll(x => (DateTime.UtcNow - x.dt).TotalMinutes > 2); // remove orphen messages after 2 mins
break;
}
Response.Write(ret);
PUSH:将传入的聊天消息添加到数据中。 您可以看到,插入了两条记录 - 一条针对你,另一条针对陌生人。
PULL:检索特定用户的聊天消息。 检索后,立即将其从数据对象中删除。 第二个 RemoveAll() lamda 删除任何性质为孤立的消息。 由于网络问题或浏览器关闭,可能存在未交付的未使用消息。
注意事项
- 静态 List<> 是我首先想到的,但请注意,不建议使用静态方法。 如果应用程序域被回收,它可能会丢失值,它不适用于负载均衡的环境,它的存储能力取决于你的机器拥有多少内存等等。 请探索其他内存存储方式
- 除非进行修改以提高可扩展性,否则此示例应用程序不可扩展
- 此设计不考虑群聊。
- 如果第三个人使用第一个或第二个用户的昵称之一,系统将表现得很奇怪
- 示例代码中没有适当的异常处理
- 编码最佳实践几乎没有遵循
演示
我在此处托管了一个示例演示。 但我不知道它将可用多久,所以如果链接不起作用,请不要抱怨。