我正试图在 C# 中制作一个 stunnel 克隆,只是为了好玩。主循环是这样的(暂时忽略 catch-everything-and-do-nothing try-catches)
ServicePointManager.ServerCertificateValidationCallback = Validator;
TcpListener a = new TcpListener (9999);
a.Start ();
while (true) {
Console.Error.WriteLine ("Spinning...");
try {
TcpClient remote = new TcpClient ("XXX.XX.XXX.XXX", 2376);
SslStream ssl = new SslStream(remote.GetStream(), false, new RemoteCertificateValidationCallback(Validator));
ssl.AuthenticateAsClient("mirai.ca");
TcpClient user = a.AcceptTcpClient ();
new Thread (new ThreadStart(() => {
Thread.CurrentThread.IsBackground = true;
try{
forward(user.GetStream(), ssl); //forward is a blocking function I wrote
}catch{}
})).Start ();
} catch {
Thread.Sleep (1000);
}
}
我发现,如果我在等待用户之前进行远程 SSL 连接,就像我所做的那样,那么当用户连接时,SSL 已经设置好(这是用于隧道 HTTP,因此延迟非常重要)。另一方面,我的服务器会关闭长期不活动的连接,因此如果在 5 分钟内没有新连接发生,一切都会锁定。
什么是最好的方法?
另外,我观察到我的程序生成了多达 200 个线程,这当然意味着上下文切换的开销相当大,有时甚至会导致整个过程阻塞几秒钟,即使只有一个用户通过该程序进行隧道传输也是如此。我的前向函数在要点上是这样的
new Thread(new ThreadStart(()=>in.CopyTo(out))).Start();
out.CopyTo(in);
当然有很多错误处理来防止断开的连接永远挂起。不过,这似乎停滞不前。我不知道如何使用像 BeginRead 这样的异步方法,根据谷歌的说法,这应该有所帮助。
最佳答案
对于任何类型的代理服务器(包括 stunnel 克隆),在接受前端连接后打开后端连接显然更容易实现。
如果您预先打开后端连接以预期接收前端连接,您当然可以节省 RTT(这有利于延迟),但您必须处理您暗示的问题:后端将关闭空闲连接。在您收到前端连接的任何时候,您都面临这样的风险,即您将要与此前端连接相关联且已在一段时间前打开的后端连接太旧而无法使用,并且可能会被后端关闭。您将必须管理一个当前打开的后端连接池,并在它们空闲时间过长时定期关闭和刷新它们。甚至存在竞争条件,如果后端认为连接空闲时间过长并决定关闭它,但代理服务器同时接收到新的前端连接,前端可能会决定通过后端连接转发请求 < em="">while 后端正在关闭此连接。这意味着您必须能够先验地知道后端连接在后端关闭它们之前可以空闲多长时间(您必须知道在后端配置的超时值设置为多少)以便您可以放弃它们在后端决定它们太旧之前。
总而言之:与仅按需打开后端连接相比,预打开后端连接将节省 RTT,但需要大量工作,包括微妙的连接池管理,很难实现无错误。由您来判断额外的复杂性是否值得。
顺便说一句,关于您关于处理数百个同时连接的评论,我建议将这样一个 I/O 绑定(bind)程序实现为基于事件循环而不是基于线程的代理服务器。基本上,您在单个线程中使用非阻塞套接字和处理事件(例如“这个套接字有新数据等待转发到另一端”)而不是为每个连接生成一个线程(这在线程创建中都会变得昂贵和上下文切换)。为了将这种基于事件的模型扩展到多个 CPU 内核,您可以启动少量进程的并行线程(每个 CPU 内核或多或少一个线程),每个进程处理数百(或数千)个并发连接。
关于c# - 在 SSL 包装器的本地用户连接之后或之前建立远程 SSL 连接?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17396244/
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我正在使用Sequel构建一个愿望list系统。我有一个wishlists和itemstable和一个items_wishlists连接表(该名称是续集选择的名称)。items_wishlists表还有一个用于facebookid的额外列(因此我可以存储opengraph操作),这是一个NOTNULL列。我还有Wishlist和Item具有续集many_to_many关联的模型已建立。Wishlist类也有:selectmany_to_many关联的选项设置为select:[:items.*,:items_wishlists__facebook_action_id].有没有一种方法可以
我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我使用的是Firefox版本36.0.1和Selenium-Webdrivergem版本2.45.0。我能够创建Firefox实例,但无法使用脚本继续进行进一步的操作无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055)错误。有人能帮帮我吗? 最佳答案 我遇到了同样的问题。降级到firefoxv33后一切正常。您可以找到旧版本here 关于ruby-无法在60秒内获得稳定的Firefox连接(127.0.0.1:7055),我们在StackOverflow上找到一个类
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
如何在ruby中调用C#dll? 最佳答案 我能想到几种可能性:为您的DLL编写(或找人编写)一个COM包装器,如果它还没有,则使用Ruby的WIN32OLE库来调用它;看看RubyCLR,其中一位作者是JohnLam,他继续在Microsoft从事IronRuby方面的工作。(估计不会再维护了,可能不支持.Net2.0以上的版本);正如其他地方已经提到的,看看使用IronRuby,如果这是您的技术选择。有一个主题是here.请注意,最后一篇文章实际上来自JohnLam(看起来像是2009年3月),他似乎很自在地断言RubyCL
我正在尝试在Ruby中复制Convert.ToBase64String()行为。这是我的C#代码:varsha1=newSHA1CryptoServiceProvider();varpasswordBytes=Encoding.UTF8.GetBytes("password");varpasswordHash=sha1.ComputeHash(passwordBytes);returnConvert.ToBase64String(passwordHash);//returns"W6ph5Mm5Pz8GgiULbPgzG37mj9g="当我在Ruby中尝试同样的事情时,我得到了相同sha
只是想确保我理解了事情。据我目前收集到的信息,Cucumber只是一个“包装器”,或者是一种通过将事物分类为功能和步骤来组织测试的好方法,其中实际的单元测试处于步骤阶段。它允许您根据事物的工作方式组织您的测试。对吗? 最佳答案 有点。它是一种组织测试的方式,但不仅如此。它的行为就像最初的Rails集成测试一样,但更易于使用。这里最大的好处是您的session在整个Scenario中保持透明。关于Cucumber的另一件事是您(应该)从使用您的代码的浏览器或客户端的角度进行测试。如果您愿意,您可以使用步骤来构建对象和设置状态,但通常您
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。