关于 completion ports

netsbull 2002-10-01 04:16:39
在一个网络服务程序中,本来想为每一个来自于client端的请求开一组线程来管理,包括数据传送等功能,但是如果同时连接过多,比如有2000个线程,显然不是个有效率的方法,于是想到用completion ports 来调度,在服务器上开n个固定的线程组,为来自于n个客户的请求服务,有类似经验的朋友欢迎指教。
...全文
37 24 打赏 收藏 转发到动态 举报
写回复
用AI写文章
24 条回复
切换为时间正序
请发表友善的回复…
发表回复
netsbull 2002-10-15
  • 打赏
  • 举报
回复
id是用来标志客户身份的。具体怎么来处理一些意外要看具体的实施。比如当客户提供一个已经使用过得id的处理,可以确认当前存在的连接已经出现意外才关闭,这样安全一些但也多耗点时间,或者直接中断再次连接。怎么选择也看应用的环境的安全程度。
在我的系统中,建立连接不发送id会被服务强制中断,只用确认确实是本系统的合法客户,服务端才会给他分配资源,这个过程我单独有一个线程来负责监控。另外也有一些额外的东西可以参考,比如对同一个ip短时多次的连接尝试等等。
还有,ports中得资源也不是无限制增长的,可以设置一个门槛,无论如何保证不会当掉吧 :)
everwindforce 2002-10-15
  • 打赏
  • 举报
回复
to netsbull(网牛)
多谢老兄耐心指教,.

"客户在重新连接时要提交这个id"这个我不太理解,好像是应用层地问题吧.
是不是当客户提供了一个已经使用过的id后,系统会自动关闭他先前的连接?
这个id是用来标示客户的身分吗?系统又如何生成一个新的id?

从tcp的角度考虑,客户可以通过半开放(是指一方的应用程序以结束,而另一方不知道,他和半关闭是不同的)耗尽服务器的端口资源(或者说是线程资源,因为线程数是有限的),比如在建立一个连接后不发送id,而继续建立新的连接直到耗尽服务方的
"进程"资源,对于这种情况有没有什么好的解决办法?

//btw
接受连接的过程
do {
-Wait for a previous AcceptEx to complete
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Create a new socket and associate it with the completion port
-Allocate context structure etc.
-Post an AcceptEx request.
}while(TRUE);

huangbeyond 2002-10-14
  • 打赏
  • 举报
回复
netsbull(网牛)的考虑已经比较周到了。
其实,保证服务端的用户安全机制,也基本就如此了。

但是,按照netsbull(网牛)说的“我的客户端都是"自己人",没有恶意倾向”,那么,如果是服务端忽然死去,客户端就也需要记时了。也就是说,C/S的表明“我还活着”,应该是双向的!

几位觉得如何?
netsbull 2002-10-14
  • 打赏
  • 举报
回复
我的客户端都是"自己人",没有恶意倾向 :)

不过风力兄这个问题是有意思。
对于每一个客户端,只要与服务端建立过连接,服务端都为他分配一个id,根据id分配资源,在任务完成后释放,或者空闲若干时间后释放。这个id 也以某种隐蔽形式保存在客户端,客户在重新连接时要提交这个id,这样在短时多次恶意/善意连接时不会影响到其他资源。如果他有意延长时间,服务端也早已释放掉他的先前的id,同样也不会占用多余的资源。为避免无恶意延时而造成的重复工作,如数据传输,可以每一个id建立一个历史纪录,当一个客户在超时后继续未毕的工作,服务可以根据历史纪录把任务转交给另一个空闲的id,并整理id历史纪录集。即使为每个id保持一千个历史,也不是什么负担。
everwindforce 2002-10-14
  • 打赏
  • 举报
回复
还有就是让客户端不断告诉服务器,我还活着,服务端在收不到这个信息一段时间后就认为客户已经死亡,中止任务,关闭连接。

有一个问题,由于服务进程是有限的,一个恶意客户可以通过不断的非正常关闭连接,
导致所有的服务都进入锁定状态,从而达到拒绝服务的目的.

(如果服务数量不限,计时器又长,就变成了双方拼资源....)
这和楼主的问题无关,不过很有趣.
huangbeyond 2002-10-14
  • 打赏
  • 举报
回复
在"连接"判断这个问题上,
看来 netsbull(网牛) 说的,和我已经做的,恰好相同,呵呵

其实,IO完成端口也还是比较简单的,关键是在与实现功能.
sqsq999 2002-10-14
  • 打赏
  • 举报
回复
我怎么看不懂呀?混了!!!
netsbull 2002-10-14
  • 打赏
  • 举报
回复
这个倒是未必,
你在服务器上为每个客户都分配一个结构,分配一个index(在任务完成后释放,或者空闲若干时间后释放),而socket client和index是关联的,当一个客户任务没有完成而重新启动,再次连接时,根据index,可以做出判断而进行处理。
还有就是让客户端不断告诉服务器,我还活着,服务端在收不到这个信息一段时间后就认为客户已经死亡,中止任务,关闭连接。
还要说明一下,我是专门开了一个线程来处理连接的问题的,这个线程不在ports池子里面
huangbeyond 2002-10-13
  • 打赏
  • 举报
