美高梅娱乐4858.comAlibaba公告《2016多少风控年报》,网络业务鲜绿产业链分析

一体化版PDF《二〇一五数码风控年报》下载,请点击那里

姣好端口与高质量服务器程序开发


Email:kruglinski_at_gmail_dot_com
Blog:kruglinski.blogchina.com

第三章  二〇一四年数据风控回想

二零一五年电商、网游及网络经济神速发展,各类创业公司由此活动方式的补贴来获取用户、作育用户的开销习惯,但高额的补贴、促销同时也催生了“石黄产业链”,由“黄牛”、“打码手”、“羊毛党”组成的协会已经形成了专业化团队,从业人数过百万,他们内部有着明显分工,严重破坏了商业活动的目标,侵夺了巨额的位移资产,使不奇怪的用户分享不到移动的一贯利益,那些作为距离欺诈唯有一步之遥。

二〇一六年的互连网不合规也变得越来越专业化、规模化、协会化,国内外各行业出现新闻走漏引起的最首要安全事故20余起,有账户风险的用户量超越十亿。

互连网在改变古板商业的同时,同样也使以哄骗、偷窃等形式来博取利益的黑心行为照旧不合法发生了根本性转变;利用网络分布式消息方可一起共享的能力,让“黑产”参加方之间可以实时、多方、多角度地相互关系。那种网状、协同格局是争执于传统犯罪链最大的优势,除了正规的“黑客”、“黄牛”,这些互连网还老是了万倍的外侧成员,他们所做的事只有是“打码”、“发短信”、虚假交易、不符合实际的评头品足,轻松赚钱。

早在两年前自个儿就已经能很熟悉的运用完毕端口那种技能了,只是直接从未机会将它用在什么样类型中,那段时光来看那种技术被过分炒作,过分的神秘化,就想写一篇解释它怎么工作的小说.想告诉大家它并未故事中的那么高深难懂!有何样错误的地点还请高人指正.转发请注脚出处及小编,多谢!

其次章  互连网业务月光蓝产业链分析

脚下黑产的日交易额可达数亿,但那仅是冰山一角,那几个冰山下的尤为复杂隐蔽,黑产的总体规模难以估测,其无人问津的力量更令人恐惧。

以二个文件传输服务端为例,在自家的机械上它只起八个线程就可以为许多一律客户端同时提供文件下载服务,程序的习性会随机器内CPU个数的加码而线性增加,小编尽恐怕做到使它清晰易懂,固然先后十分的小却用到了NT
5的有些新特点,重叠IO,达成端口以及线程池,基于那种模型的服务端程序应该是NT系统上质量最好的了.

2.1 月光蓝产业链综述

黑产现近日一度有了拾叁分早熟的小购销运作情势,产业链复杂、隐蔽、高效,是一个紧凑结合的繁杂链条。

在产业链的上游是2个基础性的环节,承担着开挖、制作生产和供应的职分,协理着很多项目标互联网黑产,为其提供关键资料。黑产的上游包括提供验证码辨识服务、手机验证码服务平台、自动化的软件工具,以及为黑产提供身份新闻与账号生产原材质的社工库等。

高中级是互联网账号提供商及交易交流平台,在产业链中充当账号生产者和各类服务提供者的角色,是关联上下游的桥梁。
产业链的下游紧假诺行使十分常渠道的网络账号进行诈骗、盗窃、刷单等恶意行为的团体,他们冲在最前沿,与网络用户正面交锋,给用户带来直接的裨益损失。

美高梅娱乐4858.com 1

图1 网络象牙白产业链全景图

 

黑产人士以17至2三岁的男性为主,紧要分布在辽宁、湖南、湖南、西藏等沿海省份,那也适合经济前行水平和食指密集度的遍布。

美高梅娱乐4858.com 2

图2 黑产从业人士的Top区域分布

 

比较二〇一四年,黑产在当年总收入千亿级,手机验证码平台相关黑产总收入最高,刷单平台相关黑产人均收入最高。

黑产具备专业的攻防能力、百分百如日中天投入、完整的产业链布局和分工,及各样先进的检测工具等,而公司或开发者没有对应的日喀则攻防经验、没有生命力和岁月投入到平安攻防中,导致他们中间是一场没有硝烟、实力悬殊的大战。

美高梅娱乐4858.com 3

