PPTP-VPN第三章——用户流量与并发数限制
在前面两篇文章中详细介绍了pptp vpn的安装与使用,以及如何配置用户认证存入mysql数据库。本文将在前面两篇文章的基础上介绍如何对用户的流量做限制,同时限制相同账号的用户,同一时刻的在线数为1。
前文传送门地址:
PPTP-VPN部署与简单使用 http://ylw6006.blog.51cto.com/470441/1794577
PPTP-VPN使用mysql进行用户登录认证 http://ylw6006.blog.51cto.com/470441/1795201
一、向mysql库表中插入基础数据
1
2
3
4
5
6
7
8
|
mysql> use radius mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Auth-Type',':=','Local'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Service-Type',':=','Framed-User'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Framed-IP-Address',':=','255.255.255.255'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Framed-IP-Netmask',':=','255.255.255.0'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Acct-Interim-Interval',':=','600'); mysql> INSERT INTO radgroupreply (groupname,attribute,op,VALUE) VALUES ('user','Max-Monthly-Traffic',':=','20480'); mysql> INSERT INTO radgroupcheck (groupname,attribute,op,VALUE) VALUES ('user','Simultaneous-Use',':=','1'); |
acct-interim-interval是计算流量的间隔(600秒),意味着每隔10分钟记录当前流量;
Max-Monthly-Traffic是每月最大流量,这里是20G(单位是M);
radgroupcheck表的Simultaneous-Use表示单个用户的同时连接数目;
这里要格外注意的是,许多网络上的文章介绍Max-Monthly-Traffic单位为字节,数值为5368709102,换算一下大概5G左右,而如果我们也精确到字节,数值设为20G,也就是21474836480,则用户拨入进行身份验证的时候将会报错。因而此次我们将流量限制的精度单位修改为M。详细可参考如下链接介绍:http://www.xj123.info/2856.html
二、修改配置文件
1、修改/etc/raddb/sites-enabled/default文件,添加流量限制的reject条件
1
2
3
4
5
6
7
8
|
# vi /etc/raddb/sites-enabled/default #找到authorize一节插入如下内容: update request { Group-Name := "%{sql:SELECT groupname FROM radusergroup WHERE username='%{User-Name}' ORDER BY priority}" } if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") { reject } |
2、由于使用了非内置的attribute Max-Monthly-Traffic,所以需要在/etc/raddb/dictionary里面定义
1
2
|
# tail -1 /etc/raddb/dictionary ATTRIBUTE Max-Monthly-Traffic 3003 integer |
3、修改/etc/raddb/sql/mysql/dialup.conf文件,开启在线用户数检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
# vi /etc/raddb/sql/mysql/dialup.conf sql_user_name = "%{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}}" #sql_user_name = "%{User-Name}" #注释掉这行 # Uncomment simul_count_query to enable simultaneous use checking simul_count_query = "SELECT COUNT(*) \ FROM ${acct_table1} \ WHERE username = '%{SQL-User-Name}' \ AND acctstoptime IS NULL" simul_verify_query = "SELECT radacctid, acctsessionid, username, \ nasipaddress, nasportid, framedipaddress, \ callingstationid, framedprotocol \ FROM ${acct_table1} \ WHERE username = '%{SQL-User-Name}' \ AND acctstoptime IS NULL" |
三、重启服务
# /etc/init.d/radiusd stop
# /etc/init.d/pptpd restart
四、测试
1、将rediusd服务运行在debug模式下,进行拨号测试,主要测试流量控制!
#radiusd -X
通过上面可以看到当前的用户流量消耗为2M,限制流量的值为20480M。
因而在/etc/raddb/sites-enabled/default文件,判断流量限制的reject条件的结果为false,用户可以通过验证,完成拨号!下面是详细的拨号日志:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
|
rad_recv: Access-Request packet from host 127.0.0.1 port 49226, id=94, length=150 Service-Type = Framed-User Framed-Protocol = PPP User-Name = "ptest1" MS-CHAP-Challenge = 0x6716c32940f1c84ad213d2d52df1712d MS-CHAP2-Response = 0x2400c77c090296803fb3c0822b8c679547f000000000000000001eb41fe8e518c1f756fb5d9d5904ddb8dc1fe271e98aa055 Calling-Station-Id = "27.151.123.121" NAS-IP-Address = 127.0.0.1 NAS-Port = 0 # Executing section authorize from file /etc/raddb/sites-enabled/default +group authorize { ++update request { sql_xlat expand: %{Stripped-User-Name} -> ... expanding second conditional expand: %{User-Name} -> ptest1 expand: %{%{User-Name}:-DEFAULT} -> ptest1 expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 sql_set_user escaped user --> 'ptest1' expand: SELECT groupname FROM radusergroup WHERE username='%{User-Name}' ORDER BY priority -> SELECT groupname FROM radusergroup WHERE username='ptest1' ORDER BY priority rlm_sql (sql): Reserving sql socket id: 30 sql_xlat finished rlm_sql (sql): Released sql socket id: 30 expand: %{sql:SELECT groupname FROM radusergroup WHERE username='%{User-Name}' ORDER BY priority} -> user ++} # update request = noop ++? if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") sql_xlat expand: %{Stripped-User-Name} -> ... expanding second conditional expand: %{User-Name} -> ptest1 expand: %{%{User-Name}:-DEFAULT} -> ptest1 expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 sql_set_user escaped user --> 'ptest1' expand: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now()); -> SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='ptest1' AND date_format(acctstarttime, '2016-06-30') >= date_format(now(),'2016-06-01') AND date_format(acctstoptime, '2016-06-30') <= last_day(now()); rlm_sql (sql): Reserving sql socket id: 29 sql_xlat finished rlm_sql (sql): Released sql socket id: 29 expand: %{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());} -> 2 sql_xlat expand: %{Stripped-User-Name} -> ... expanding second conditional expand: %{User-Name} -> ptest1 expand: %{%{User-Name}:-DEFAULT} -> ptest1 expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 sql_set_user escaped user --> 'ptest1' expand: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic'; -> SELECT value FROM radgroupreply WHERE groupname='user' AND attribute='Max-Monthly-Traffic'; rlm_sql (sql): Reserving sql socket id: 28 sql_xlat finished rlm_sql (sql): Released sql socket id: 28 expand: %{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';} -> 20480 ? Evaluating ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") -> FALSE ++? if ("%{sql: SELECT SUM(acctinputoctets+acctoutputoctets) div 1048576 FROM radacct WHERE username='%{User-Name}' AND date_format(acctstarttime, '%Y-%m-%d') >= date_format(now(),'%Y-%m-01') AND date_format(acctstoptime, '%Y-%m-%d') <= last_day(now());}" >= "%{sql: SELECT value FROM radgroupreply WHERE groupname='%{Group-Name}' AND attribute='Max-Monthly-Traffic';}") -> FALSE ++[preprocess] = ok ++[chap] = noop [mschap] Found MS-CHAP attributes. Setting 'Auth-Type = mschap' ++[mschap] = ok ++[digest] = noop [suffix] No '@' in User-Name = "ptest1", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] = noop [eap] No EAP-Message, not doing EAP ++[eap] = noop [sql] expand: %{Stripped-User-Name} -> [sql] ... expanding second conditional [sql] expand: %{User-Name} -> ptest1 [sql] expand: %{%{User-Name}:-DEFAULT} -> ptest1 [sql] expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 [sql] sql_set_user escaped user --> 'ptest1' rlm_sql (sql): Reserving sql socket id: 27 [sql] expand: SELECT id, username, attribute, value, op FROM radcheck WHERE username = '%{SQL-User-Name}' ORDER BY id -> SELECT id, username, attribute, value, op FROM radcheck WHERE username = 'ptest1' ORDER BY id WARNING: Found User-Password == "...". WARNING: Are you sure you don't mean Cleartext-Password? WARNING: See "man rlm_pap" for more information. [sql] User found in radcheck table [sql] expand: SELECT id, username, attribute, value, op FROM radreply WHERE username = '%{SQL-User-Name}' ORDER BY id -> SELECT id, username, attribute, value, op FROM radreply WHERE username = 'ptest1' ORDER BY id [sql] expand: SELECT groupname FROM radusergroup WHERE username = '%{SQL-User-Name}' ORDER BY priority -> SELECT groupname FROM radusergroup WHERE username = 'ptest1' ORDER BY priority [sql] expand: SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute, Value, op FROM radgroupcheck WHERE groupname = 'user' ORDER BY id [sql] User found in group user [sql] expand: SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = '%{Sql-Group}' ORDER BY id -> SELECT id, groupname, attribute, value, op FROM radgroupreply WHERE groupname = 'user' ORDER BY id rlm_sql (sql): Released sql socket id: 27 ++[sql] = ok ++[expiration] = noop ++[logintime] = noop [pap] WARNING: Auth-Type already set. Not setting to PAP ++[pap] = noop +} # group authorize = ok Found Auth-Type = MSCHAP !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! Replacing User-Password in config items with Cleartext-Password. !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!! Please update your configuration so that the "known good" !!! !!! clear text password is in Cleartext-Password, and not in User-Password. !!! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! # Executing group from file /etc/raddb/sites-enabled/default +group MS-CHAP { [mschap] Creating challenge hash with username: ptest1 [mschap] Client is using MS-CHAPv2 for ptest1, we need NT-Password [mschap] adding MS-CHAPv2 MPPE keys ++[mschap] = ok +} # group MS-CHAP = ok # Executing section session from file /etc/raddb/sites-enabled/default +group session { [radutmp] expand: /var/log/radius/radutmp -> /var/log/radius/radutmp ++[radutmp] = ok +} # group session = ok # Executing section post-auth from file /etc/raddb/sites-enabled/default +group post-auth { [sql] expand: %{Stripped-User-Name} -> [sql] ... expanding second conditional [sql] expand: %{User-Name} -> ptest1 [sql] expand: %{%{User-Name}:-DEFAULT} -> ptest1 [sql] expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 [sql] sql_set_user escaped user --> 'ptest1' [sql] expand: %{User-Password} -> [sql] ... expanding second conditional [sql] expand: %{Chap-Password} -> [sql] expand: INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( '%{User-Name}', '%{%{User-Password}:-%{Chap-Password}}', '%{reply:Packet-Type}', '%S') -> INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'ptest1', '', 'Access-Accept', '2016-06-30 13:05:14') rlm_sql (sql) in sql_postauth: query is INSERT INTO radpostauth (username, pass, reply, authdate) VALUES ( 'ptest1', '', 'Access-Accept', '2016-06-30 13:05:14') rlm_sql (sql): Reserving sql socket id: 26 rlm_sql (sql): Released sql socket id: 26 ++[sql] = ok ++[exec] = noop +} # group post-auth = ok Sending Access-Accept of id 94 to 127.0.0.1 port 49226 Service-Type := Framed-User Framed-IP-Address := 255.255.255.255 Framed-IP-Netmask := 255.255.255.0 Acct-Interim-Interval := 600 MS-CHAP2-Success = 0x24533d46303044303641413737333432343231363234364143413245333041373133433531344439353037 MS-MPPE-Recv-Key = 0x3373da01475488084e5f82abae7cbda8 MS-MPPE-Send-Key = 0xdb408d5d7f18d9fd38e6c1888b8c0b13 MS-MPPE-Encryption-Policy = 0x00000001 MS-MPPE-Encryption-Types = 0x00000006 Finished request 0. Going to the next request Waking up in 4.9 seconds. Cleaning up request 0 ID 94 with timestamp +88 Ready to process requests. rad_recv: Accounting-Request packet from host 127.0.0.1 port 58801, id=95, length=114 Acct-Session-Id = "5774A890092400" User-Name = "ptest1" Acct-Status-Type = Start Service-Type = Framed-User Framed-Protocol = PPP Calling-Station-Id = "27.151.123.121" Acct-Authentic = RADIUS NAS-Port-Type = Async Framed-IP-Address = 192.168.222.10 NAS-IP-Address = 127.0.0.1 NAS-Port = 0 Acct-Delay-Time = 0 # Executing section preacct from file /etc/raddb/sites-enabled/default +group preacct { ++[preprocess] = ok [acct_unique] WARNING: Attribute NAS-Identifier was not found in request, unique ID MAY be inconsistent [acct_unique] Hashing 'NAS-Port = 0,,NAS-IP-Address = 127.0.0.1,Acct-Session-Id = "5774A890092400",User-Name = "ptest1"' [acct_unique] Acct-Unique-Session-ID = "413ac0cc5b5f4759". ++[acct_unique] = ok [suffix] No '@' in User-Name = "ptest1", looking up realm NULL [suffix] No such realm "NULL" ++[suffix] = noop +} # group preacct = ok # Executing section accounting from file /etc/raddb/sites-enabled/default +group accounting { [detail] expand: %{Packet-Src-IP-Address} -> 127.0.0.1 [detail] expand: /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d -> /var/log/radius/radacct/127.0.0.1/detail-20160630 [detail] /var/log/radius/radacct/%{%{Packet-Src-IP-Address}:-%{Packet-Src-IPv6-Address}}/detail-%Y%m%d expands to /var/log/radius/radacct/127.0.0.1/detail-20160630 [detail] expand: %t -> Thu Jun 30 13:05:20 2016 ++[detail] = ok [sql] expand: %{Stripped-User-Name} -> [sql] ... expanding second conditional [sql] expand: %{User-Name} -> ptest1 [sql] expand: %{%{User-Name}:-DEFAULT} -> ptest1 [sql] expand: %{%{Stripped-User-Name}:-%{%{User-Name}:-DEFAULT}} -> ptest1 [sql] sql_set_user escaped user --> 'ptest1' [sql] expand: %{Acct-Delay-Time} -> 0 [sql] expand: INSERT INTO radacct (acctsessionid, acctuniqueid, username, realm, nasipaddress, nasportid, nasporttype, acctstarttime, acctstoptime, acctsessiontime, acctauthentic, connectinfo_start, connectinfo_stop, acctinputoctets, acctoutputoctets, calledstationid, callingstationid, acctterminatecause, servicetype, framedprotocol, framedipaddress, acctstartdelay, acctstopdelay, xascendsessionsvrkey) VALUES ('%{Acct-Session-Id}', '%{Acct-Unique-Session-Id}', '%{SQL-User-Name}', '%{Realm}', '%{NAS-IP-Address}', '%{NAS-Port}', '%{NAS-Port-Type}', '%S', NULL, '0', '%{Acct-Authentic}', '%{Connect-Info}', '', '0', '0', '%{Called-Station-Id}', '%{Calling-Station-Id}', '', '%{Service-Type}', '%{Framed-Protocol}', '%{Framed-IP-Address}', rlm_sql (sql): Reserving sql socket id: 25 rlm_sql (sql): Released sql socket id: 25 ++[sql] = ok ++[exec] = noop [attr_filter.accounting_response] expand: %{User-Name} -> ptest1 attr_filter: Matched entry DEFAULT at line 12 ++[attr_filter.accounting_response] = updated +} # group accounting = updated Sending Accounting-Response of id 95 to 127.0.0.1 port 58801 Finished request 1. Cleaning up request 1 ID 95 with timestamp +94 Going to the next request Ready to process requests. |
2、测试同一个VPN账号,多终端登录
通过如下sql语句可以看到当前用户的拨号连接情况,很明显通过前面的配置,并没有起到限制的效果。
1
2
|
mysql> SELECT radacctid, acctsessionid, username,nasipaddress, nasportid, framedipaddress, callingstationid, framedprotocol FROM radacct WHERE username ='yang' AND acctstoptime IS NULL; mysql> SELECT COUNT(*) from radacct WHERE username ='yang' AND acctstoptime IS NULL; |
通过修改/etc/raddb/sites-enabled/default文件,注释掉session节的radutmp配置,重启radiusd服务后测试,发现效果符合预期
# vi /etc/raddb/sites-enabled/default
同一个账号的第二个拨号连接就会直接提示验证失败!
PPTP-VPN第三章——用户流量与并发数限制的更多相关文章
- (转)iOS Wow体验 - 第三章 - 用户体验的差异化策略
本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第三章译文精选,其余章节将陆续放出.上一篇:Wow ...
- Testlink1.9.17使用方法( 第三章 初始配置[配置用户、产品] )
第三章 初始配置(配置用户.产品) 一. 设置用户 QQ交流群:585499566 在TestLink系统中,每个用户都可以维护自己的私有信息.admin可以创建用户,但不能看到其它用户的密码.在用户 ...
- Gradle2.0用户指南翻译——第三章. 教程
翻译项目请关注Github上的地址:https://github.com/msdx/gradledoc本文翻译所在分支:https://github.com/msdx/gradledoc/tree/2 ...
- 2017.2.28 activiti实战--第五章--用户与组及部署管理(三)部署流程及资源读取
学习资料:<Activiti实战> 第五章 用户与组及部署管理(三)部署流程及资源读取 内容概览:如何利用API读取已经部署的资源,比如读取流程定义的XML文件,或流程对应的图片文件. 以 ...
- CentOS 6.5搭建PPTP VPN服务器
VPN是虚拟专用网络(Virtual Private Network)的缩写,VPN有多种分类方式,包括PPTP.L2TP.IPSec等,本文配置的VPN服务器是采用PPTP协议的,PPTP是在PPP ...
- 精通Web Analytics 2.0 (5) 第三章:点击流分析的奇妙世界:指标
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第三章:点击流分析的奇妙世界:指标 新的Web Analytics 2.0心态:搞定它.新的闪亮系列工具:是的.准备好了吗?当然 ...
- ubuntu 搭建PPTP VPN服务器
上一篇文章介绍了如何在Ubuntu服务器上搭建IPSEC L2TP VPN服务器.继续介绍如何在Ubuntu服务器上搭建PPTP VPN服务器. 首先安装以下所需包 #apt-get install ...
- 转载 - Vultr VPS注册开通且一键快速安装PPTP VPN和电脑连接使用
本文转载来自:https://www.vultrclub.com/139.html 从2014年Vultr VPS进入市场之后,作为有背景.实力的搅局者,是的最近两年VPS.服务器的用户成本降低.配置 ...
- SEO 第三章
SEO第三章 本次课目标: 1. 掌握关键词的选取方法 2. 掌握关键词的竞争强度分析 3. 掌握关键词的拓展方法 一.关键词的选取 选择关键词的时候可以根据公司网站的定位,围绕公司的主营产品或 ...
随机推荐
- asp.net webform 中使用Microsoft ASP.NET Web Optimization压缩js及css
使用静态资源压缩可以合并静态资源文件减少客户端请求数量,压缩文件大小,减少网络流量的损耗. 注:只有通过web.config关闭调试功能,压缩才会生效 <system.web> <c ...
- [DFNews] Touch ID不是神话,指模依旧能搞定。
扫描制作翻模,使用含石墨硅胶压膜,前者复制指纹纹路,后者欺骗活体检测.
- Java多线程之并发协作生产者消费者设计模式
两个线程一个生产者个一个消费者 需求情景 两个线程,一个负责生产,一个负责消费,生产者生产一个,消费者消费一个 涉及问题 同步问题:如何保证同一资源被多个线程并发访问时的完整性.常用的同步方法是采用标 ...
- 一个.NET通用JSON解析/构建类的实现(c#)转
转自:http://www.cnblogs.com/xfrog/archive/2010/04/07/1706754.html NET通用JSON解析/构建类的实现(c#) 在.NET Framewo ...
- Webpack 入门指南 - 3. Hello, Angular2!
Webpack 入门指南 - 1.安装 Webpack 入门指南 - 2.模块 这一次,我们使用 Webpack 来打包 Angular 2 的应用. 与官方的 Hello, Angular 2 项目 ...
- ExpressJs server中Router的设置
expressjs的路由设置方法 一.基本方法: app.METHOD(PATH, HANDLER)把路径path和操作方法method(可以是http的get/put/delete等),映射到一个处 ...
- messagePaneHost
Microsoft.Dynamics.Framework.UI.WinForms.Controls.MessageBarType messageBarType; super(); imageList ...
- iOS 为iPhone和iPad创建不同的storyboard
复制Main.storyboard,重命名为Main_iPad.storyboard 在info.plist文件中添加 Main storyboard file base name (iPad) -- ...
- Runtime的几个小例子(含Demo)
一.什么是runtime(也就是所谓的“运行时”,因为是在运行时实现的.) 1.runtime是一套底层的c语言API(包括很多强大实用的c语言类型,c语言函数); [runti ...
- Winform Textbox MultiLine和WordWrap属性的使用
突然用到,有些不明白,零乱记录下: 1.MultiLine属性为True时,Dock属性Fill值才能达到所需效果 2.MultiLine属性为False时,WordWrap属性也是无效果的,同1,T ...