回复
TO: netsbull(网牛)

我最近做的也是IO CompletePort。所以,想和你交流些细节。

我觉得,用这个IO模型,别的好说,就是处理“非正常关闭”时比较麻烦。你是如何处理的?分别对“雅致”“非雅致”“对方忽然重启”。

我目前采用的方案是:记时器的思路。
netsbull 2002-10-13
  • 打赏
  • 举报
回复
to mess:
相当于:one thread per client 模式
不过对于很大数量的连接,如果有1000个客户,开一千个线程显然不是个好主意,所以用completion ports,我的程序已经做完了,还没做负载测试,但感觉确实比one thread per client 更好,特别是资源耗用。
huangbeyond 2002-10-13
  • 打赏
  • 举报
回复
不过也有一个副作用:
假如客户“重启”之后,再也不连接上来了,服务器也就一直在傻等了。。。。。不好不好,还是使用记时器算了。。。。。。。
huangbeyond 2002-10-13
  • 打赏
  • 举报
回复
不错,就如常everwindforce(windforce) 所说

如果是n个用户的“非正常关闭”模式是“忽然重启”,我该如何处理呢?因为这种情况,在服务器是根本得不到对方已经不存在的任何信息的。而且,就是“忽然重启”是最苛刻的;netsbull(网牛) 做的处理,都是在“服务器能够知道对方关闭”的前提下的。

其实,一个SOCKET程序被用户关闭(即:进程终止),在WINSOCK-DLL层是经过资源释放的,所以连接的对方是肯定知道的。就是“重启”这种情况,是没有任何处理的。

不过, everwindforce(windforce) 倒是启发了我一个思路:强制规定一个端口就只允许一个IP地址进行连接,如果有多的进来,就肯定是上一次是“非法关闭”,哈哈,这样就解决很多问题啦!!
everwindforce 2002-10-13
  • 打赏
  • 举报
回复
非正常关闭可能会导致服务器端口锁定,在一定时间内无法建立tcp连接.
有没有试过同时非正常关闭n个客户端?
netsbull 2002-10-13
  • 打赏
  • 举报
回复
对于非正常关闭,我做了如下处理:
1 服务端有任务列表,记录当前的任务,客户在完成任务并检查通过后,服务器才根据客户端的反馈结束任务。
2 我的服务和客户端都加上了自动重新连接功能,当客户再一次连接上服务器时,首先检查任务表,完成未尽的任务。
3 对于数据传输,应用断点续传
mess 2002-10-10
  • 打赏
  • 举报
回复
实在不明白你的意思,“本来想为每一个来自于client端的请求开一组线程来管理”“在服务器上开n个固定的线程组,为来自于n个客户的请求服务”
xwmhn 2002-10-10
  • 打赏
  • 举报
回复
一旦服务器与客户端建立了连接之后,就可以通过 Internet 传输数据和文件。但是在WinSock中存在两种传输模式“阻塞”和“非阻塞”的概念。
一般都采用非阻塞方式。在客户端,如果把 ClientType特性设置为ctNonBlocking,表示采用非阻塞方式进行连接。当服务器端 Socket试图进行读/写操作的时候,客户端 Socket就会得到通知,即OnRead或者OnWrite事件。
对于服务器端Socket来说,如果把ServerType特性设置为 StNonBlocking,表示采取非阻塞方式进行连接。当客户端 Socket试图进行读/写的时候,服务器端Socket就会得到通知,即OnClientRead或者OnClientWrite事件。
与非阻塞方式不同的是,在阻塞方式下没有诸如OnRead或者OnWrite等异步事件。Socket必须主动去读或者写数据。在读写操作完成之前,其他代码都无法执行,成为了纯粹的独占使用方式,整个应用程序将处于等待状态,大大降低应用程序的性能。
对于客户端Socket来说,如果把 ClientType特性设置为ctBlocking,表示采取阻塞方式进行连接,为了尽可能的减少阻塞方式的负面影响,可以把所有涉及到读写的操作放在一个单独的线程中,这样可以使其他的线程可以继续得到执行。
对于服务器端 Socket来说,如果把ServerType设置为stThreadBlocking,表示采取阻塞方式进行连接。Delphi 中将为每一个阻塞方式的连接自动分配一个新的线程,这样即使一个客户正在进行读写操作,其他的客户也不必等待。
http://geocom.hhcc.net.cn/magz/wk0202/7.htm
louifox 2002-10-10
  • 打赏
  • 举报
回复
哪里有相关的资料可以学习一下?
netsbull 2002-10-09
  • 打赏
  • 举报
回复
哈哈,已经做完了,当作散分吧,前20个有分
netsbull 2002-10-03
  • 打赏
  • 举报
回复
哈哈,不会让我把贴子删掉吧
wenyuanfeng 2002-10-02
  • 打赏
  • 举报
回复
没高国
加载更多回复(4)

4,356

社区成员

发帖
与我相关
我的任务
社区描述
通信技术相关讨论
社区管理员
  • 网络通信
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