图3 公司和开发者与黑产之间是一场实力悬殊的战火

首先.做为完结端口的根基,大家应当明白重叠IO,这亟需您早就知晓了基础对象及操作系统的片段定义概念,什么是信号/非信号态,什么是等待函数,什么是马到功成等待的副功用,什么是线程挂起等,若是这几个概令还没有精晓,你应超过看一下Windows
宗旨编程中的相关内容.尽管已经通晓那些,那么重叠IO对您来说并简单.

 

您可以这样认为重叠IO,以后您早就跻身3个服务器/客户机环境,请不要混淆概念,那里的服务器是指操作系统,而客户机是指你的先后(它举办IO操作),是当您举办IO操作(send,recv,writefile,readfile….)时您发送3个IO请求给服务器(操作系统),由服务器来形成你需求的操作,然后您如何事都未曾了,当服务器完毕IO请求时它会打招呼你,当然在那之间你可以做其它事,1个常用的技艺是在殡葬重叠IO请求后,程序在二个循环中二头调用PeekMessage,TranslateMessage和DispatchMessage更新界面,同时调用GetOverlappedResult等待服务器已毕IO操作,更快速一点的做法是行使IO已毕例程来拍卖服务器(操作系统)再次回到的结果,但并不是种种扶助重叠IO操作的函数都辅助达成例程如TransmitFile函数.

2.2 黑产上游:打码平台、手机验证码平台、黑产软件

1. 打码平台(图片验证码平台)
成百上千网站都会通过图形验证码来分辨机具行为,对非平常请求进行拦阻。由此打码平台已成为绝当先八分之四黑产软件必备的模块之一,为黑产软件提供接口,突破网站为辨别机器照旧全人类行为而设置的图片验证码。

黑产协会社会低收入人口在打码平台上人肉识别图片验证码(每一种仅需0.001元至0.25元),便可轻松绕过图片验证码的防控。二零一四年,打码平台的充值客户数比二零一五年增进了27%,充值金额升高了百分之四十。

美高梅娱乐4858.com 4

图4 图片验证码平台的周转链路

 

打码平台从业人士(码工)首要分布在山东、福建、安徽等区域。

美高梅娱乐4858.com 5

图5 图片验证码平台的Top区域分布

 

2. 有线电话验证码平台
手机验证码平台经过整合多方手机验证码商户的能源,作为交易平台衔接验证码商行与购买者。

购买者可将手机验证码平台上得到的手机号填入所需注册认证的网站,然后平台就会给买家再次来到收到的验证码,从而通过网站的验证,一般的话那类手机号是一次性使用。有的网站为了应对以上行为,会对用户的手机号举行频仍验证,因而先导有手机验证码平台提供了可长期利用的手机号。2个部手机验证码收费从0.1元到3元不等,相较用实体手机卡开销更是廉价。

美高梅娱乐4858.com 6

图6 手机验证码平台的运作链路

 

手机验证码平台的使用量逐月递增,二零一六年平台的充值人数是2015年的3倍,充值金额是二零一五年的2.6倍,涨幅迅猛。 

美高梅娱乐4858.com 7

图7 手机验证码平台充值人数和金额的同比拉长

 

另一方面,手机验证码平台的手机号重假设源于中国联通、中国电信、中国移动和虚构运营商,归属地重假使山西、江苏、新疆、湖北为主,使用手机验证码平台的人手重点分布在吉林、云南、云南、辽宁等地。

美高梅娱乐4858.com 8

图8 手机验证码平台的Top区域分布

 

二零一六年,手机验证码平台主要用来社交、电商、金融、生活等行业,总占比88%,那一个手机号八分之四以上都以用于账号注册。

美高梅娱乐4858.com 9

图9 手机黑卡流向的本行

 

3. 黑产软件

黑产软件涉猎广泛,包含刷单、盗号、注册、抢购、新闻收集、音信群发等,具体制作销售链路如下。

美高梅娱乐4858.com 10

图10 软件的成立销售链路

例1.三回重合写操作进度(GetOverlappedResult方法):
1.填写二个OVEPAJEROLAPPED结构
2.展开2次写操作,并点名重叠操作参数(下面的OVESportageLAPPED结构变量的指针)
3.做别的事(如更新界面)
4.GetOverlappedResult取操作结果
5.假使IO请求没有完毕,并且没有出错则赶回期3
6.处理IO操作结果

 

例2.二回重合写操作进度(完毕例程方法):
1.填写多少个OVE奥迪Q5LAPPED结构
2.展开1遍写操作,并点名重叠操作参数(下面的OVE安德拉LAPPED结构变量的指针),并内定达成例程
3.做其余事(如更新界面)
4.当成功例程被调用表达IO操作已经形成或出错,将来可以对操作结果开展处理了

2.3 黑产中游:恶意注册、盗号

1.  黑心注册
账号恶意注册是黑心行为的源头,整个工艺流程已趋于专业化、从业人士九万级,形成了手机验证码服务平台、打码平台、注册软件开发集团、垃圾账号分销平台等一行服务。批量性恶意注册紧假设由此软件已毕的,具体流程如下图。

美高梅娱乐4858.com 11

图11 注册软件批量报了名的流程

 

2.  盗号
黑产在登录环节通过暴力破解、撞库等方法,来得到用户音讯进而盗取账号。

美高梅娱乐4858.com 12

图12 黑产盗号流程

 

盗号团伙从黑客手中收购一批拖库而来的账号数据,后将数据与各大P2P、社交、O2O等网站开展匹配,通过俗称的“撞库”以获取所需网站的账号密码。盗号团伙驾驭网站的账号密码后通过洗号,剥离有价值的账号,通过各个渠道销售账号获利。

如若你早已明白地点的概念,就已经很相近IO达成端口了,当然那只是很健康的交汇操作它早已越发飞快,但万一再结合多线程对1个File或是Socket举办重叠IO操作就会格外复杂,经常程序员很难把握这种复杂度.完毕端口可以说就是为了丰富发挥四线程和重叠IO操作相结合的习性而设计的.很多个人都说它复杂,其实若是你协调完结1个四线程的对贰个File或是Socket进行重叠IO操作的程序(注意是四个线程对3个HANDLE或SOCKET进行重叠IO操作,而不是启一个线程对二个HANDLE举行重叠IO操作)就会意识形成端口实际上简化了八线程里使用重叠IO的复杂度,并且质量更高,品质高在哪?上面进行表明.

2.4 黑产下游:利益套现

黑产通过上中间的备选,最终将开展利益套现,首要的方式包涵运动刷单、欺诈、盗窃、勒索等。

移动刷单是正规协会通过得到多个账号,使用八个设施,以活动或手动的措施突破平台工作逻辑限制,举行间接得到暴利的一颦一笑。活动刷单是互连网公司在加大时普遍碰到的威逼,主要爆发在秒杀、零元购、红包、降价券等活动中。

美高梅娱乐4858.com 13

图13 活动刷单的流程

 

前几日互连网+环境下,刷单现象万分沉痛、利润率很高,行业分工更为细,渐渐变为支柱性黑客产业链。其中热门活动被刷的几率达百分百,如某品零元购运动、某老牌旅游集团让利红包被刷等案例不乏先例,那一个被刷的本钱间接流入黑产。

美高梅娱乐4858.com 14

图14 二零一四年有的活动刷单案例

我们大概写过如此的服务端程序:

2.5 风险防控方案

就算整个产业链涉及多少个环节,但最首要动作均是因此互连网账户举行,一般来讲首要涉及三个互相关系的事情场景:

注册场景:超过一半网上行为都是根据账号举办,是“黑产”一切活动的基础、弹药,账号量的略微、账号的质量,基本与“黑产团伙”获利成正比,从各平台账号购销的标价,也足以一贯报告出各平台利益及防控的效劳。识别恶意注册,并开展阻挠和打击,缩小“黑产”可以运用的账号量,可使得压缩活动作弊、垃圾音讯、欺诈等风险 。

登录现象:报到是一道门槛,通过用户作为及设施特征的剖析,当先八分之四的刷库、盗号、活动作弊等高危害均可以在报到时辨认,进步恶意账号登录门槛,对刷库及被盗风险账号扩张对应验证。比如,登录环节通过验证码、短信验证均可下跌账号使用风险。在找密、用户消息修改场景也会合临登录相同的高危机,可应用同一的防控方法。

活动(交易)场景:那一个是“黑产”对抗的主战场,也是削减其纯利的第三手战场,那里的势不两立措施,不可以只简简单单的识别危害,还须要考虑账户的市值,通过机械行为危机与价值双纬度判断,使用身份验证与优化力度双杠杆调节来使“灰产”无利可图。

二〇一四年,Ali聚安全生产了按照场景的多少风控服务,提供危机评估、风险识别、危机控制的实时防控功用。更加多服务介绍和接通,请登录Ali聚铁岭官网

美高梅娱乐4858.com 15

图15 Ali聚安全部据风控成效

例3.主程序:
1.监听2个端口
2.等候连接
3.当有连接来时
4.启1个线程对这一个客户端举行处理
5.回到2

其三章  数据风控发展趋势

账号作为“网络蓝灰产业链”关键要素,已经得以作为一种攻防功用的衡量目标,账号的购销价格、账号供应量,可以直接展现出“黑产”规模与被口诛笔伐矛头。
依照账户安全的“黑产”已经显示高回报、高技能、低本钱的增高态势,二零一五年那种趋势将会更具发生性。

1.  “人肉”、“社工”形式规模将扩充
2014年根据业务规则漏洞,采用“人肉”、“社工”格局的恶心协会范围将扩大,恶意注册、账号购销、盗号、隐衷新闻购买销售、音讯推广、刷单、活动作弊等“黑产”各环节均能致富,高回报也将吸引多量人手加入,许多环节已经“人肉”替代了“技术”,风险识别也急需从原来设备、环境越多的向用户作为做综合判断。

2.  “实时化”风险识别能力要求增强
2014年,通过与互联网不合规的攻防战,双方响应时间逐步减少,从注册1个账号到获利,已经从原先T+N收缩到分钟级。二〇一六年的对峙将是“实时总括”,实时发现危害、化解风险将是风控系统的发展趋势,由于实时风控系统的建设基金较高,像阿里聚平安那类提供规范实时安全服务的能力将改为主流。

3.  “多种化验证”将改成主流
二零一四年,大批量的账户被盗,已经让用户对于密码失去信心,“去密码”化,将会成为一种趋势,基于危机的“三种化可布署验证”将变成平衡安全与经验的关键手段。


完全版PDF《二零一五多少风控年报》下载,请点击那里 

 

劳务线程:
1.读客户端请求
2.如若客户端不再有请求,执行6
3.处理请求
4.回去操作结果
5.回到1
6.退出线程

那是一种最不难易行的网络服务器模型,大家把它优化一下

例4.主程序:
1.开多个线程池,里面有机器能接受的最大线程数个线程,线程都处在挂起(suspend)状态
1.监听叁个端口
2.守候连接
3.当有连接来时
4.从线程池里Resume多个线程对那个客户端举行处理
5.回到2

劳务线程与例3模型里的一样,只是当线程处理完客户端全部请求后,不是脱离而是回到线程池,再次挂起让出CPU时间,并等待为下二个客户机服务.当然在此时期线程会因为IO操作(服务线程的第2,5操作,恐怕还有其余阻塞操作)挂起本身,但不会回去线程池,相当于说它叁次只可以为叁个客户端服务.

那只怕是您能体悟的最迅速的服务端模型了吗!它与第一个服务端模型对照少了家常便饭个用户态到内核态的CONTEXT
Switch,反映也越发飞快,或者你只怕认为这很无所谓,那说明您缺少对普遍高品质服务器程序(比如网游服务端)的认识,如若您的服务端程序要对几千万个客户端举办服务啊?那也是微软Windows
NT开发组在NT 5以上的系统中添加线程池的原因.

思想一下怎么的模子可以让三个线程为三个客户端服务吗!那就要跳出每来3个连接启线程为其劳动的一定思维形式,我们把线程服务的纤维单元区划为单独的读或写操作(注意是读或写不是读和写),而不是2个客户端从一连到断开时期的保有读写操作.逐个线程都应用重叠IO举办读写操作,投递了读写请求后线程回到线程池,等待为任何客户机服务,当操作落成或出错时再重临处理操作结果,然后再回来线程池.

看望那样的服务器模型:
例5.主程序:
1.开多个线程池,里面有机器内CPU个数两倍的线程,线程都地处挂起(suspend)状态,它们在都等处理二遍重合IO操作的达成结果
1.监听3个端口
2.等候连接
3.当有连接来时
4.投递1个交汇读操作读取命令
5.回到2

服务线程:
1.只要读已毕,则处理读取的故事情节(如HTTP GET命令),否则执行3
2.投递二个交汇写操作(如再次回到HTTP GET命令需求的网页)
3.假使是3个写操作完毕,可以再投递一个交汇读操作,读取客户机的下3个请求,或然是关闭连接(如HTTP协议里每发完一个网页就断开)
4.取得下一个交汇IO操作结果,借使IO操作没有马到成功或从不IO操作则回到线程池

假设那是三个WEB服务器程序,可以见到工作者线程是以读或写为最小的办事单元运营的,在主程序里面举行了贰回重合读操作

当读操作完结时2个线程池中的一个劳动力线程被激活取得了操作结果,处理GET或POST命令,然后发送三个网页内容,发送也是二个交汇操作,然后处理对任何客户机的IO操作结果,尽管没有其余的事物必要处理时回来线程池等待.可以看出拔取那种模型发送和吸收可以是也得以不是三个线程.

当发送操作达成时,线程池中的四个劳引力线程池激活,它倒闭连接(HTTP协议),然后处理其余的IO操作结果,假设没有别的的事物要求处理时再次来到线程池等待.

探望在如此的模子中五个线程怎么为七个客户端服务,同样是仿照二个WEB服务器例子:

比方今后系统中有五个线程,ThreadA,ThreadB它们在都等处理一回重合IO操作的已毕结果

当四个客户机ClientA连接来时主程序投递叁个交汇读操作,然后等待下四个客户机连接,当读操作达成时ThreadA被激活,它接受三个HTTP
GET命令,然后ThreadA使用重叠写操作发送七个网页给ClientA,然后立刻回到线程池等待处理下1个IO操作结果,那时发送操作还并未完结,又有3个客户机ClientB连接来,主程序再投递贰个重合读操作,当读操作落成时ThreadA(当然也或许是ThreadB)再次被激活,它再也雷同步骤,收到三个GET命令,使用重叠写操作发送二个网页给ClientB,本次它并以往得及回到线程池时,又有三个连接ClientC连入,主程序再投递叁个交汇读操作,读操作已毕时ThreadB被激活(因为ThreadA还尚无回去线程池)它接受二个HTTP
GET命令,然后ThreadB使用重叠写操作发送2个网页给ClientC,然后ThreadB回到线程池,那时ThreadA也回到了线程池.

可以想像以往有八个挂起的出殡操作分别是ThreadA发送给ClientA和ClientB的网页,以及ThreadB发送给ClientC的网页,它们由操作系统内核来处理.ThreadA和ThreadB将来一度再次回到线程池,可以继续为其余任何客户端服务.

当对ClientA的重合写操作已经落成,ThreadA(也足以是ThreadB)又被激活它倒闭与ClientA连接,但还未曾回来线程池,与此同时发送给ClientB的重合写操作也马到功成,ThreadB被激活(因为ThreadA还尚未重回线程池)它倒闭与ClientB的连年,然后回来线程池,那时ClientC的写操作也形成,ThreadB再一次被激活(因为ThreadA照旧没有回到线程池),它再关闭与ClientC的连接,这时ThreadA回到线程池,ThreadB也回到线程池.那时对八个客户端的劳动整个达成.可以看来在任何服务进度中,”建立连接”,”读数据”,”写多少”和”关闭连接”等操作是逻辑上连年而实质上分开的.

到前几日得了四个线程处理了贰遍读操作和1遍写操作,在这个读写操作进度中所现身的状态机(state
machine)是比较复杂的,大家模拟的是透过本身简化过的,实际上的图景要比那几个还要复杂很多,可是那样的服务端模型在客户端请求越来越多时与前八个模型对照的习性越高.而采用完了端口我们得以很不难达成那样的服务器模型.

微软的IIS
WEB服务器就是选取那样的服务端模型,很多人说什么样阿帕奇服务器比IIS的习性好怎么怎么的作者代表疑虑,除非阿帕奇服务器得以将线程分割成,为更小的单元服务,我觉着不太可能!这种成功端口模型已经将单个读或写操作作为最小的服务单元,作者觉得在同一机器配置的图景下IIS的习性要远远超出其余WEB服务器,那也是从完毕机理上来分析的,假使出现质量上的差距或许是在不一样的操作系统上,可能Linux的基石比Windows的自身,有人真正研讨过呢?依然大家齐声在炒作啊.

对此状态机概念,在诸多上边都利用,TCPIP中有,编译原理中有,OpengGL中有等等,小编的离散数学不佳(我是会计专业不学那一个),然则依旧搞懂了些,小编想假设你多花些时日看,如故得以搞懂的.最终是一个简便的文件传输服务器程序代码,只用了七个线程(我的机械里只有一块CPU)就可以服务八个客户端.作者调试时用它同时为四个nc客户端提供文件下载服务都并未难题,当然越来越多也不会有毛病,只是略为使用了须臾间NT
5的线程池和形成端口技术就足以有诸如此类高的属性,更不用说IIS的质量咯!

期待大家不要陷在这一个程序的框架中,Ctrl+C,Ctrl+V没有怎么意义,要了解它的实质.程序行使Visual
C++ 6.0 SP5+二零零二 Platform SDK编译通过,在Windows XP
Professional下调试运转通过.程序运转的最低要求是Windows 两千操作系统.

/********************************************************************
    created:    2005/12/24
    created:    24:12:2005   20:25
    modified:    2005/12/24
    filename:     d:\vcwork\iocomp\iocomp.cpp
    file path:    d:\vcwork\iocomp
    file base:    iocomp
    file ext:    cpp
    author:        kruglinski(kruglinski_at_gmail_dot_com)
   
    purpose:    利用完结端口技术落成的高品质文件下载服务程序
*********************************************************************/

#define _WIN32_WINNT    0x0500

#include <cstdlib>
#include <clocale>
#include <ctime>
#include <iostream>//一使用输入输出流程序霎时增大70K
#include <vector>
#include <algorithm>
#include <winsock2.h>
#include <mswsock.h>

using namespace std;

#pragma comment(lib,”ws2_32.lib”)
#pragma comment(lib,”mswsock.lib”)

const int MAX_BUFFER_SIZE=1024;
const int PRE_SEND_SIZE=1024;
const int QUIT_TIME_OUT=3000;
const int PRE_DOT_TIMER=QUIT_TIME_OUT/80;

typedef enum{IoTransFile,IoSend,IoRecv,IoQuit} IO_TYPE;

typedef struct
{
    SOCKET hSocket;
    SOCKADDR_IN ClientAddr;
}PRE_SOCKET_DATA,*PPRE_SOCKET_DATA;

typedef struct
{
    OVERLAPPED    oa;
    WSABUF        DataBuf;
    char        Buffer[MAX_BUFFER_SIZE];
    IO_TYPE        IoType;
}PRE_IO_DATA,*PPRE_IO_DATA;

typedef vector<PPRE_SOCKET_DATA>    SocketDataVector;
typedef vector<PPRE_IO_DATA>        IoDataVector;

SocketDataVector    gSockDataVec;
IoDataVector        gIoDataVec;

CRITICAL_SECTION    csProtection;

char* TimeNow(void)
{
    time_t t=time(NULL);
    tm *localtm=localtime(&t);
    static char timemsg[512]={0};
   
    strftime(timemsg,512,”%Z: %B %d %X,%Y”,localtm);
    return timemsg;
}

BOOL TransFile(PPRE_IO_DATA pIoData,PPRE_SOCKET_DATA
pSocketData,DWORD dwNameLen)
{
    //这一句是为nc做的,你可以修改它
    pIoData->Buffer[dwNameLen-1]=’\0′;
   
    HANDLE
hFile=CreateFile(pIoData->Buffer,GENERIC_READ,0,NULL,OPEN_EXISTING,0,NULL);
    BOOL bRet=FALSE;

    if(hFile!=INVALID_HANDLE_VALUE)
    {
        cout<<“Transmit File “<<pIoData->Buffer<<”
to client”<<endl;
        pIoData->IoType=IoTransFile;
        memset(&pIoData->oa,0,sizeof(OVERLAPPED));
        *reinterpret_cast<HANDLE*>(pIoData->Buffer)=hFile;
       
TransmitFile(pSocketData->hSocket,hFile,GetFileSize(hFile,NULL),PRE_SEND_SIZE,reinterpret_cast<LPOVERLAPPED>(pIoData),NULL,TF_USE_SYSTEM_THREAD);
        bRet=WSAGetLastError()==WSA_IO_PENDING;
    }
    else
        cout<<“Transmit File
“<<“Error:”<<GetLastError()<<endl;

    return bRet;
}

DWORD WINAPI ThreadProc(LPVOID IocpHandle)
{
    DWORD dwRecv=0;
    DWORD dwFlags=0;
   
    HANDLE hIocp=reinterpret_cast<HANDLE>(IocpHandle);
    DWORD dwTransCount=0;
    PPRE_IO_DATA pPreIoData=NULL;
    PPRE_SOCKET_DATA pPreHandleData=NULL;

    while(TRUE)
    {
        if(GetQueuedCompletionStatus(hIocp,&dwTransCount,
            reinterpret_cast<LPDWORD>(&pPreHandleData),
           
reinterpret_cast<LPOVERLAPPED*>(&pPreIoData),INFINITE))
        {
            if(0==dwTransCount&&IoQuit!=pPreIoData->IoType)
            {
                cout<<“Client:”
                   
<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
                   
<<“:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
                    <<” is closed”<<endl;

                closesocket(pPreHandleData->hSocket);

                EnterCriticalSection(&csProtection);
                    IoDataVector::iterator
itrIoDelete=find(gIoDataVec.begin(),gIoDataVec.end(),pPreIoData);
                    SocketDataVector::iterator
itrSockDelete=find(gSockDataVec.begin(),gSockDataVec.end(),pPreHandleData);
                   delete *itrIoDelete;
                   delete *itrSockDelete;
                   gIoDataVec.erase(itrIoDelete);
                   gSockDataVec.erase(itrSockDelete);
                LeaveCriticalSection(&csProtection);

                      
                continue;
            }
           
            switch(pPreIoData->IoType){
            case IoTransFile:
                cout<<“Client:”
                   
<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
                   
<<“:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
                    <<” Transmit finished”<<endl;
               
CloseHandle(*reinterpret_cast<HANDLE*>(pPreIoData->Buffer));
                goto LRERECV;
               
            case IoSend:
                cout<<“Client:”
                   
<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
                   
<<“:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
                    <<” Send finished”<<endl;

LRERECV:
                pPreIoData->IoType=IoRecv;
                pPreIoData->DataBuf.len=MAX_BUFFER_SIZE;
                memset(&pPreIoData->oa,0,sizeof(OVERLAPPED));

               
WSARecv(pPreHandleData->hSocket,&pPreIoData->DataBuf,1,
                    &dwRecv,&dwFlags,
                   
reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData),NULL);

                break;

            case IoRecv:
                cout<<“Client:”
                   
<<inet_ntoa(pPreHandleData->ClientAddr.sin_addr)
                   
<<“:”<<ntohs(pPreHandleData->ClientAddr.sin_port)
                    <<” recv finished”<<endl;
                pPreIoData->IoType=IoSend;
               
                if(!TransFile(pPreIoData,pPreHandleData,dwTransCount))
                {
                    memset(&pPreIoData->oa,0,sizeof(OVERLAPPED));
                    strcpy(pPreIoData->DataBuf.buf,”File transmit
error!\r\n”);
                   
pPreIoData->DataBuf.len=strlen(pPreIoData->DataBuf.buf);
                   
                   
WSASend(pPreHandleData->hSocket,&pPreIoData->DataBuf,1,
                        &dwRecv,dwFlags,
                       
reinterpret_cast<LPWSAOVERLAPPED>(pPreIoData),NULL);
                }
                break;
               
            case IoQuit:
                goto LQUIT;
               
            default:
                ;
            }
        }   
    }
   
LQUIT:
    return 0;
}

HANDLE hIocp=NULL;
SOCKET hListen=NULL;

BOOL WINAPI ShutdownHandler(DWORD dwCtrlType)
{
    PRE_SOCKET_DATA PreSockData={0};
    PRE_IO_DATA PreIoData={0};

    PreIoData.IoType=IoQuit;

    if(hIocp)
    {
        PostQueuedCompletionStatus(hIocp,1,
            reinterpret_cast<ULONG_PTR>(&PreSockData),
            reinterpret_cast<LPOVERLAPPED>(&PreIoData));

        cout<<“Shutdown at
“<<TimeNow()<<endl<<“wait for a moment
please”<<endl;
       
        //让出CPU时间,让线程退出
        for(int t=0;t<80;t+=1)
        {
            Sleep(PRE_DOT_TIMER);
            cout<<“.”;
        }
       
        CloseHandle(hIocp);
    }
   
    int i=0;

    for(;i<gSockDataVec.size();i++)
    {
        PPRE_SOCKET_DATA pSockData=gSockDataVec[i];
        closesocket(pSockData->hSocket);
        delete pSockData;
    }

    for(i=0;i<gIoDataVec.size();i++)
    {
        PPRE_IO_DATA pIoData=gIoDataVec[i];
        delete pIoData;
    }

    DeleteCriticalSection(&csProtection);
    if(hListen)
        closesocket(hListen);

    WSACleanup();
    exit(0);
    return TRUE;
}

LONG WINAPI MyExceptionFilter(struct _EXCEPTION_POINTERS
*ExceptionInfo)
{
    ShutdownHandler(0);
    return EXCEPTION_EXECUTE_HANDLER;
}

u_short DefPort=8182;

int main(int argc,char **argv)
{
    if(argc==2)
        DefPort=atoi(argv[1]);

    InitializeCriticalSection(&csProtection);
    SetUnhandledExceptionFilter(MyExceptionFilter);
    SetConsoleCtrlHandler(ShutdownHandler,TRUE);

    hIocp=CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);

    WSADATA data={0};
    WSAStartup(0x0202,&data);

    hListen=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(INVALID_SOCKET==hListen)
    {
        ShutdownHandler(0);
    }
   
    SOCKADDR_IN addr={0};
    addr.sin_family=AF_INET;
    addr.sin_port=htons(DefPort);
   
    if(bind(hListen,reinterpret_cast<PSOCKADDR>(&addr),
        sizeof(addr))==SOCKET_ERROR)
    {
        ShutdownHandler(0);
    }
   
    if(listen(hListen,256)==SOCKET_ERROR)
        ShutdownHandler(0);

    SYSTEM_INFO si={0};
    GetSystemInfo(&si);
    si.dwNumberOfProcessors<<=1;

    for(int i=0;i<si.dwNumberOfProcessors;i++)
    {
       
        QueueUserWorkItem(ThreadProc,hIocp,WT_EXECUTELONGFUNCTION);
    }
   
    cout<<“Startup at “<<TimeNow()<<endl
        <<“work on port “<<DefPort<<endl
        <<“press CTRL+C to
shutdown”<<endl<<endl<<endl;

    while(TRUE)
    {
        int namelen=sizeof(addr);
        memset(&addr,0,sizeof(addr));
        SOCKET
hAccept=accept(hListen,reinterpret_cast<PSOCKADDR>(&addr),&namelen);

        if(hAccept!=INVALID_SOCKET)
        {
            cout<<“accept a
client:”<<inet_ntoa(addr.sin_addr)<<“:”<<ntohs(addr.sin_port)<<endl;

            PPRE_SOCKET_DATA pPreHandleData=new PRE_SOCKET_DATA;
            pPreHandleData->hSocket=hAccept;
            memcpy(&pPreHandleData->ClientAddr,&addr,sizeof(addr));
           
           
CreateIoCompletionPort(reinterpret_cast<HANDLE>(hAccept),
               
hIocp,reinterpret_cast<DWORD>(pPreHandleData),0);
           
            PPRE_IO_DATA pPreIoData=new(nothrow) PRE_IO_DATA;

            if(pPreIoData)
            {
                EnterCriticalSection(&csProtection);
                    gSockDataVec.push_back(pPreHandleData);
                    gIoDataVec.push_back(pPreIoData);
                LeaveCriticalSection(&csProtection);

                memset(pPreIoData,0,sizeof(PRE_IO_DATA));
                pPreIoData->IoType=IoRecv;
                pPreIoData->DataBuf.len=MAX_BUFFER_SIZE;
                pPreIoData->DataBuf.buf=pPreIoData->Buffer;
                DWORD dwRecv=0;
                DWORD dwFlags=0;
                WSARecv(hAccept,&pPreIoData->DataBuf,1,
                    &dwRecv,&dwFlags,
                   
reinterpret_cast<WSAOVERLAPPED*>(pPreIoData),NULL);
            }
            else
            {
                delete pPreHandleData;
                closesocket(hAccept);
            }
        }
    }
   
    return 0;
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注