首页> 搜索结果页
"a1528 网络" 检索
共 17 条结果
一个Oracle监听问题的网络排查
  今天在梳理一套环境的时候,发现了一个奇怪的问题,应用端连接正常,但是服务端却有些问题。    假设服务端的IP地址为10.129.128.57    使用tnsping本机的服务,竟然抛出了监听的问题。 $ tnsping s2gamebbs Attempting to contact (DESCRIPTION = (ADDRESS = (PROTOCOL = TCP)(HOST = s2gamebbs.test.com)(PORT = 1528)) (CONNECT_DATA = (SERVER = DEDICATED) (SERVICE_NAME = gamebbs))) TNS-12541: TNS:no listener    是监听没启动吗,查看监听进程存在,确实是启动了,但是查看监听状态却抛出了错误 LSNRCTL> status listener_1528 Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=s2gamebbs.test.com)(PORT=1528))) TNS-12541: TNS:no listener  TNS-12560: TNS:protocol adapter error   TNS-00511: No listener    Linux Error: 111: Connection refused 这个问题立马勾起了我的兴趣,我使用域名解析的方式查看是没有问题的。 $ ping `hostname` PING s2gamebbs.cyou.com (10.129.128.57) 56(84) bytes of data. 64 bytes from s2gamebbs.cyou.com (10.129.128.57): icmp_seq=1 ttl=64 time=0.059 ms 。。。 ^C 但是ping服务器的IP是有问题的。 # ping 10.129.128.57                                      PING 10.129.128.57 (10.129.128.57) 56(84) bytes of data.    From 10.129.128.57 icmp_seq=1 Destination Port Unreachable  From 10.129.128.57 icmp_seq=2 Destination Port Unreachable     如此一来,这个问题就有趣了,我对比了如下的几种测试场景。  # telnet 10.129.128.57 1528 Trying 10.129.128.57... telnet: connect to address 10.129.128.57: Connection refused #  telnet 127.0.0.1 1528 Trying 127.0.0.1... telnet: connect to address 127.0.0.1: Connection refused # telnet `hostname` 1528 Trying 10.129.128.57... telnet: connect to address 10.129.128.57: Connection refused 同时做了strace调试,也没有看到明显的问题,于是我怀疑是网络层面解析的问题,/etc/hosts的文件看了很多遍没有问题,那就只有网络层面,比如防火墙了,我开始琢磨防火墙里的配置。 看到了下面的一段: -A INPUT -s 10.10.75.59/32 -j ACCEPT -A INPUT -p udp -j ACCEPT -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT -A INPUT -j REJECT --reject-with icmp-port-unreachable 其中最后的一句是关键,如果倒数两句的顺序调整一下,上面的错误就会完全不一样。    这个参数其实的设定其实也是一种安全策略,如果能够扫描到我们的端口,但是却没法得知我们的网络访问是否在防火墙控制下,当然这个地方的设置伤害到“自己人”了。所以暂不需要。 去掉折后,重新启动防火墙,问题就得到了解决。
文章
Oracle  ·  关系型数据库  ·  网络安全  ·  网络协议  ·  域名解析  ·  Linux
2017-08-17
dg broker校验失败的一个奇怪问题(二)
对昨天提出的问题做了一个简单的分析和排查,也算是有了一个交代,上一篇文章在 dg broker校验失败的一个奇怪问题 http://blog.itpub.net/23718752/viewspace-2064499/ 我查看了最近的日志,发现在半个月以前有一行日志引起了我的注意。 Thu Mar 03 17:32:12 2016 ALTER SYSTEM SET log_archive_dest_state_2='DEFER' SCOPE=BOTH; 关于这个DEFER的设置,让我想起了之前的一个设置。 原来的主库发生了硬件电源故障,启用备用电源之后,勉强撑了几个小时,因为数据库之前使用的异机逻辑备份,恢复起来还是需要些时间,直接就找了台机器搭建了dataguard,然后做了switchover,把数据库迁移到了新的服务器上,然后在新的备库上又搭建了一套相应的dataguard环境,在搭建新的dataguard之前,原有存在电源故障的机器还是可用,但是因为硬件已经过保,就直接做了服务器退还。为了防止后续的归档检查失败,就设置了log_archive-dest_state_2=DEFER,搭建dataguard成功之后,就把服务器从dg broker里删除了。 所以从这个不起眼的过程来看,log_archive_dest_state有了三个状态的切换,defer,reset,enable 我们能不能简单复现一下这个问题,答案是肯定的。而且可以直接用这套环境来模拟一下。 首先dg broker检查没有任何问题。 DGMGRL> show configuration Configuration - testdb_dg   Protection Mode: MaxPerformance   Databases:     sactvdb  - Primary database     s2actvdb - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS 我们在主库设置归档路径状态为defer SQL> ALTER SYSTEM SET log_archive_dest_state_2=DEFER; System altered. 这个时候如果再次检查,dg broker就是下面的状态了。 DGMGRL> show configuration; Configuration - testdb_dg   Protection Mode: MaxPerformance   Databases:     sactvdb  - Primary database       Error: ORA-16764: redo transport service to a standby database is not running     s2actvdb - Physical standby database Fast-Start Failover: DISABLED Configuration Status: ERROR 然后我们把备库停掉。来看看主库的变化。 可以从主库日志看到下面的信息,自defer的日志之后,开始有了一些网络的检查,失败几次之后,在日志最后做了一个reset的操作。 ALTER SYSTEM SET log_archive_dest_state_2='DEFER' SCOPE=BOTH; Sat Mar 26 20:35:54 2016 *********************************************************************** Fatal NI connect error 12528, connecting to:  (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=xxxx)(PORT=1528)))(CONNECT_DATA=(SERVICE_NAME=s2actvdb_DGB)(CID=(PROGRAM=oracle)(HOST=testdb2.test.com)(USER=oracle))))   VERSION INFORMATION:         TNS for Linux: Version 11.2.0.3.0 - Production         TCP/IP NT Protocol Adapter for Linux: Version 11.2.0.3.0 - Production   Time: 26-MAR-2016 20:35:54   Tracing not turned on.   Tns error struct:     ns main err code: 12564      TNS-12564: TNS:connection refused     ns secondary err code: 0     nt main err code: 0     nt secondary err code: 0     nt OS err code: 0 *********************************************************************** Fatal NI connect error 12528, connecting to:  (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.127.130.58)(PORT=1528)))(CONNECT_DATA=(SERVICE_NAME=s2actvdb_DGB)(CID=(PROGRAM=oracle)(HOST=testdb2.test.com)(USER=oracle))))   VERSION INFORMATION:         TNS for Linux: Version 11.2.0.3.0 - Production         TCP/IP NT Protocol Adapter for Linux: Version 11.2.0.3.0 - Production   Time: 26-MAR-2016 20:35:54   Tracing not turned on.   Tns error struct:     ns main err code: 12564      TNS-12564: TNS:connection refused     ns secondary err code: 0     nt main err code: 0     nt secondary err code: 0     nt OS err code: 0 *********************************************************************** 。。。 LNS: Attempting destination LOG_ARCHIVE_DEST_2 network reconnect (3135) LNS: Destination LOG_ARCHIVE_DEST_2 network reconnect abandoned Error 3135 for archive log file 2 to 's2actvdb' Errors in file /U01/app/oracle/diag/rdbms/sactvdb/actvdb/trace/actvdb_nsa2_20231.trc: ORA-03135: connection lost contact LNS: Failed to archive log 2 thread 1 sequence 10137 (3135) Sat Mar 26 20:36:04 2016 *********************************************************************** 。。。      TNS-12564: TNS:connection refused     ns secondary err code: 0     nt main err code: 0     nt secondary err code: 0     nt OS err code: 0 Sat Mar 26 20:36:04 2016 ALTER SYSTEM SET log_archive_dest_state_2='RESET' SCOPE=BOTH;   然后重启备库到open状态,稍作等待,检查dg broker的状态,一切显示就正常了。 DGMGRL> show configuration; Configuration - testdb_dg   Protection Mode: MaxPerformance   Databases:     sactvdb  - Primary database     s2actvdb - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS 可以看到这个问题看起来比较清楚了,归档路径从defer变为了reset,然后变为了enable. 那么这个问题不设置defer,是否会出现reset的操作呢,能否复现,可以简单再测试一下。 再次停掉备库,然后查看主库的日志如下: Fatal NI connect error 12514, connecting to:  (DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=10.127.130.58)(PORT=1528)))(CONNECT_DATA=(SERVICE_NAME=s2actvdb_DGB)(CID=(PROGRAM=oracle)(HOST=testdb2.test.com)(USER=oracle))))   VERSION INFORMATION:         TNS for Linux: Version 11.2.0.3.0 - Production         TCP/IP NT Protocol Adapter for Linux: Version 11.2.0.3.0 - Production   Time: 26-MAR-2016 20:41:48   Tracing not turned on.   Tns error struct:     ns main err code: 12564      TNS-12564: TNS:connection refused     ns secondary err code: 0     nt main err code: 0     nt secondary err code: 0     nt OS err code: 0 Sat Mar 26 20:41:48 2016 ALTER SYSTEM SET log_archive_dest_state_2='RESET' SCOPE=BOTH; 可以看到,日志末尾会有reset的字样,所以说和之前的defer是没有直接关系,dg broker的配置下,这是一个状态的自动变化。 那么备库停掉之后,再次重启是否会有dg broker中备库为disable的状态呢。 DGMGRL> show configuration; Configuration - testdb_dg   Protection Mode: MaxPerformance   Databases:     sactvdb  - Primary database     s2actvdb - Physical standby database (disabled) Fast-Start Failover: DISABLED Configuration Status: SUCCESS 可以简单复现问题,那就是备库在nomount状态,11g环境中,mount,open状态下都没有此类问题,也是因为这个时候备库的RFS,MRP可以正常工作。 复现过程如下: 重启备库到nomount状态 DGMGRL> show configuration; Configuration - testdb_dg   Protection Mode: MaxPerformance   Databases:     sactvdb  - Primary database     s2actvdb - Physical standby database (disabled) Fast-Start Failover: DISABLED Configuration Status: SUCCESS 启动备库到mount DGMGRL> show configuration; Configuration - testdb_dg   Protection Mode: MaxPerformance   Databases:     sactvdb  - Primary database     s2actvdb - Physical standby database Fast-Start Failover: DISABLED Configuration Status: SUCCESS 所以通过以上的测试复现,可以看到这个问题其实不奇怪,备库重启,但是备库在nomount阶段导致了这个奇怪的现象,但是对于dataguard而言,归档路径的状态有defer,reset,enable几种情况,可能会以reset为一个临界点来做转换。
文章
监控  ·  关系型数据库  ·  Linux  ·  数据库  ·  Windows
2016-03-27
io_uring vs epoll ,谁在网络编程领域更胜一筹?
本文作者:王小光,「高性能存储技术SIG」核心成员。背景io_uring 在传统存储 io 场景已经证明其价值,但 io_uring 不仅支持传统存储 io,也支持网络 io。io_uring 社区有众多的开发者尝试将 io_uring 用于网络应用。我们之前也在《你认为 io_uring 只适用于存储 IO?大错特错!》中也探索过 io_uring 在网络场景的应用及其与传统网络编程基石 epoll 的对比,当时我们的测试结果显示在 cpu 漏洞缓解使能的前提下,io_uring 相比于 epoll 可以带来一定的优势,在 cpu 漏铜缓解未使能时,io_uring 相比于 epoll 没有优势,可能还会存在性能下降。在 io_uring 社区,关于 io_uring 和 epoll 孰优孰劣也一直存在争论,有些开发者宣称 io_uring 可以获得比 epoll 更好的性能,有些开发者则宣称二者性能持平或者 io_uring 甚至不如 epoll。相关的讨论非常多,具体可参见如下两例:https://github.com/axboe/liburing/issues/189https://github.com/frevib/io_uring-echo-server/issues/8以上讨论从 2020 年 8 月一直持续到现在,其过程非常长也非常地激烈。可以看出 io_uring 和 epoll 在网络编程领域孰优孰劣目前确实比较难以达成共识。目前很多业务想将 io_uring 在网络场景应用起来,但 io_uring 是否能比 epoll 带来性能提升,大家或多或少存在些许疑问。为了彻底厘清这个问题,龙蜥社区高性能存储 SIG尝试从定量分析的角度,通过量化 io_uring 和 epoll 两种编程框架下的相关操作的耗时,来分析二者的性能差异。评估模型我们仍然选用 echo server 模型进行性能评估,server 端采用单线程模型,同时为公平对比,io_uring 不使用内部的 io-wq 机制(io_uring 在内核态维护的线程池,可以用来执行用户提交的 io 请求)。epoll 采用 send(2) 和 recv(2) 进行数据的读写操作;而 io_uring 采用 IORING_OP_SEND 和 IORING_OP_RECV 进行数据的读写操作。结合 echo server 的模型,我们分析有四个因素会影响 io_uring 和 epoll 的性能,分别是: 1、系统调用用户态到内核态上下文切换开销,记为 s; 2、系统调用自身内核态工作逻辑开销,记为 w; 3、io_uring 框架本身开销,记为 o;4、io_uring 的 batch 量,记为 n,epoll 版 echo server 由于直接调用 recv(2) 和 send(2), 其 batch 实际为 1。同时在本文中我们仅评估 io_uring 和 epoll 请求读写操作的开销,对于 io_uring 和 epoll 本身的事件通知机制本身不做衡量,因为通过 perf 工具分析,读写请求本身开销占据绝大部分。系统调用用户态到内核态上下文切换开销可以通过专门的程序进行测量,因素 2、3、4 等可以通过衡量内核相关函数的执行时间进行测量,用 bpftrace 进行分析。epoll 版 echo server 开销度量从用户态视角,send(2) 或者 recv(2) 开销主要包含两个方面,系统调用用户态到内核态上下文切换开销和系统调用自身内核态工作逻辑开销,其中系统调用本身工作逻辑的开销,send(2) 和 recv(2) 分别衡量 sys_sendto(), sys_recvfrom() 即可。由于 epoll 场景下其系统调用的 batch 为 1,因此 epoll  模型下收发请求的平均耗时为 (s + w)。io_uring 版 echo server 开销度量io_uring 中 io_uring_enter(2) 系统调用既可以用来提交 sqe,也可以用来 reap cqe,两种操作混合在一个系统调用中,准确衡量 sqe 的提交收发请求的耗时比较困难。简单起见,我们采用跟踪 io_submit_sqes() 的开销来衡量 IORING_OP_SEND 和 IORING_OP_RECV 的开销,此函数被 io_uring_enter(2) 所调用。io_submit_sqes() 包含send(2) 和 revc(2) 内核侧工作逻辑开销,及 io_uring 框架的开销,记为 t。同时我们采用 io_uring 的 multi-shot 模式,从而确保 io_submit_sqes() 中的提交的 IORING_OP_SEND 和 IORING_OP_RECV 请求都可以直接完成,而不会用到io_uring的 task-work 机制。由于 io_uring 场景下可以 batch 系统调用的执行,因此 io_uirng 模型下收发请求的平均耗时为 (s + t) / n。实际度量我们测试环境 Intel(R) Xeon(R) CPU E5-2682 v4 @ 2.50GHz,衡量 echo server 单链接性能数据。用户态内核态系统调用上下文切换开销cpu 漏洞对系统调用用户态内核态上下文切换的影响比较大,在我们的测试环境中:漏铜缓解使能时,系统调用的上下文切换开销为 700ns 左右;漏铜缓解未使能时,系统调用的上下文切换开销为 230ns 左右。epoll 模型下 send(2)/recv(2) 内核侧开销采用bpftrace 脚本分别衡量 sys_sendto(),sys_recvfrom() 即可。 bpftrace 脚本如下:BEGIN { @start = 0; @send_time = 0; @send_count = 0; } kprobe:__sys_sendto /comm == "epoll_echo_serv"/ { @start = nsecs; } kprobe:__sys_recvfrom /comm == "epoll_echo_serv"/ { @start = nsecs; } kretprobe:__sys_sendto /comm == "epoll_echo_serv"/ { if (@start > 0) { @delay = nsecs - @start; @send_time = @delay + @send_time; @send_count = @send_count + 1; } } kretprobe:__sys_recvfrom /comm == "epoll_echo_serv"/ { if (@start > 0) { @delay = nsecs - @start; @send_time = @delay + @send_time; @send_count = @send_count + 1; } } interval:s:5 { printf("time: %llu\n", @send_time / @send_count); @send_time = 0; @send_count = 0; }在单连接,包大小 16 字节场景下,epoll 版的 echo_server 的 tps 在 1000 左右,其 recv(2) 和 send(2) 的内核侧逻辑平均开销如下:time: 1489、time: 1492、time: 1484、time: 1491、time: 1499、time: 1505、time: 1512、time: 1528、time: 1493、time: 1509、time: 1495、time: 1499、time: 1544从上述数据可以看出,send(2) 和 recv(2) 的内核侧平均开销在1500ns左右,因此:1) cpu 漏洞缓解,send(2) 和 recv(2) 的平均开销为 s=700ns,w=1500ns,总共 (s+w) = 2200ns。 2) cpu 漏洞为缓解,send(2) 和 recv(2) 的平均开销为 s=230ns,w=1500ns,总共 (s+w) = 1730ns。 io_uring 模型下 io_uring_enter(2) 内核侧开销采用bpftrace 脚本分别衡量 io_submit_sqes() 开销即可。BEGIN { @start = 0; @send_time = 0; @send_count = 0; } kprobe:io_submit_sqes /comm == "io_uring_echo_s"/ { @start = nsecs; @send_count = @send_count + arg1; } kretprobe:io_submit_sqes /comm == "io_uring_echo_s"/ { if (@start > 0) { @delay = nsecs - @start; @send_time = @delay + @send_time; } } interval:s:5 { printf("time: %llu\n", @send_time / @send_count); @send_time = 0; @send_count = 0; }运行类似上述 epoll 同样的测试,数据为:time: 1892、time: 1901、time: 1901、time: 1882、time: 1890、time: 1936、time: 1960、time: 1907、time: 1896、time: 1897、time: 1911、time: 1897、time: 1891、time: 1893、time: 1918、time: 1895、time: 1885从上述数据可以看出,io_submit_sqes() 的内核侧平均开销在 1900ns 左右,注意此时的batch n=1,且该开销包括收发请求的内核态工作逻辑开销及 io_uring 框架开销。1) cpu 漏洞缓解,用户态观察到的 io_uring_enter(2) 平均开销为 t=1900ns,n=1,s=700ns,总共 (t+s) / n = 2600ns。2) cpu 漏洞未缓解,用户态观察到的 io_uring_enter(2) 的平均开销为 t=1900ns,n=1,s=230ns,总共 (t+s) / n = 2130ns。注意由于我们实际只 trace io_submit_sqes,而 io_uring_enter(2) 系统调用是调用 io_submit_sqes 的,因此 io_uring_enter(2) 的实际开销是肯定大于 (t+s) / n。数据量化分析从上述数据发现,cpu 漏洞确实对系统调用的性能影响较大,尤其对于小数据包的场景,我们分别讨论下:cpu 漏洞缓解未使能epoll: s+w,  io_uring: (t+s) / n  可以看出在此种情况下,由于 t 大于 w, 即使扩大 batch,io_uring 的性能也不如 epoll。cpu 漏洞缓解使能epoll: s+w,  io_uring: (t+s) / n  可以看出在此种情况下,由于 s 比较大,当 batch 比较低时,io_uring 不如 epoll,但当 batch 比较大时,io_uring 场景下系统调用上下文切换开销被极大摊薄,此时 io_uring 的性能是优于 epoll。在我们的实际测试中,1000连接时,io_uring 的的吞吐要比 epoll 高 10% 左右,基本符合我们的建模。结论从我们的量化分析可以看出 io_uring 与 epoll 孰优孰劣完全由评估模型中定义的 4 个变量决定:epoll: s + wio_uring: (t + s) / n如果某个变量占主导地位,则性能数据会截然不同。举个例子,假设系统调用上下文切换开销 s 很大,而且 io_uring batch n 也很大,则 io_uring 在此种场景下的性能肯定是会比 epoll 好;再比如系统内核侧开销 w 很大,此时 io_uring 和 epoll 性能会接近。因此 io_uring 和 epoll 孰优孰劣,取决于其应用场景,我们建议的最佳实践是基于业务真实网络模型,将其简化为 echo server 模型,运行我们的度量脚本,从而可以评估二者在真实环境的性能,以指导真实应用开发。同时上述度量数据也为我们的性能优化提供方向,我们可以尽可能的减少某一变量的开销,从而提高性能,比如可以进一步优化 io_uring 框架的开销。高性能存储技术SIG介绍高性能存储技术SIG :致力于存储栈性能挖掘化,打造标准的高性能存储技术软件栈,推动软硬件协同发展。欢迎更多开发者加入SIG:网址:https://openanolis.cn/sig/high-perf-storage邮件列表:storage@lists.openanolis.cn—— 完 ——加入龙蜥社群加入微信群:添加社区助理-龙蜥社区小龙(微信:openanolis_assis),备注【龙蜥】拉你入群;加入钉钉群:扫描下方钉钉群二维码。欢迎开发者/用户加入龙蜥社区(OpenAnolis)交流,共同推进龙蜥社区的发展,一起打造一个活跃的、健康的开源操作系统生态!关于龙蜥社区龙蜥社区(OpenAnolis)是由企事业单位、高等院校、科研单位、非营利性组织、个人等按照自愿、平等、开源、协作的基础上组成的非盈利性开源社区。龙蜥社区成立于 2020 年 9 月,旨在构建一个开源、中立、开放的Linux上游发行版社区及创新平台。短期目标是开发龙蜥操作系统(Anolis OS)作为 CentOS 替代版,重新构建一个兼容国际 Linux 主流厂商发行版。中长期目标是探索打造一个面向未来的操作系统,建立统一的开源操作系统生态,孵化创新开源项目,繁荣开源生态。龙蜥OS 8.4已发布,支持 x86_64 、ARM64、LoongArch 架构,完善适配 Intel、飞腾、海光、兆芯、鲲鹏、龙芯等芯片,并提供全栈国密支持。欢迎下载:https://openanolis.cn/download加入我们,一起打造面向未来的开源操作系统!https://openanolis.cn
文章
存储  ·  安全  ·  Java  ·  Linux  ·  测试技术  ·  开发者  ·  芯片  ·  C++
2021-12-16
IOS开发笔记
1 iphone开发笔记 2 3 退回输入键盘 4 - (BOOL) textFieldShouldReturn:(id)textField{ 5 [textField resignFirstResponder]; 6 } 7 8 CGRect 9 CGRect frame = CGRectMake (origin.x, origin.y, size.width, size.height);矩形 10 NSStringFromCGRect(someCG) 把CGRect结构转变为格式化字符串; 11 CGRectFromString(aString) 由字符串恢复出矩形; 12 CGRectInset(aRect) 创建较小或较大的矩形(中心点相同),+较小 -较大 13 CGRectIntersectsRect(rect1, rect2) 判断两矩形是否交叉,是否重叠 14 CGRectZero 高度和宽度为零的/位于(0,0)的矩形常量 15 16 CGPoint & CGSize 17 CGPoint aPoint = CGPointMake(x, y); 18 CGSize aSize = CGSizeMake(width, height); 19 20 设置透明度 21 [myView setAlpha:value]; (0.0 < value < 1.0) 22 23 设置背景色 24 [myView setBackgroundColor:[UIColor redColor]]; 25 (blackColor;darkGrayColor;lightGrayColor; 26 whiteColor;grayColor; redColor; greenColor; 27 blueColor; cyanColor;yellowColor; 28 magentaColor;orangeColor;purpleColor; 29 brownColor; clearColor; ) 30 31 自定义颜色 32 UIColor *newColor = [[UIColor alloc] 33 initWithRed:(float) green:(float) blue:(float) alpha:(float)]; 34 0.0~1.0 35 36 竖屏 37 320X480 38 39 横屏 40 480X320 41 42 状态栏高 (显示时间和网络状态) 43 20 像素 44 45 导航栏、工具栏高(返回) 46 44像素 47 48 隐藏状态栏 49 [[UIApplication shareApplication] setStatusBarHidden: YES animated:NO] 50 51 横屏 52 [[UIApplication shareApplication] 53 setStatusBarOrientation:UIInterfaceOrientationLandscapeRight]. 54 55 屏幕变动检测 56 orientation == UIInterfaceOrientationLandscapeLeft 57 58 全屏 59 window=[[UIWindow alloc] initWithFrame:[UIScreen mainScreen] bounds]; 60 61 自动适应父视图大小: 62 aView.autoresizingSubviews = YES; 63 aView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | 64 UIViewAutoresizingFlexibleHeight); 65 66 定义按钮 67 UIButton *scaleUpButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 68 [scaleUpButton setTitle:@"放 大" forState:UIControlStateNormal]; 69 scaleUpButton.frame = CGRectMake(40, 420, 100, 40); 70 [scaleUpButton addTarget:self 71 action:@selector(scaleUp) 72 forControlEvents:UIControlEventTouchUpInside]; 73 74 设置视图背景图片 75 UIImageView *aView; 76 [aView setImage:[UIImage imageNamed:@”name.png”]]; 77 view1.backgroundColor = [UIColor colorWithPatternImage: 78 [UIImage imageNamed:@"image1.png"]]; 79 80 自定义UISlider的样式和滑块 81 82 我们使用的是UISlider的setMinimumTrackImage,和setMaximumTrackImage方法来定义图片的,这两个方法可以设置滑块左边和右边的图片的,不过如果用的是同一张图片且宽度和控件宽度基本一致,就不会有变形拉伸的后果,先看代码,写在 viewDidLoad中: 83 //左右轨的图片 84 UIImage *stetchLeftTrack= [UIImage imageNamed:@"brightness_bar.png"]; 85 UIImage *stetchRightTrack = [UIImage imageNamed:@"brightness_bar.png"]; 86 //滑块图片 87 UIImage *thumbImage = [UIImage imageNamed:@"mark.png"]; 88 89 UISlider *sliderA=[[UISlider alloc]initWithFrame:CGRectMake(30, 320, 257, 7)]; 90 sliderA.backgroundColor = [UIColor clearColor]; 91 sliderA.value=1.0; 92 sliderA.minimumValue=0.7; 93 sliderA.maximumValue=1.0; 94 95 [sliderA setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal]; 96 [sliderA setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal]; 97 //注意这里要加UIControlStateHightlighted的状态,否则当拖动滑块时滑块将变成原生的控件 98 [sliderA setThumbImage:thumbImage forState:UIControlStateHighlighted]; 99 [sliderA setThumbImage:thumbImage forState:UIControlStateNormal]; 100 //滑块拖动时的事件 101 [sliderA addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; 102 //滑动拖动后的事件 103 [sliderA addTarget:self action:@selector(sliderDragUp:) forControlEvents:UIControlEventTouchUpInside]; 104 105 [self.view addSubview:sliderA]; 106 107 为了大家实验方便,我附上背景图brightness_bar.png和滑块图mark.png 108 http://pic002.cnblogs.com/images/2011/162291/2011121611431816.png 109 http://pic002.cnblogs.com/images/2011/162291/2011121611432897.png 110 111 -(IBAction)sliderValueChanged:(id)sender{ 112 UISlider *slider = (UISlider *) sender; 113 NSString *newText = [[NSString alloc] initWithFormat:@”%d”, (int)(slider.value + 0.5f)]; 114 label.text = newText; 115 } 116 117 活动表单 118 <UIActionSheetDelegate> 119 120 - (IBActive) someButtonPressed:(id) sender 121 { 122 UIActionSheet *actionSheet = [[UIActionSheet alloc] 123 initWithTitle:@”Are you sure?” 124 delegate:self 125 cancelButtonTitle:@”No way!” 126 destructiveButtonTitle:@”Yes, I’m Sure!” 127 otherButtonTitles:nil]; 128 [actionSheet showInView:self.view]; 129 [actionSheet release]; 130 } 131 132 警告视图 133 <UIAlertViewDelegate> 134 135 - (void) actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger) buttonIndex 136 { 137 if(buttonIndex != [actionSheet cancelButtonIndex]) 138 { 139 NSString *message = [[NSString alloc] initWithFormat:@”You can 140 breathe easy, everything went OK.”]; 141 UIAlertView *alert = [[UIAlertView alloc] 142 initWithTitle:@”Something was done” 143 message:message 144 delegate:self 145 cancelButtonTitle:@”OK” 146 otherButtonTitles:nil]; 147 [alert show]; 148 [alert release]; 149 [message release]; 150 } 151 } 152 153 动画效果 154 -(void)doChange:(id)sender 155 { 156 if(view2 == nil) 157 { 158 [self loadSec]; 159 } 160 [UIView beginAnimations:nil context:NULL]; 161 [UIView setAnimationDuration:1]; 162 [UIView setAnimationTransition:([view1 superview]?UIViewAnimationTransitionFlipFromLeft:UIViewAnimationTransitionFlipFromRight)forView:self.view cache:YES]; 163 164 if([view1 superview]!= nil) 165 { 166 [view1 removeFromSuperview]; 167 [self.view addSubview:view2]; 168 169 }else { 170 171 [view2 removeFromSuperview]; 172 [self.view addSubview:view1]; 173 } 174 [UIView commitAnimations]; 175 } 176 177 Table View <UITableViewDateSource> 178 #pragma mark - 179 #pragma mark Table View Data Source Methods 180 //指定分区中的行数,默认为1 181 - (NSInteger)tableView:(UITableView *)tableView 182 numberOfRowsInSection:(NSInteger)section 183 { 184 return [self.listData count]; 185 } 186 187 //设置每一行cell显示的内容 188 - (UITableViewCell *)tableView:(UITableView *)tableView 189 cellForRowAtIndexPath:(NSIndexPath *)indexPath 190 { 191 static NSString *SimpleTableIndentifier = @"SimpleTableIndentifier"; 192 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIndentifier]; 193 if (cell == nil) { 194 cell = [[[UITableViewCell alloc] 195 initWithStyle:UITableViewCellStyleSubtitle 196 reuseIdentifier:SimpleTableIndentifier] 197 autorelease]; 198 } 199 UIImage *image = [UIImage imageNamed:@"13.gif"]; 200 cell.imageView.image = image; 201 202 NSUInteger row = [indexPath row]; 203 cell.textLabel.text = [listData objectAtIndex:row]; 204 cell.textLabel.font = [UIFont boldSystemFontOfSize:20]; 205 206 if(row < 5) 207 cell.detailTextLabel.text = @"Best friends"; 208 else 209 cell.detailTextLabel.text = @"friends"; 210 return cell; 211 } 212 213 图像、文本标签和详细文本标签 214 215 图像:如果设置图像,则它显示在文本的左侧; 文本标签:这是单元的主要文本(UITableViewCellStyleDefault 只显示文本标签);详细文本标签:这是单元的辅助文本,通常用作解释性说明或标签 216 217 UITableViewCellStyleSubtitle 218 UITableViewCellStyleDefault 219 UITableViewCellStyleValue1 220 UITableViewCellStyleValue2 221 222 <UITableViewDelegate> 223 #pragma mark - 224 #pragma mark Table View Delegate Methods 225 //把每一行缩进级别设置为其行号 226 - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath 227 { 228 NSUInteger row = [indexPath row]; 229 return row; 230 } 231 //获取传递过来的indexPath值 232 - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath 233 { 234 NSUInteger row = [indexPath row]; 235 if (row == 0) 236 return nil; 237 return indexPath; 238 } 239 240 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 241 { 242 NSUInteger row = [indexPath row]; 243 NSString *rowValue = [listData objectAtIndex:row]; 244 NSString *message = [[NSString alloc] initWithFormat:@"You selected %@",rowValue]; 245 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Row Selected" 246 message:message 247 delegate:nil 248 cancelButtonTitle:@"Yes, I did!" 249 otherButtonTitles:nil]; 250 [alert show]; 251 [alert release]; 252 [message release]; 253 [tableView deselectRowAtIndexPath:indexPath animated:YES]; 254 } 255 256 //设置行的高度 257 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 258 { 259 return 40; 260 } 261 262 NavigationController 推出push 推出pop 263 [self.navigationController pushViewController:_detailController animated:YES]; 264 [self.navigationController popViewControllerAnimated:YES]; 265 266 Debug: 267 NSLog(@"%s %d", __FUNCTION__, __LINE__); 268 269 点击textField外的地方回收键盘 270 271 先定义一个UIControl类型的对象,在上面可以添加触发事件,令SEL实践为回收键盘的方法,最后将UIControl的实例加到当前View上。 272 UIControl *m_control = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; 273 [m_control addTarget:self action:@selector(keyboardReturn) 274 forControlEvents:UIControlEventTouchUpInside]; 275 [self.view addSubview:m_control]; 276 277 - (void) keyboardReturn 278 { 279 [aTextField resignFirstResponder]; 280 } 281 282 键盘覆盖输入框 283 当键盘调出时将输入框覆盖时,可以用下方法: 284 - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField 285 { 286 [self.view setFrame:CGRectMake(0, -100, 320, 480) ]; 287 return YES; 288 } 289 - (BOOL)textFieldShouldEndEditing:(UITextField *)textField 290 { 291 [self.view setFrame:CGRectMake(0, 0, 320, 480)]; 292 return YES; 293 } 294 当准备输入时,将视图的位置上调100,这样键盘就不能覆盖到输入框。 295 296 当依赖注入方法不好使时,可以在AppDelegate内申明一个全局的控制器实例_anotherViewController,在另一个需要使用_anotherViewController的地方定义以下委托方法,使用共享的UIApplication实例来获取该委托的引用 297 SomeAppDelegate *appDelegate = (SomeAppDelegate *)[[UIApplication sharedApplication] delegate]; 298 _anotherViewController = appDelegate._anotherViewController; 299 300 UIViewController内建Table View 301 302 纯代码在UIViewController控制器内建Table View 303 @interface RootViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { 304 NSArray *timeZoneNames; 305 } 306 @property (nonatomic,retain) NSArray *timeZoneNames; 307 @end 308 309 (void) loadView 310 { 311 UITableView *tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] style: UITableViewStylePlain]; 312 tableView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingWidth); 313 tableView.delegate = self; 314 tableView.dataSource = self; 315 [tableView reloadData]; 316 317 self.view = tableView; 318 [tableView release]; 319 } 320 321 322 将plist文件中的数据赋给数组 323 NSString *thePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"]; 324 NSArray *array = [NSArray arrayWithContentsOfFile:thePath]; 325 326 UITouch 327 手指的触摸范围:64X64 328 329 #pragma mark - 330 #pragma mark Touch Events 331 332 - (void)touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event { 333 originFrame = bookCover.frame; 334 NSLog(@"%s %d", __FUNCTION__,__LINE__); 335 336 if ([touches count] == 2) 337 { 338 NSArray *twoTouches = [touches allObjects]; 339 UITouch *firstTouch = [twoTouches objectAtIndex:0]; 340 UITouch *secondTouch = [twoTouches objectAtIndex:1]; 341 CGPoint firstPoint = [firstTouch locationInView:bookCover]; 342 CGPoint secondPoint = [secondTouch locationInView:bookCover]; 343 344 CGFloat deltaX = secondPoint.x - firstPoint.x; 345 CGFloat deltaY = secondPoint.y - firstPoint.y; 346 initialDistance = sqrt(deltaX * deltaX + deltaY * deltaY ); 347 frameX = bookCover.frame.origin.x; 348 frameY = bookCover.frame.origin.y; 349 frameW = bookCover.frame.size.width; 350 frameH = bookCover.frame.size.height; 351 NSLog(@"%s %d", __FUNCTION__,__LINE__); 352 } 353 } 354 355 - (void)touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event { 356 357 if([touches count] == 2) 358 { 359 NSLog(@"%s %d", __FUNCTION__,__LINE__); 360 361 NSArray *twoTouches = [touches allObjects]; 362 UITouch *firstTouch = [twoTouches objectAtIndex:0]; 363 UITouch *secondTouch = [twoTouches objectAtIndex:1]; 364 365 CGPoint firstPoint = [firstTouch locationInView:bookCover]; 366 CGPoint secondPoint = [secondTouch locationInView:bookCover]; 367 368 CGFloat deltaX = secondPoint.x - firstPoint.x; 369 CGFloat deltaY = secondPoint.y - firstPoint.y; 370 CGFloat currentDistance = sqrt(deltaX * deltaX + deltaY * deltaY ); 371 372 if (initialDistance == 0) { 373 initialDistance = currentDistance; 374 } 375 else if (currentDistance != initialDistance) 376 { 377 CGFloat changedDistance = currentDistance - initialDistance; 378 NSLog(@"changedDistance = %f",changedDistance); 379 [bookCover setFrame:CGRectMake(frameX - changedDistance / 2, 380 frameY - (changedDistance * frameH) / (2 * frameW), 381 frameW + changedDistance, 382 frameH + (changedDistance * frameH) / frameW)]; 383 } 384 } 385 } 386 387 - (void)touchesEnded:(NSSet *) touches withEvent:(UIEvent *) event { 388 UITouch *touch = [touches anyObject]; 389 390 UITouch双击图片变大/还原 391 if ([touch tapCount] == 2) 392 { 393 NSLog(@"%s %d", __FUNCTION__,__LINE__); 394 395 if (!flag) { 396 [bookCover setFrame:CGRectMake(bookCover.frame.origin.x - bookCover.frame.size.width / 2, 397 bookCover.frame.origin.y - bookCover.frame.size.height / 2, 398 2 * bookCover.frame.size.width, 399 2 * bookCover.frame.size.height)]; 400 flag = YES; 401 } 402 else { 403 [bookCover setFrame:CGRectMake(bookCover.frame.origin.x + bookCover.frame.size.width / 4, bookCover.frame.origin.y + bookCover.frame.size.height / 4, 404 bookCover.frame.size.width / 2, bookCover.frame.size.height / 2)]; 405 flag = NO; 406 } 407 } 408 } 409 410 Get the Location of Touches 411 (CGPoint)locationInView:(UIView *)view 412 (CGPoint)previousLocationInView:(UIView *)view 413 view window 414 415 Getting Touch Attributes 416 tapCount(read only) timestamp(read only) phase(read only) 417 418 Getting a Touch Object's Gesture Recognizers 419 gestureRecognizers 420 421 Touch Phase 422 UITouchPhaseBegan 423 UITouchPhaseMoved 424 UITouchPhaseStationary 425 UITouchPhaseEnded 426 UITouchPhaseCancelled 427 428 从Plist里读内容 429 NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"book" ofType:@"plist"]; 430 NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; 431 NSString *book = [dictionary objectForKey:bookTitle]; 432 [textView setText:book]; 433 434 (void) initialize { 435 NSUserDefaults = [NSUserDefaults standardUserDefaults]; 436 NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"YES" forKey:@"DeleteBackup"]; 437 [defaults registerDefaults:appDefaults]; 438 } 439 440 To get a value of a default, use the valueForKey: method: 441 [[theDefaultsController values] valueForKey:@"userName"]; 442 To set a value for a default, use setValue:forKey: 443 [[theDefaultsController values] setValue:newUserName forKey:@"userName"]; 444 445 [[NSUserDefaults standardUserDefaults] setValue:aVale forKey:aKey]; 446 [[NSUserDefaults standardUserDefaults] valueForKey:aKey]; 447 448 获取Documents目录 449 NSArray *paths = NSSearchPathForDictionariesInDomains(NSDocumentDirectory, 450 NSUserDomainMask, YES); 451 NSString *documentsDirectory = [paths objectAtIndex:0]; 452 NSString *filename = [documentsDirectory 453 stringByAppendingPathComponent:@"theFile.txt"]; 454 455 获取tmp目录 456 NSString *tempPath = NSTemporaryDirectory(); 457 NSString *tempFile = [tempPath stringByAppendingPathComponent:@"tempFile.txt"]; 458 459 [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"someKey"]; 460 [[NSUserDefaults standardUserDefaults] objectForKey:aKey]; 461 462 自定义NavigationBar 463 navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; 464 [navigationBar setBarStyle:UIBarStyleBlackOpaque]; 465 466 myNavigationItem = [[UINavigationItem alloc] initWithTitle:@"Setting"]; 467 [navigationBar setItems:[NSArray arrayWithObject:myNavigationItem]]; 468 [self.view addSubview:navigationBar]; 469 470 backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(back)]; 471 myNavigationItem.leftBarButtonItem = backButton; 472 473 474 利用Safari打开一个链接 475 NSURL *url = [NSURL URLWithString:@"http://www.cnblogs.com/tracy-e/"]; 476 [[UIApplication sharedApplication] openURL:url]; 477 478 利用UIWebView显示pdf文件、网页。。。 479 webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; 480 [webView setDelegate:self]; 481 [webView setScalesPageToFit:YES]; 482 [webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 483 [webView setAllowsInlineMediaPlayback:YES]; 484 [self.view addSubview:webView]; 485 NSString *pdfPath = [[NSBundle mainBundle] pathForResource:@"ojc" ofType:@"pdf"]; 486 NSURL *url = [NSURL fileURLWithPath:pdfPath]; 487 NSURLRequest *request = [NSURLRequest requestWithURL:url 488 cachePolicy:NSURLRequestUseProtocolCachePolicy 489 timeoutInterval:5]; 490 [webView loadRequest:request]; 491 492 493 [myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL 494 URLWithString: @"http://www.cnblogs.com/tracy-e/"]]]; 495 496 NSString *errorString = [NSString stringWithFormat:@"<html><center><font size= 497 +5 color ='red'>An Error Occurred:<br>%@</fone></center></html>",error]; 498 [myWebView loadHTMLString:errorString baseURL:nil]; 499 500 //Stopping a load request when the view is to disappear 501 - (void)viewWillDisappear:(BOOL)animate{ 502 if ([myWebView loading]){ 503 [myWebView stopLoading]; 504 } 505 myWebView.delegate = nil; 506 [UIApplication shareApplication].networkActivityIndicatorVisible = NO; 507 } 508 509 汉字转码 510 NSString *oriString = @"\u67aa\u738b"; 511 NSString *escapedString = [oriString 512 stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; 513 514 515 Checking for background support on earlier versions of iOS 516 UIDevice *device = [UIDevice currentDevice]; 517 BOOL backgroundSupported = NO; 518 if ([device respondsToSelector:@selector(isMultitaskingSupported)]){ 519 backgroundSupported = device.multitaskingSupported; 520 } 521 522 Being a Responsible,Multitasking-Aware Application 523 # Do not make any OpenGL ES calls from your code. 524 # Cancel any Bonjour-related services before being suspended. 525 # Be prepared to handle connection failures in your network-based sockets. 526 # Save your application state before moving to the background. 527 # Release any unneeded memory when moving to the background. 528 # Stop using shared system resources before being suspended. 529 # Avoid updating your windows and views. 530 # Respond to connect and disconnect notification for external accessories. 531 # Clean up resource for active alerts when moving to the background. 532 # Remove sensitive information from views before moving to the background. 533 # Do minimal work while running in the background. 534 535 Handing the Keyboard notifications 536 //Call this method somewhere in your view controller setup code 537 - (void) registerForKeyboardNotifications{ 538 539 [[NSNotificationCenter defaultCenter] addObserver:self 540 selector:@selector(keyboardWasShown:) 541 name:UIKeyboardDidShowNotification 542 object:nil]; 543 [[NSNotificationCenter defaultCenter] addObserver:self 544 selector:@selector(keyboardWasHidden:) 545 name:UIKeyboardDidHideNotification 546 object:nil]; 547 548 } 549 550 //Called when the UIKeyboardDidShowNotification is sent 551 - (void)keyboardWasShown:(NSNotification *) aNotification{ 552 if(keyboardShown) 553 return; 554 NSDictionary *info = [aNotification userInfo]; 555 556 //get the size of the keyboard. 557 NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey]; 558 CGSize keyboardSize = [aValue CGRectValue].size; 559 560 //Resize the scroll view 561 CGRect viewFrame = [scrollView frame]; 562 viewFrame.size.height -= keyboardSize.height; 563 564 //Scroll the active text field into view 565 CGRect textFieldRect = [activeField frame]; 566 [scrollView scrollRectToVisible:textFieldRect animated:YES]; 567 568 keyboardShown = YES; 569 } 570 571 //Called when the UIKeyboardDidHideNotification is sent 572 - (void)keyboardWasHidden:(NSNotification *) aNotification{ 573 NSDictionary *info = [aNotification userInfo]; 574 575 //Get the size of the keyboard. 576 NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey]; 577 CGSize keyboardSize = [aValue CGRectValue].size; 578 579 //Reset the height of the scroll view to its original value 580 CGRect viewFrame = [scrollView Frame]; 581 viewFrame.size.height += keyboardSize.height; 582 scrollView.frame = viewFrame; 583 584 keyboardShown = NO; 585 } 586 587 点击键盘的next按钮,在不同的textField之间换行 588 //首先给不同的textField赋不同的且相邻的tag值 589 - (BOOL)textFieldShouldReturn:(UITextField *)textField 590 { 591 if ([textField returnKeyType] != UIReturnKeyDone) 592 { 593 NSInteger nextTag = [textField tag] + 1; 594 UIView *nextTextField = [[self tableView] viewWithTag:nextTag]; 595 [nextTextField becomeFirstResponder]; 596 } 597 else { 598 [textField resignFirstResponder]; 599 } 600 return YES; 601 } 602 603 Configuring a date formatter 604 - (void)viewDidLoad { 605 [super viewDidLoad]; 606 dateFormatter = [[NSDateFormatter alloc] init]; 607 [dateFormatter setGeneratesCalendarDates:YES]; 608 [dateFormatter setLocale:[NSLocale currentLocale]]; 609 [dateFormatter setCalendar:[NSCalendar autoupdatingCurrentCalendar]]; 610 [dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]]; 611 [dateFormatter setDateStyle:NSDateFormatterShortStyle]; 612 DOB.placeholder = [NSString stringWithFormat:@"Example: %@",[dateFormatter stringFromDate:[NSDate date]]]; 613 } 614 615 - (void)textFieldDidEndEditing:(UITextField *)textField{ 616 [textField resignFirstResponder]; 617 if ([textField.text isEqualToString:@""]) 618 return; 619 switch (textField.tag){ 620 case DOBField: 621 NSDate *theDate = [dateFormatter dateFromString:textField.text]; 622 if (theDate) 623 [inputDate setObject:theDate forKey:MyAppPersonDOBKey]; 624 break; 625 default: 626 break; 627 } 628 } 629 630 tableView的cell高度 631 632 tableView的cell高度除了在delegate中指定外,还可以在任意位置以[tableView setRowHeight:44]的方式指定 633 634 [[self navigationItem] setLeftBarButtonItem:[self editButtonItem]]; 635 636 - (void)setEditing:(BOOL)editing animated:(BOOL)animated{ 637 [super setEditing:editing animated:animated]; 638 if (editing){ 639 ...... 640 } 641 else{ 642 ...... 643 } 644 } 645 646 One added a subview to a view, release the subview to avoid the extra retain count of it, Because when you insert a view as a subview using addSubview:, the subview is retained by its superview. When you remove the subview from its superview using the removeFromSuperview: method, subview is autoreleased. 647 648 为UINavigationBar设置背景图片 649 在iPhone开发中, 有时候我们想给导航条添加背景图片, 实现多样化的导航条效果, 用其他方法往往无法达到理想的效果, 经过网上搜索及多次实验, 确定如下最佳实现方案: 650 为UINavigatonBar增加如下Category(类别:提供一种为某个类添加方法而又不必编写子类的途径,类别只能添加成员函数,不能添加数据成员): 651 652 @implementation UINavigationBar (CustomImage) 653 - (void)drawRect:(CGRect)rect { 654 UIImage *image = [UIImage imageNamed: @"NavigationBar.png"]; 655 [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 656 } 657 @end 658 659 例如, 在我的项目中, 添加如下代码: 660 ///////////////////////////////////////////////////////// 661 /* input: The image and a tag to later identify the view */ 662 @implementation UINavigationBar (CustomImage) 663 - (void)drawRect:(CGRect)rect { 664 UIImage *image = [UIImage imageNamed: @"title_bg.png"]; 665 [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 666 } 667 @end 668 ///////////////////////////////////////////////////////// 669 @implementation FriendsPageViewController 670 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 671 - (void)viewDidLoad { 672 self.navigationBar.tintColor = [UIColor purpleColor]; 673 674 [self initWithRootViewController:[[RegPageViewController alloc] init]]; 675 [super viewDidLoad]; 676 } 677 ...... 678 实现的效果如下图: 679 680 681 转载,原文地址 http://blog.csdn.net/wave_1102/archive/2009/11/04/4768212.aspx 682 683 为UINavigationBar添加自定义背景 684 685 @implementation UINavigationBar (UINavigationBarCategory) 686 687 - (void)drawRect:(CGRect)rect { 688 //颜色填充 689 // UIColor *color = [UIColor redColor]; 690 // CGContextRef context = UIGraphicsGetCurrentContext(); 691 // CGContextSetFillColor(context, CGColorGetComponents( [color CGColor])); 692 // CGContextFillRect(context, rect); 693 // self.tintColor = color; 694 //图片填充 695 UIColor *color = [UIColor colorWithRed:46.0f/255.0f 696 green:87.0f/255.0f blue:29.0f/255.0f alpha:1.0f]; 697 698 UIImage *img = [UIImage imageNamed: @"bg.png"]; 699 [img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 700 701 self.tintColor = color; 702 } 703 704 @end 705 706 加载图片要及时release 707 708 你还在使用myImage = [UIImage imageNamed:@"icon.png"]; 吗? 709 710 如题,是不是大家为了方便都这样加载图片啊 711 712 myImage = [UIImage imageNamed:@"icon.png"]; 713 714 那么小心了 715 716 这种方法在一些图片很少,或者图片很小的程序里是ok的。 717 718 但是,在大量加载图片的程序里,请千万不要这样做。 719 720 为什么呢 ??????? 721 722 这种方法在application bundle的顶层文件夹寻找由供应的名字的图象。 如果找到图片,装载到iPhone系统缓存图象。那意味图片是(理论上)放在内存里作为cache的。 723 724 试想你图片多了,是什么后果? 725 726 图片cache极有可能不会响应 memory warnings and release its objects 727 728 所以,用图片的时候一定要小心的alloc和release。 729 730 推荐使用 NSString *path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"]; 731 732 myImage = [UIImage imageWithContentsOfFile:path]; 733 734 // Todo use of myImage 735 736 [myImage release]; 737 738 From: http://www.cocoachina.com/bbs/simple/?t27420.html 739 740 uiwebview打开doc,pdf文件 741 UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 55, 320, 300)]; 742 webView.delegate = self; 743 webView.multipleTouchEnabled = YES; 744 webView.scalesPageToFit = YES; 745 746 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 747 NSString *documentsDirectory = [paths objectAtIndex:0]; 748 NSString *docPath = [documentsDirectory stringByAppendingString:@"/doc2003_1.doc"]; NSLog(@"#######%@",docPath); 749 750 NSURL *url = [NSURL fileURLWithPath:docPath]; 751 NSURLRequest *request = [NSURLRequest requestWithURL:url]; 752 [webView loadRequest:request]; 753 754 [self.view addSubview:webView]; 755 [webView release]; 756 757 From:http://blog.csdn.net/dadalan/archive/2010/10/22/5959301.aspx 758 759 iPhone游戏中既播放背景音乐又播放特效声音的办法 760 761 有时候在 iPhone 游戏中,既要播放背景音乐,同时又要播放比如枪的开火音效。此时您可以试试以下方法 762 763 NSString *musicFilePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"wav"]; //创建音乐文件路径 764 NSURL *musicURL = [[NSURL alloc] initFileURLWithPath:musicFilePath]; 765 AVAudioPlayer* musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; 766 [musicURL release]; 767 [musicPlayer prepareToPlay]; 768 //[musicPlayer setVolume:1]; //设置音量大小 769 //musicPlayer .numberOfLoops = -1;//设置音乐播放次数 -1为一直循环 770 771 要导入框架 AVFoundation.framework,头文件中 #import <AVFoundation/AVFoundation.h>;做成类的话则更方便。 772 773 From: http://blog.csdn.net/dadalan/archive/2010/10/19/5950493.aspx 774 775 NSNotificationCenter用于增加回调函数 776 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_willBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; 777 778 UINavigationBar 背景Hack 779 LOGO_320×44.png 图片显示在背景上, 780 781 @implementation UINavigationBar (UINavigationBarCategory) 782 - (void)drawRect:(CGRect)rect { 783 //加入旋转坐标系代码 784 // Drawing code 785 UIImage *navBarImage = [UIImage imageNamed:@"LOGO_320×44.png"]; 786 CGContextRef context = UIGraphicsGetCurrentContext(); 787 CGContextTranslateCTM(context, 0.0, self.frame.size.height); 788 CGContextScaleCTM(context, 1.0, -1.0); 789 790 CGPoint center=self.center; 791 792 CGImageRef cgImage= CGImageCreateWithImageInRect(navBarImage.CGImage, CGRectMake(0, 0, 1, 44)); 793 CGContextDrawImage(context, CGRectMake(center.x-160-80, 0, 80, self.frame.size.height), cgImage); 794 CGContextDrawImage(context, CGRectMake(center.x-160, 0, 320, self.frame.size.height), navBarImage.CGImage); 795 CGContextDrawImage(context, CGRectMake(center.x+160, 0, 80, self.frame.size.height), cgImage); 796 } 797 @end 798 799 old code 800 CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), navBarImage.CGImage); 801 802 hack 过logo 不再拉伸 803 804 From: http://blog.163.com/fengyi1103@126/blog/static/13835627420106279102671/ 805 806 清除电话号码中的其他符号(源码) 807 808 最近从通讯录读取电话号码,读出得号码如:134-1814-****。 809 而我需要的为11位纯数字,一直找方法解决此问题,今天终于找到了。。 810 分享一下…… 811 812 代码如下: 813 814 NSString *originalString = @"(123) 123123 abc"; 815 NSMutableString *strippedString = [NSMutableString 816 stringWithCapacity:originalString.length]; 817 818 NSScanner *scanner = [NSScanner scannerWithString:originalString]; 819 NSCharacterSet *numbers = [NSCharacterSet 820 characterSetWithCharactersInString:@"0123456789"]; 821 822 while ([scanner isAtEnd] == NO) { 823 NSString *buffer; 824 if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) { 825 [strippedString appendString:buffer]; 826 } 827 // --------- Add the following to get out of endless loop 828 else { 829 [scanner setScanLocation:([scanner scanLocation] + 1)]; 830 } 831 // --------- End of addition 832 } 833 834 NSLog(@"%@", strippedString); // "123123123" 835 836 From: http://stackoverflow.com/questions/1129521/remove-all-but-numbers-from-nsstring 837 838 839 正则判断:字符串只包含字母和数字 840 841 NSString *mystring = @"Letter1234"; 842 NSString *regex = @"[a-z][A-Z][0-9]"; 843 844 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 845 846 if ([predicate evaluateWithObject:mystring] == YES) { 847 //implement 848 } 849 850 851 一行代码设置 UITableViewCell 与导航条间距 852 853 UITableView 的 cell 默认出现在 uitableview 的第一行,如果你想自定义 UITableViewCell 与导航条间距的话,可以使用下面这行代码 854 855 tableview.tableHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)]autorelease]; 856 857 From: http://blog.163.com/fengyi1103@126/blog/static/1383562742010101611107492/ 858 859 860 修改 UITableview 滚动条颜色的方法 861 862 UITableview 的滚动条默认颜色是黑色的,如果 UItableview 背景也是深颜色,则滚动条会变的很不明显。您可以用下面这行代码来改变滚动条的颜色 863 864 self.tableView.indicatorStyle=UIScrollViewIndicatorStyleWhite; 865 866 当然,最后的 “White” 也可以换成其它颜色。 867 868 869 下文件之前获取到文件大小的代码 870 871 下面这段代码,能实现在下载文件之前获得文件大小,应用在软件里,能在很大程度上改善用户体验 872 873 [m_pASIHTTPRequest setDidReceiveResponseHeadersSelector:@selector(didReceiveResponseHeaders:)]; 874 875 - (void)didReceiveResponseHeaders:(ASIHTTPRequest *)request 876 { 877 NSLog(@"didReceiveResponseHeaders %@",[m_request.responseHeaders valueForKey:@"Content-Length"]); 878 } 879 880 网络编程总结 iphone 881 882 一:确认网络环境3G/WIFI 883 884 1. 添加源文件和framework 885 886 开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息。如果没有处理它们,是不会通过Apple的审(我们的)查的。 887 Apple 的 例程 Reachability 中介绍了取得/检测网络状态的方法。要在应用程序程序中使用Reachability,首先要完成如下两部: 888 889 1.1. 添加源文件: 890 在你的程序中使用 Reachability 只须将该例程中的 Reachability.h 和 Reachability.m 拷贝到你的工程中。如下图: 891 892 893 894 1.2.添加framework: 895 将SystemConfiguration.framework 添加进工程。如下图: 896 897 898 2. 网络状态 899 900 Reachability.h中定义了三种网络状态: 901 typedef enum { 902 NotReachable = 0, //无连接 903 ReachableViaWiFi, //使用3G/GPRS网络 904 ReachableViaWWAN //使用WiFi网络 905 } NetworkStatus; 906 907 因此可以这样检查网络状态: 908 909 Reachability *r = [Reachability reachabilityWithHostName:@“www.apple.com”]; 910 switch ([r currentReachabilityStatus]) { 911 case NotReachable: 912 // 没有网络连接 913 break; 914 case ReachableViaWWAN: 915 // 使用3G网络 916 break; 917 case ReachableViaWiFi: 918 // 使用WiFi网络 919 break; 920 } 921 922 3.检查当前网络环境 923 程序启动时,如果想检测可用的网络环境,可以像这样 924 // 是否wifi 925 + (BOOL) IsEnableWIFI { 926 return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable); 927 } 928 929 // 是否3G 930 + (BOOL) IsEnable3G { 931 return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable); 932 } 933 例子: 934 - (void)viewWillAppear:(BOOL)animated { 935 if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) && 936 ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) { 937 self.navigationItem.hidesBackButton = YES; 938 [self.navigationItem setLeftBarButtonItem:nil animated:NO]; 939 } 940 } 941 942 4. 链接状态的实时通知 943 网络连接状态的实时检查,通知在网络应用中也是十分必要的。接续状态发生变化时,需要及时地通知用户: 944 945 Reachability 1.5版本 946 // My.AppDelegate.h 947 #import "Reachability.h" 948 949 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 950 NetworkStatus remoteHostStatus; 951 } 952 953 @property NetworkStatus remoteHostStatus; 954 955 @end 956 957 // My.AppDelegate.m 958 #import "MyAppDelegate.h" 959 960 @implementation MyAppDelegate 961 @synthesize remoteHostStatus; 962 963 // 更新网络状态 964 - (void)updateStatus { 965 self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus]; 966 } 967 968 // 通知网络状态 969 - (void)reachabilityChanged:(NSNotification *)note { 970 [self updateStatus]; 971 if (self.remoteHostStatus == NotReachable) { 972 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil) 973 message:NSLocalizedString (@"NotReachable", nil) 974 delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 975 [alert show]; 976 [alert release]; 977 } 978 } 979 980 // 程序启动器,启动网络监视 981 - (void)applicationDidFinishLaunching:(UIApplication *)application { 982 983 // 设置网络检测的站点 984 [[Reachability sharedReachability] setHostName:@"www.apple.com"]; 985 [[Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES]; 986 // 设置网络状态变化时的通知函数 987 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) 988 name:@"kNetworkReachabilityChangedNotification" object:nil]; 989 [self updateStatus]; 990 } 991 992 - (void)dealloc { 993 // 删除通知对象 994 [[NSNotificationCenter defaultCenter] removeObserver:self]; 995 [window release]; 996 [super dealloc]; 997 } 998 999 Reachability 2.0版本 1000 1001 1002 // MyAppDelegate.h 1003 @class Reachability; 1004 1005 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 1006 Reachability *hostReach; 1007 } 1008 1009 @end 1010 1011 // MyAppDelegate.m 1012 - (void)reachabilityChanged:(NSNotification *)note { 1013 Reachability* curReach = [note object]; 1014 NSParameterAssert([curReach isKindOfClass: [Reachability class]]); 1015 NetworkStatus status = [curReach currentReachabilityStatus]; 1016 1017 if (status == NotReachable) { 1018 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AppName"" 1019 message:@"NotReachable" 1020 delegate:nil 1021 cancelButtonTitle:@"YES" otherButtonTitles:nil]; 1022 [alert show]; 1023 [alert release]; 1024 } 1025 } 1026 1027 - (void)applicationDidFinishLaunching:(UIApplication *)application { 1028 // ... 1029 1030 // 监测网络情况 1031 [[NSNotificationCenter defaultCenter] addObserver:self 1032 selector:@selector(reachabilityChanged:) 1033 name: kReachabilityChangedNotification 1034 object: nil]; 1035 hostReach = [[Reachability reachabilityWithHostName:@"www.google.com"] retain]; 1036 hostReach startNotifer]; 1037 // ... 1038 } 1039 1040 1041 二:使用NSConnection下载数据 1042 1043 1.创建NSConnection对象,设置委托对象 1044 1045 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]]]; 1046 [NSURLConnection connectionWithRequest:request delegate:self]; 1047 1048 2. NSURLConnection delegate委托方法 1049 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; 1050 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; 1051 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; 1052 - (void)connectionDidFinishLoading:(NSURLConnection *)connection; 1053 1054 3. 实现委托方法 1055 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 1056 // store data 1057 [self.receivedData setLength:0]; //通常在这里先清空接受数据的缓存 1058 } 1059 1060 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 1061 /* appends the new data to the received data */ 1062 [self.receivedData appendData:data]; //可能多次收到数据,把新的数据添加在现有数据最后 1063 } 1064 1065 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 1066 // 错误处理 1067 } 1068 1069 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 1070 // disconnect 1071 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 1072 NSString *returnString = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; 1073 NSLog(returnString); 1074 [self urlLoaded:[self urlString] data:self.receivedData]; 1075 firstTimeDownloaded = YES; 1076 } 1077 1078 三:使用NSXMLParser解析xml文件 1079 1080 1. 设置委托对象,开始解析 1081 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //或者也可以使用initWithContentsOfURL直接下载文件,但是有一个原因不这么做: 1082 // It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable 1083 // because it gives less control over the network, particularly in responding to connection errors. 1084 [parser setDelegate:self]; 1085 [parser parse]; 1086 1087 2. 常用的委托方法 1088 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 1089 namespaceURI:(NSString *)namespaceURI 1090 qualifiedName:(NSString *)qName 1091 attributes:(NSDictionary *)attributeDict; 1092 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 1093 namespaceURI:(NSString *)namespaceURI 1094 qualifiedName:(NSString *)qName; 1095 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; 1096 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError; 1097 1098 static NSString *feedURLString = @"http://www.yifeiyang.net/test/test.xml"; 1099 1100 3. 应用举例 1101 - (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error 1102 { 1103 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL]; 1104 [parser setDelegate:self]; 1105 [parser setShouldProcessNamespaces:NO]; 1106 [parser setShouldReportNamespacePrefixes:NO]; 1107 [parser setShouldResolveExternalEntities:NO]; 1108 [parser parse]; 1109 NSError *parseError = [parser parserError]; 1110 if (parseError && error) { 1111 *error = parseError; 1112 } 1113 [parser release]; 1114 } 1115 1116 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1117 qualifiedName:(NSString*)qName attributes:(NSDictionary *)attributeDict{ 1118 // 元素开始句柄 1119 if (qName) { 1120 elementName = qName; 1121 } 1122 if ([elementName isEqualToString:@"user"]) { 1123 // 输出属性值 1124 NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]); 1125 } 1126 } 1127 1128 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1129 qualifiedName:(NSString *)qName 1130 { 1131 // 元素终了句柄 1132 if (qName) { 1133 elementName = qName; 1134 } 1135 } 1136 1137 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 1138 { 1139 // 取得元素的text 1140 } 1141 1142 NSError *parseError = nil; 1143 [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError]; 1144 1145 Iphone 实现画折线图 1146 1147 iphone里面要画图一般都是通过CoreGraphics.framwork和QuartzCore.framwork实现,apple的官方sdk demon中包含了QuartzCore的基本用法, 1148 1149 1150 具体demo请参考http://developer.apple.com/library/ios/#samplecode/QuartzDemo/ 1151 折线图 1152 1153 1154 要实现折线图也就把全部的点连起来,movePointLineto,具体的调用里面的api就可以实现了,但是画坐标就比较麻烦了,里面需要去转很多,好在国外有人开源了一个画折线图的开发包,首先看看效果吧,具体怎么用可以参考作者git版本库中的wiki。 1155 http://github.com/devinross/tapkulibrary/wiki/How-To-Use-This-Library 1156 1157 这个包还提供了其他的很好看的UI,都可以调来用,但是我们只需要一个画图要把整个包都导进去,工程太大了,既然是开源的那就想办法提取出来吧,原先之前也有人干过这样的事。http://duivesteyn.net/2010/03/07/iphone-sdk-implementing-the-tapku-graph-in-your-application/ 1158 我对源代码进行简单的修改,使其显示坐标之类的,更加符合工程的需要,但是还没有实现画多组数据,只能画一组数据,不用viewContol,而使用addsubview,直接添加到当前的窗口,最终效果如下。 1159 使用方法: 1160 1161 1.工程添加tk库里面的如下文件 1162 1163 2. 添加QuartzCore framework 1164 #import <QuartzCore/QuartzCore.h> 1165 添加TapkuLibrary.bundle资源文件 1166 3.代码中完成实例,数据初始化就可以用了 1167 1168 下载修改后的版本。下次有时间在整理一个工程版本出来。 1169 1170 让iPhone屏幕常亮不变暗的方法 1171 1172 如果您希望运行自己开发的App时,iPhone的屏幕不再自动变暗,可以使用以下方法让屏幕常亮: iPhone OS用一个布尔值用来控制是否取消应用程序空闲时间:@property(nonatomic, getter=isIdleTime 1173 1174 如果您希望运行自己开发的App时,iPhone的屏幕不再自动变暗,可以使用以下方法让屏幕常亮: 1175 1176 iPhone OS用一个布尔值用来控制是否取消应用程序空闲时间:@property(nonatomic, getter=isIdleTimerDisabled) BOOL idleTimerDisabled。这个值的默认属性是"NO"。当大多数应用程序没有接收到用户输入信息的时候,系统会把设备设置成“休眠”状态,iPhone屏幕也会变暗。这样做是为了保存更多电量。事实上,应用程序在运行加速度游戏的时候是不需要用户输入的,当然这里只是一个假设,把这个变量设置为"YES",来取消系统休眠的“空闲时间”。 1177 1178 重点是:你必须当真正需要的时候才打开这个属性当你不用的时候马上还愿成"NO"。大多数应用程序在休眠时间到的时候让系统关闭屏幕。这个包括了有音频的应用程 序。在Audio Session Services中使用适当的回放和记录功能不会被间断当屏幕关闭时。只有地图应用程序,游戏或者一些不间断的用户交互程序可以取消这个属性。 1179 1180 苹果开发网络编程知识总结 1181 1182 以下苹果开发网络编程知识由 CocoaChina 会员 cocoa_yang 总结,希望能为苹果开发新手梳理知识脉络,节省入门时间。一:确认网络环境3G/WIFI 1. 添加源文件和framework 开发Web等网络应用程序 1183 1184 以下苹果开发网络编程知识由 CocoaChina 会员 “cocoa_yang” 总结,希望能为苹果开发新手梳理知识脉络,节省入门时间。 1185 1186 一:确认网络环境3G/WIFI 1187 1188 1. 添加源文件和framework 1189 1190 开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息。如果没有处理它们,是不会通过Apple的审查的。 1191 Apple 的 例程 Reachability 中介绍了取得/检测网络状态的方法。要在应用程序程序中使用Reachability,首先要完成如下两部: 1192 1193 1.1. 添加源文件: 1194 在你的程序中使用 Reachability 只须将该例程中的 Reachability.h 和 Reachability.m 拷贝到你的工程中。如下图: 1195 1196 1.2.添加framework: 1197 将SystemConfiguration.framework 添加进工程。如下图: 1198 1199 1200 2. 网络状态 1201 1202 Reachability.h中定义了三种网络状态: 1203 typedef enum { 1204 NotReachable = 0, //无连接 1205 ReachableViaWiFi, //使用3G/GPRS网络 1206 ReachableViaWWAN //使用WiFi网络 1207 } NetworkStatus; 1208 1209 因此可以这样检查网络状态: 1210 1211 Reachability *r = [Reachability reachabilityWithHostName:@“www.apple.com”]; 1212 switch ([r currentReachabilityStatus]) { 1213 case NotReachable: 1214 // 没有网络连接 1215 break; 1216 case ReachableViaWWAN: 1217 // 使用3G网络 1218 break; 1219 case ReachableViaWiFi: 1220 // 使用WiFi网络 1221 break; 1222 } 1223 1224 3.检查当前网络环境 1225 1226 程序启动时,如果想检测可用的网络环境,可以像这样 1227 // 是否wifi 1228 + (BOOL) IsEnableWIFI { 1229 return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable); 1230 } 1231 1232 // 是否3G 1233 + (BOOL) IsEnable3G { 1234 return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable); 1235 } 1236 例子: 1237 - (void)viewWillAppear:(BOOL)animated { 1238 if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) && 1239 ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) { 1240 self.navigationItem.hidesBackButton = YES; 1241 [self.navigationItem setLeftBarButtonItem:nil animated:NO]; 1242 } 1243 } 1244 1245 4. 链接状态的实时通知 1246 1247 网络连接状态的实时检查,通知在网络应用中也是十分必要的。接续状态发生变化时,需要及时地通知用户: 1248 1249 Reachability 1.5版本 1250 // My.AppDelegate.h 1251 #import "Reachability.h" 1252 1253 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 1254 NetworkStatus remoteHostStatus; 1255 } 1256 1257 @property NetworkStatus remoteHostStatus; 1258 1259 @end 1260 1261 // My.AppDelegate.m 1262 #import "MyAppDelegate.h" 1263 1264 @implementation MyAppDelegate 1265 @synthesize remoteHostStatus; 1266 1267 // 更新网络状态 1268 - (void)updateStatus { 1269 self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus]; 1270 } 1271 1272 // 通知网络状态 1273 - (void)reachabilityChanged:(NSNotification *)note { 1274 [self updateStatus]; 1275 if (self.remoteHostStatus == NotReachable) { 1276 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil) 1277 message:NSLocalizedString (@"NotReachable", nil) 1278 delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 1279 [alert show]; 1280 [alert release]; 1281 } 1282 } 1283 1284 // 程序启动器,启动网络监视 1285 - (void)applicationDidFinishLaunching:(UIApplication *)application { 1286 1287 // 设置网络检测的站点 1288 [[Reachability sharedReachability] setHostName:@"www.apple.com"]; 1289 [[Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES]; 1290 // 设置网络状态变化时的通知函数 1291 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) 1292 name:@"kNetworkReachabilityChangedNotification" object:nil]; 1293 [self updateStatus]; 1294 } 1295 1296 - (void)dealloc { 1297 // 删除通知对象 1298 [[NSNotificationCenter defaultCenter] removeObserver:self]; 1299 [window release]; 1300 [super dealloc]; 1301 } 1302 1303 Reachability 2.0版本 1304 1305 1306 // MyAppDelegate.h 1307 @class Reachability; 1308 1309 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 1310 Reachability *hostReach; 1311 } 1312 1313 @end 1314 1315 // MyAppDelegate.m 1316 - (void)reachabilityChanged:(NSNotification *)note { 1317 Reachability* curReach = [note object]; 1318 NSParameterAssert([curReach isKindOfClass: [Reachability class]]); 1319 NetworkStatus status = [curReach currentReachabilityStatus]; 1320 1321 if (status == NotReachable) { 1322 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AppName"" 1323 message:@"NotReachable" 1324 delegate:nil 1325 cancelButtonTitle:@"YES" otherButtonTitles:nil]; 1326 [alert show]; 1327 [alert release]; 1328 } 1329 } 1330 1331 - (void)applicationDidFinishLaunching:(UIApplication *)application { 1332 // ... 1333 1334 // 监测网络情况 1335 [[NSNotificationCenter defaultCenter] addObserver:self 1336 selector:@selector(reachabilityChanged:) 1337 name: kReachabilityChangedNotification 1338 object: nil]; 1339 hostReach = [[Reachability reachabilityWithHostName:@"www.google.com"] retain]; 1340 hostReach startNotifer]; 1341 // ... 1342 } 1343 1344 1345 二:使用NSConnection下载数据 1346 1347 1.创建NSConnection对象,设置委托对象 1348 1349 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]]]; 1350 [NSURLConnection connectionWithRequest:request delegate:self]; 1351 1352 2. NSURLConnection delegate委托方法 1353 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; 1354 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; 1355 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; 1356 - (void)connectionDidFinishLoading:(NSURLConnection *)connection; 1357 1358 3. 实现委托方法 1359 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 1360 // store data 1361 [self.receivedData setLength:0]; //通常在这里先清空接受数据的缓存 1362 } 1363 1364 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 1365 /* appends the new data to the received data */ 1366 [self.receivedData appendData:data]; //可能多次收到数据,把新的数据添加在现有数据最后 1367 } 1368 1369 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 1370 // 错误处理 1371 } 1372 1373 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 1374 // disconnect 1375 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 1376 NSString *returnString = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; 1377 NSLog(returnString); 1378 [self urlLoaded:[self urlString] data:self.receivedData]; 1379 firstTimeDownloaded = YES; 1380 } 1381 1382 三:使用NSXMLParser解析xml文件 1383 1384 1. 设置委托对象,开始解析 1385 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //或者也可以使用initWithContentsOfURL直接下载文件,但是有一个原因不这么做: 1386 // It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable 1387 // because it gives less control over the network, particularly in responding to connection errors. 1388 [parser setDelegate:self]; 1389 [parser parse]; 1390 1391 2. 常用的委托方法 1392 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 1393 namespaceURI:(NSString *)namespaceURI 1394 qualifiedName:(NSString *)qName 1395 attributes:(NSDictionary *)attributeDict; 1396 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 1397 namespaceURI:(NSString *)namespaceURI 1398 qualifiedName:(NSString *)qName; 1399 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; 1400 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError; 1401 1402 static NSString *feedURLString = @"http://www.yifeiyang.net/test/test.xml"; 1403 1404 3. 应用举例 1405 - (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error 1406 { 1407 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL]; 1408 [parser setDelegate:self]; 1409 [parser setShouldProcessNamespaces:NO]; 1410 [parser setShouldReportNamespacePrefixes:NO]; 1411 [parser setShouldResolveExternalEntities:NO]; 1412 [parser parse]; 1413 NSError *parseError = [parser parserError]; 1414 if (parseError && error) { 1415 *error = parseError; 1416 } 1417 [parser release]; 1418 } 1419 1420 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1421 qualifiedName:(NSString*)qName attributes:(NSDictionary *)attributeDict{ 1422 // 元素开始句柄 1423 if (qName) { 1424 elementName = qName; 1425 } 1426 if ([elementName isEqualToString:@"user"]) { 1427 // 输出属性值 1428 NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]); 1429 } 1430 } 1431 1432 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1433 qualifiedName:(NSString *)qName 1434 { 1435 // 元素终了句柄 1436 if (qName) { 1437 elementName = qName; 1438 } 1439 } 1440 1441 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 1442 { 1443 // 取得元素的text 1444 } 1445 1446 NSError *parseError = nil; 1447 [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError]; 1448 1449 如何隐藏状态栏 1450 [ UIApplication sharedApplication ].statusBarHidden = YES; 1451 1452 .m 文件与.mm文件的区别 1453 .m文件是object-c文件 1454 .mm文件相当于c++或者c文件 1455 1456 NSLog(@"afd")与 NSLog("afd") 1457 1458 细微差别会导致程序崩溃。 1459 1460 但是我不太明白为何苹果要把编译器做的对这两种常量有区别。 1461 1462 不过值得一提的是可能为了方便苹果自身的NSObject对象的格式化输出。 1463 1464 safari其实没有把内存的缓存写到存储卡上 1465 1466 NSURLCache doesn't seem to support writing to disk on iPhone. The documentation for NSCachedURLResponse says that the NSURLCacheStoragePolicy "NSURLCacheStorageAllowed" is treated as "NSURLCacheStorageAllowedInMemoryOnly" by iPhone OS. 1467 1468 官方文档是这么说的。 1469 1470 为了证明这个,我找到了一个目录。 1471 1472 /private/var/mobile/Library/Caches/Safari/Thumbnails 1473 1474 随机数的使用 1475 1476 头文件的引用 1477 #import <time.h> 1478 #import <mach/mach_time.h> 1479 1480 srandom()的使用 1481 srandom((unsigned)(mach_absolute_time() & 0xFFFFFFFF)); 1482 1483 直接使用 random() 来调用随机数 1484 1485 在UIImageView 中旋转图像 1486 1487 float rotateAngle = M_PI; 1488 CGAffineTransform transform =CGAffineTransformMakeRotation(rotateAngle); 1489 imageView.transform = transform; 1490 1491 以上代码旋转imageView, 角度为rotateAngle, 方向可以自己测试哦! 1492 1493 1494 在Quartz中如何设置旋转点 1495 1496 UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg.png"]]; 1497 imageView.layer.anchorPoint = CGPointMake(0.5, 1.0); 1498 1499 这个是把旋转点设置为底部中间。记住是在QuartzCore.framework中才得到支持。 1500 1501 创建.plist文件并存储 1502 1503 NSString *errorDesc; //用来存放错误信息 1504 NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:4]; //NSDictionary, NSData等文件可以直接转化为plist文件 1505 NSDictionary *innerDict; 1506 NSString *name; 1507 Player *player; 1508 NSInteger saveIndex; 1509 1510 for(int i = 0; i < [playerArray count]; i++) { 1511 player = nil; 1512 player = [playerArray objectAtIndex:i]; 1513 if(player == nil) 1514 break; 1515 name = player.playerName;// This "Player1" denotes the player name could also be the computer name 1516 innerDict = [self getAllNodeInfoToDictionary:player]; 1517 [rootObj setObject:innerDict forKey:name]; // This "Player1" denotes the person who start this game 1518 } 1519 player = nil; 1520 NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc]; 1521 1522 红色部分可以忽略,只是给rootObj添加一点内容。这个plistData为创建好的plist文件,用其writeToFile方法就可以写成文件。下面是代码: 1523 1524 /*得到移动设备上的文件存放位置*/ 1525 NSString *documentsPath = [self getDocumentsDirectory]; 1526 NSString *savePath = [documentsPath stringByAppendingPathComponent:@"save.plist"]; 1527 1528 /*存文件*/ 1529 if (plistData) { 1530 [plistData writeToFile:savePath atomically:YES]; 1531 } 1532 else { 1533 NSLog(errorDesc); 1534 [errorDesc release]; 1535 } 1536 1537 - (NSString *)getDocumentsDirectory { 1538 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 1539 return [paths objectAtIndex:0]; 1540 } 1541 1542 读取plist文件并转化为NSDictionary 1543 1544 NSString *documentsPath = [self getDocumentsDirectory]; 1545 NSString *fullPath = [documentsPath stringByAppendingPathComponent:@"save.plist"]; 1546 NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPath]; 1547 1548 读取一般性文档文件 1549 1550 NSString *tmp; 1551 NSArray *lines; /*将文件转化为一行一行的*/ 1552 lines = [[NSString stringWithContentsOfFile:@"testFileReadLines.txt"] 1553 componentsSeparatedByString:@"\n"]; 1554 1555 NSEnumerator *nse = [lines objectEnumerator]; 1556 1557 // 读取<>里的内容 1558 while(tmp = [nse nextObject]) { 1559 NSString *stringBetweenBrackets = nil; 1560 NSScanner *scanner = [NSScanner scannerWithString:tmp]; 1561 [scanner scanUpToString:@"<" intoString:nil]; 1562 [scanner scanString:@"<" intoString:nil]; 1563 [scanner scanUpToString:@">" intoString:&stringBetweenBrackets]; 1564 1565 NSLog([stringBetweenBrackets description]); 1566 } 1567 1568 对于读写文件,还有补充,暂时到此。随机数和文件读写在游戏开发中经常用到。所以把部分内容放在这,以便和大家分享,也当记录,便于查找。 1569 1570 隐藏NavigationBar 1571 [self.navigationController setNavigationBarHidden:YES animated:YES]; 1572 1573 在想隐藏的ViewController中使用就可以了。 1574 1575 如何在iPhone程序中调用外部命令 1576 1577 下面是如何在iPhone非官方SDK程序中调用外部命令的方法。 1578 1579 - ( NSString * ) executeCommand : ( NSString * ) cmd { NSString * output = [ NSString string ] ; FILE * pipe = popen ( [ cmd cStringUsingEncoding : NSASCIIStringEnc 1580    1581 下面是如何在iPhone非官方SDK程序中调用外部命令的方法。 1582 1583 - (NSString *)executeCommand: (NSString *)cmd 1584 { 1585 NSString *output = [NSString string]; 1586 FILE *pipe = popen([cmd cStringUsingEncoding: NSASCIIStringEncoding], "r"); 1587 if (!pipe) return; 1588 1589 char buf[1024]; 1590 while(fgets(buf, 1024, pipe)) { 1591 output = [output stringByAppendingFormat: @"%s", buf]; 1592 } 1593 1594 pclose(pipe); 1595 return output; 1596 } 1597 1598 NSString *yourcmd = [NSString stringWithFormat: @"your command"]; 1599 [self executeCommand: yourcmd]; 1600 1601 如何在iPhone程序读取数据时显示进度窗 1602 1603 下面代码说明如何使用iPhone 非官方SDK在读取数据时显示进度条。 1604 1605 以下代码参考了MobileRss。 1606 1607 定义头文件: 1608 1609 #import "uikit/UIProgressHUD.h" 1610 1611 @interface EyeCandy : UIApplication { 1612 UIProgressHUD *progress; 1613 } 1614 1615 - (void) showProgressHUD:(NSString *)label withWindow:(UIWindow *)w withView:(UIView *)v withRect:(struct CGRect)rect; 1616 - (void) hideProgressHUD; 1617 1618 .@end 1619 1620 上面的引号要改成<>。 1621 1622 import "EyeCandy.h" 1623 1624 @implementation EyeCandy 1625 - (void)showProgressHUD:(NSString *)label withWindow:(UIWindow *)w withView:(UIView *)v withRect:(struct CGRect)rect 1626 { 1627 progress = [[UIProgressHUD alloc] initWithWindow: w]; 1628 [progress setText: label]; 1629 [progress drawRect: rect]; 1630 [progress show: YES]; 1631 1632 [v addSubview:progress]; 1633 } 1634 1635 - (void)hideProgressHUD 1636 { 1637 [progress show: NO]; 1638 [progress removeFromSuperview]; 1639 } 1640 1641 @end 1642 1643 使用下面代码调用: 1644 1645 // Setup Eye Candy View 1646 _eyeCandy = [[[EyeCandy alloc] init] retain]; 1647 1648 // Call loading display 1649 [_eyeCandy showProgressHUD:@"Loading …" withWindow:window withView:mainView withRect:CGRectMake(0.0f, 100.0f, 320.0f, 50.0f)]; 1650 1651 // When finished for hiding the "loading text" 1652 [_eyeCandy hideProgressHUD]; 1653 1654 WebKit的基本用法 1655 1656 WebKit是苹果开发中比较常用的浏览器引擎,Safari使用的正是WebKit引擎。WebKit基于KDE的KHTML加以再开发,解析速度超过了以往所有的浏览器。这里简单记录一下WebKit的基本用法。 1657 1658 WebKit由下面的结构组成: 1659 1660 ,如需转载请自行联系原作者
文章
Web App开发  ·  缓存  ·  开发工具  ·  Android开发  ·  iOS开发
2017-11-08
poj 题型分类
主流算法: 1.搜索 //回溯 2.DP(动态规划)  3.贪心  4.图论 //Dijkstra、最小生成树、网络流 5.数论 //解模线性方程 6.计算几何 //凸壳、同等安置矩形的并的面积与周长 7.组合数学 //Polya定理 8.模拟  9.数据结构 //并查集、堆 10.博弈论 1、 排序1423, 1694, 1723, 1727, 1763, 1788, 1828, 1838, 1840, 2201, 2376, 2377, 2380, 1318, 1877, 1928, 1971, 1974, 1990, 2001, 2002, 2092, 2379, 1002(需要字符处理,排序用快排即可) 1007(稳定的排序) 2159(题意较难懂) 2231 2371(简单排序) 2388(顺序统计算法) 2418(二叉排序树) 2、 搜索、回溯、遍历1022 1111d 1118 1129 1190 1562 1564 1573 1655 2184 2225 2243 2312 2362 2378 2386 1010,1011,1018,1020,1054,1062,1256,1321,1363,1501,1650,1659,1664,1753,2078,2083,2303,2310,2329简单:1128, 1166, 1176, 1231, 1256, 1270, 1321, 1543, 1606, 1664, 1731, 1742, 1745, 1847, 1915, 1950, 2038, 2157, 2182, 2183, 2381, 2386, 2426, 不易:1024, 1054, 1117, 1167, 1708, 1746, 1775, 1878, 1903, 1966, 2046, 2197, 2349, 推荐:1011, 1190, 1191, 1416, 1579, 1632, 1639, 1659, 1680, 1683, 1691, 1709, 1714, 1753, 1771, 1826, 1855, 1856, 1890, 1924, 1935, 1948, 1979, 1980, 2170, 2288, 2331, 2339, 2340,1979(和迷宫类似) 1980(对剪枝要求较高) 3、 历法1008 2080 (这种题要小心) 4、 枚举1012,1046, 1387, 1411, 2245, 2326, 2363, 2381,1054(剪枝要求较高),1650 (小数的精度问题) 5、 数据结构的典型算法容易:1182, 1656, 2021, 2023, 2051, 2153, 2227, 2236, 2247, 2352, 2395, 不易:1145, 1177, 1195, 1227, 1661, 1834, 推荐:1330, 1338, 1451, 1470, 1634, 1689, 1693, 1703, 1724, 1988, 2004, 2010, 2119, 2274, 1125(弗洛伊德算法) ,2421(图的最小生成树) 6、 动态规划1037 A decorative fence、1050 To the Max、1088 滑雪、1125 Stockbroker Grapevine、1141 Brackets Sequence、1159 Palindrome、1160 Post Office、1163 The Triangle、1458 Common Subsequence、1579 Function Run Fun、1887 Testing the CATCHER、1953 World Cup Noise、2386 Lake Counting 7、 贪心1042, 1065, 1230, 1323, 1477, 1716, 1784,1328 1755(或用单纯形方法),2054,1017, 1328,1862, 1922 ,2054, 2209, 2313, 2325, 2370。 8、 模拟容易:1006, 1008, 1013, 1016, 1017, 1169, 1298, 1326, 1350, 1363, 1676, 1786, 1791, 1835, 1970, 2317, 2325, 2390, 不易:1012, 1082, 1099, 1114, 1642, 1677, 1684, 1886,1281 1928 2083 2141 2015 9、 递归1664 10、字符串处理1488, 1598, 1686, 1706, 1747, 1748, 1750, 1760, 1782, 1790, 1866, 1888, 1896, 1951, 2003, 2121, 2141, 2145, 2159, 2337, 2359, 2372, 2406, 2408, 1016 1051 1126 1318 1572 1917 1936 2039 2083 2136 2271 2317 2330,2121 2403 11、数论1006,1014,1023,1061,1152,1183,1730,2262 12、几何有关的题目凸包:1113, 1228, 1794, 2007, 2187,1113 wall,2187 beauty contest容易:1319, 1654, 1673, 1675, 1836, 2074, 2137, 2318, 不易:1685, 1687, 1696, 1873, 1901, 2172, 2333 13、任意精度运算、数字游戏、高精度计算1001 1023 1047 1060 1079 1131 1140 1142 1207 1220 1284 1289 1306 1316 1338 1405 1454 1503 1504 1519 1565 1650 1969 2000 2006 2081 2247 2262 2305 2316 2389 1001, 1220, 1405, 1503,1001(高精度乘法) 2413(高精度加法,还有二分查找) 14、概率统计1037,1050 15、小费用最大流、最大流2195 going home 2400 supervisor, supervisee1087 a plug for UNIX1149 PIGS1273 drainage ditches1274 the perfect stall1325 machine schedule1459 power network2239 selecting courses 16、压缩存储的DP1038 bugs integrated inc1185 炮兵阵地2430 lazy cow 17、最长公共子串(LCS)1080 human gene functions1159 palindrome1458 common subsequence2192 zipper 18、图论及组合数学2421 Constructing Roads、2369 Permutations、2234 Matches Game、2243 Knight Moves、2249 Binomial Showdown、2255 Tree Recovery、2084 Game of Connections、1906 Three powers、1833 排列、1850 Code、1562 Oil Deposits、1496 Word Index、1306 Combinations、1125 Stockbroker Grapevine、1129 Channel Allocation、1146 ID Codes、1095 Trees Made to Order、找规律2247 Humble Numbers、2309 BST、2346 Lucky tickets、2370 Democracy in danger、2365 Rope、2101 Honey and Milk Land 2028 When Can We Meet?、2084 Game of Connections、1915 Knight Moves、1922 Ride to School、1941 The Sierpinski Fractal、1953 World Cup Noise、1958 Strange Towers of Hanoi、1969 Count on Canton、1806 Manhattan 2025、1809 Regetni、1844 Sum、1870 Bee Breeding、1702 Eva\'s Balance、1728 A flea on a chessboard、1604 Just the Facts、1642 Stacking Cubes、1656 Counting Black、1657 Distance on Chessboard、1662 CoIns、1663 Number Steps、1313 Booklet Printing、1316 Self Numbers、1320 Street Numbers、1323 Game Prediction、1338 Ugly Numbers、1244 Slots of Fun、1250 Tanning Salon、1102 LC-Display、1147 Binary codes、1013 Counterfeit Dollar 19、博弈类1067 取石子游戏、1740 A New Stone Game、2234 Matches Game、1082 Calendar Game 、2348 Euclid\'s Game、2413 How many Fibs?、2419 Forest 20、简单、模拟题1001 Exponentiation 、1002 487-3279、1003 Hangover 、1701 Dissatisfying Lift、2301 Beat the Spread!、2304 Combination Lock、2328 Guessing Game、2403 Hay Points 、2406 Power Strings、2339 Rock, Scissors, Paper、2350 Above Average、2218 Does This Make Me Look Fat?、2260 Error Correction、2262 Goldbach\'s Conjecture、2272 Bullseye、2136 Vertical Histogram、2174 Decoding Task、2183 Bovine Math Geniuses、2000 Gold Coins、2014 Flow Layout、2051 Argus、2081 Calendar、1918 Ranking List、1922 Ride to School、1970 The Game、1972 Dice Stacking、1974 The Happy Worm、1978 Hanafuda Shuffle、1979 Red and Black、1617 Crypto Columns、1666 Candy Sharing Game、1674 Sorting by Swapping、1503 Integer Inquiry、1504 Adding Reversed Numbers、1528 Perfection、1546 Basically Speaking、1547 Clay Bully、1573 Robot Motion、1575 Easier Done Than Said?、1581 A Contesting Decision、1590 Palindromes、1454 Factorial Frequencies、1363 Rails、1218 THE DRUNK JAILER、1281 MANAGER、1132 Border、1028 Web Navigation 21、初等数学1003 Hangover、1045 Bode Plot、1254 Hansel and Grethel、1269 Intersecting Lines、1401 Factorial、1410 Intersection、2363 Blocks 、2365 Rope、2242 The Circumference of the Circle、2291 Rotten Ropes、2295 A DP Problem、2126 Factoring a Polynomial、2191 Mersenne Composite Numbers、2196 Specialized Four-Digit Numbers、1914 Cramer\'s Rule、1835 宇航员、1799 Yeehaa!、1607 Deck、1244 Slots of Fun、1269 Intersecting Lines、1299 Polar Explorer、1183 反正切函数的应用、22、匹配1274, 1422, 1469, 1719, 2060, 2239,-------------------------------------------------------------------------------------------经典1011(搜索好题) 1012(学会打表)10131019(它体现了很多此类问题的特点)1050(绝对经典的dp)1088(dp好题)1157(花店,经典的dp)1163(怎么经典的dp那么多呀???)1328(贪心)1458(最长公共子序列)1647(很好的真题,考临场分析准确和下手迅速)1654(学会多边形面积的三角形求法)1655(一类无根树的dp问题)1804(逆序对)2084(经典组合数学问题)2187(用凸包求最远点对,求出凸包后应该有O(N)的求法,可我就是调不出来)2195(二分图的最佳匹配)2242(计算几何经典)2295(等式处理)2353(dp,但要记录最佳路径)2354(立体解析几何)2362(搜索好题)2410(读懂题是关键)2411(经典dp) 趣味1067(很难的数学,但仔细研究,是一片广阔的领域)1147(有O(n)的算法,需要思考)1240(直到一棵树的先序和后序遍历,那么有几种中序遍历呢?dp)1426(是数论吗?错,是图论!)1648(别用计算几何,用整点这个特点绕过精度的障碍吧)1833(找规律)1844(貌似dp或是搜索,其实是道有趣的数学题)1922(贪心,哈哈)22312305(不需要高精度噢)2328(要仔细噢)2356(数论知识)2359(约瑟夫问题变种)2392(有趣的问题) 很繁的题100110081087(构图很烦,还有二分图的最大匹配)1128(USACO)124513291550(考的是读题和理解能力)1649(dp)2200(字符串处理+枚举)2358(枚举和避免重复都很烦)2361(仔细仔细再仔细) 难题1014(数学证明比较难,但有那种想法更重要)1037(比较难的dp)1405(高精度算法也分有等级之分,不断改进吧)2002(不知道有没有比O(n^2*logn)更有的算法?)2054(极难,很强的思考能力)2085(组合数学)2414(dp,但要剪枝)2415(搜索)2423(计算几何+统计) 多解题1002(可以用排序,也可以用统计的方法)1338(搜索和dp都可以)1664(搜索和dp都练一练吧)2082(这可是我讲的题噢)2352(桶排和二叉树都行)Note:1011: 很经典的剪支1014: 难在数学上1017: 严格的数学证明貌似不容易1021: 有点繁,考察对图形进行各种旋转的处理1083: 巧妙的思考角度1150: 分奇偶讨论,lg(n)算法1218: 三行就够了,虽然简单,但也有优劣之别1505: 二分加贪心1654: 做法也许很多吧,本人用有向面积做的1674: 计算圈的个数(算是graph 吧)1700: 数学证明不容易1742: O(m*n)的算法1863: 要耐心地慢慢写…^_^1988: 并查集2051: 堆2078: 不难,但剪支可以做到很好2082::O(n),你想到了吗?2084: 卡特兰数2182: 线段树2195: 最小费用最大流2234: 经典博弈算法2236: 并查集2299: 二分思想2395: Kruskal 最小生成树的拓展2406: KMP2411: 用二进制串来表示状态 转自:http://www.cnblogs.com/dc10101/archive/2006/10/25/540022.html
文章
算法
2016-03-20
IOS开发笔记
1 iphone开发笔记 2 3 退回输入键盘 4 - (BOOL) textFieldShouldReturn:(id)textField{ 5 [textField resignFirstResponder]; 6 } 7 8 CGRect 9 CGRect frame = CGRectMake (origin.x, origin.y, size.width, size.height);矩形 10 NSStringFromCGRect(someCG) 把CGRect结构转变为格式化字符串; 11 CGRectFromString(aString) 由字符串恢复出矩形; 12 CGRectInset(aRect) 创建较小或较大的矩形(中心点相同),+较小 -较大 13 CGRectIntersectsRect(rect1, rect2) 判断两矩形是否交叉,是否重叠 14 CGRectZero 高度和宽度为零的/位于(0,0)的矩形常量 15 16 CGPoint & CGSize 17 CGPoint aPoint = CGPointMake(x, y); 18 CGSize aSize = CGSizeMake(width, height); 19 20 设置透明度 21 [myView setAlpha:value]; (0.0 < value < 1.0) 22 23 设置背景色 24 [myView setBackgroundColor:[UIColor redColor]]; 25 (blackColor;darkGrayColor;lightGrayColor; 26 whiteColor;grayColor; redColor; greenColor; 27 blueColor; cyanColor;yellowColor; 28 magentaColor;orangeColor;purpleColor; 29 brownColor; clearColor; ) 30 31 自定义颜色 32 UIColor *newColor = [[UIColor alloc] 33 initWithRed:(float) green:(float) blue:(float) alpha:(float)]; 34 0.0~1.0 35 36 竖屏 37 320X480 38 39 横屏 40 480X320 41 42 状态栏高 (显示时间和网络状态) 43 20 像素 44 45 导航栏、工具栏高(返回) 46 44像素 47 48 隐藏状态栏 49 [[UIApplication shareApplication] setStatusBarHidden: YES animated:NO] 50 51 横屏 52 [[UIApplication shareApplication] 53 setStatusBarOrientation:UIInterfaceOrientationLandscapeRight]. 54 55 屏幕变动检测 56 orientation == UIInterfaceOrientationLandscapeLeft 57 58 全屏 59 window=[[UIWindow alloc] initWithFrame:[UIScreen mainScreen] bounds]; 60 61 自动适应父视图大小: 62 aView.autoresizingSubviews = YES; 63 aView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | 64 UIViewAutoresizingFlexibleHeight); 65 66 定义按钮 67 UIButton *scaleUpButton = [UIButton buttonWithType:UIButtonTypeRoundedRect]; 68 [scaleUpButton setTitle:@"放 大" forState:UIControlStateNormal]; 69 scaleUpButton.frame = CGRectMake(40, 420, 100, 40); 70 [scaleUpButton addTarget:self 71 action:@selector(scaleUp) 72 forControlEvents:UIControlEventTouchUpInside]; 73 74 设置视图背景图片 75 UIImageView *aView; 76 [aView setImage:[UIImage imageNamed:@”name.png”]]; 77 view1.backgroundColor = [UIColor colorWithPatternImage: 78 [UIImage imageNamed:@"image1.png"]]; 79 80 自定义UISlider的样式和滑块 81 82 我们使用的是UISlider的setMinimumTrackImage,和setMaximumTrackImage方法来定义图片的,这两个方法可以设置滑块左边和右边的图片的,不过如果用的是同一张图片且宽度和控件宽度基本一致,就不会有变形拉伸的后果,先看代码,写在 viewDidLoad中: 83 //左右轨的图片 84 UIImage *stetchLeftTrack= [UIImage imageNamed:@"brightness_bar.png"]; 85 UIImage *stetchRightTrack = [UIImage imageNamed:@"brightness_bar.png"]; 86 //滑块图片 87 UIImage *thumbImage = [UIImage imageNamed:@"mark.png"]; 88 89 UISlider *sliderA=[[UISlider alloc]initWithFrame:CGRectMake(30, 320, 257, 7)]; 90 sliderA.backgroundColor = [UIColor clearColor]; 91 sliderA.value=1.0; 92 sliderA.minimumValue=0.7; 93 sliderA.maximumValue=1.0; 94 95 [sliderA setMinimumTrackImage:stetchLeftTrack forState:UIControlStateNormal]; 96 [sliderA setMaximumTrackImage:stetchRightTrack forState:UIControlStateNormal]; 97 //注意这里要加UIControlStateHightlighted的状态,否则当拖动滑块时滑块将变成原生的控件 98 [sliderA setThumbImage:thumbImage forState:UIControlStateHighlighted]; 99 [sliderA setThumbImage:thumbImage forState:UIControlStateNormal]; 100 //滑块拖动时的事件 101 [sliderA addTarget:self action:@selector(sliderValueChanged:) forControlEvents:UIControlEventValueChanged]; 102 //滑动拖动后的事件 103 [sliderA addTarget:self action:@selector(sliderDragUp:) forControlEvents:UIControlEventTouchUpInside]; 104 105 [self.view addSubview:sliderA]; 106 107 为了大家实验方便,我附上背景图brightness_bar.png和滑块图mark.png 108 http://pic002.cnblogs.com/images/2011/162291/2011121611431816.png 109 http://pic002.cnblogs.com/images/2011/162291/2011121611432897.png 110 111 -(IBAction)sliderValueChanged:(id)sender{ 112 UISlider *slider = (UISlider *) sender; 113 NSString *newText = [[NSString alloc] initWithFormat:@”%d”, (int)(slider.value + 0.5f)]; 114 label.text = newText; 115 } 116 117 活动表单 118 <UIActionSheetDelegate> 119 120 - (IBActive) someButtonPressed:(id) sender 121 { 122 UIActionSheet *actionSheet = [[UIActionSheet alloc] 123 initWithTitle:@”Are you sure?” 124 delegate:self 125 cancelButtonTitle:@”No way!” 126 destructiveButtonTitle:@”Yes, I’m Sure!” 127 otherButtonTitles:nil]; 128 [actionSheet showInView:self.view]; 129 [actionSheet release]; 130 } 131 132 警告视图 133 <UIAlertViewDelegate> 134 135 - (void) actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger) buttonIndex 136 { 137 if(buttonIndex != [actionSheet cancelButtonIndex]) 138 { 139 NSString *message = [[NSString alloc] initWithFormat:@”You can 140 breathe easy, everything went OK.”]; 141 UIAlertView *alert = [[UIAlertView alloc] 142 initWithTitle:@”Something was done” 143 message:message 144 delegate:self 145 cancelButtonTitle:@”OK” 146 otherButtonTitles:nil]; 147 [alert show]; 148 [alert release]; 149 [message release]; 150 } 151 } 152 153 动画效果 154 -(void)doChange:(id)sender 155 { 156 if(view2 == nil) 157 { 158 [self loadSec]; 159 } 160 [UIView beginAnimations:nil context:NULL]; 161 [UIView setAnimationDuration:1]; 162 [UIView setAnimationTransition:([view1 superview]?UIViewAnimationTransitionFlipFromLeft:UIViewAnimationTransitionFlipFromRight)forView:self.view cache:YES]; 163 164 if([view1 superview]!= nil) 165 { 166 [view1 removeFromSuperview]; 167 [self.view addSubview:view2]; 168 169 }else { 170 171 [view2 removeFromSuperview]; 172 [self.view addSubview:view1]; 173 } 174 [UIView commitAnimations]; 175 } 176 177 Table View <UITableViewDateSource> 178 #pragma mark - 179 #pragma mark Table View Data Source Methods 180 //指定分区中的行数,默认为1 181 - (NSInteger)tableView:(UITableView *)tableView 182 numberOfRowsInSection:(NSInteger)section 183 { 184 return [self.listData count]; 185 } 186 187 //设置每一行cell显示的内容 188 - (UITableViewCell *)tableView:(UITableView *)tableView 189 cellForRowAtIndexPath:(NSIndexPath *)indexPath 190 { 191 static NSString *SimpleTableIndentifier = @"SimpleTableIndentifier"; 192 UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:SimpleTableIndentifier]; 193 if (cell == nil) { 194 cell = [[[UITableViewCell alloc] 195 initWithStyle:UITableViewCellStyleSubtitle 196 reuseIdentifier:SimpleTableIndentifier] 197 autorelease]; 198 } 199 UIImage *image = [UIImage imageNamed:@"13.gif"]; 200 cell.imageView.image = image; 201 202 NSUInteger row = [indexPath row]; 203 cell.textLabel.text = [listData objectAtIndex:row]; 204 cell.textLabel.font = [UIFont boldSystemFontOfSize:20]; 205 206 if(row < 5) 207 cell.detailTextLabel.text = @"Best friends"; 208 else 209 cell.detailTextLabel.text = @"friends"; 210 return cell; 211 } 212 213 图像、文本标签和详细文本标签 214 215 图像:如果设置图像,则它显示在文本的左侧; 文本标签:这是单元的主要文本(UITableViewCellStyleDefault 只显示文本标签);详细文本标签:这是单元的辅助文本,通常用作解释性说明或标签 216 217 UITableViewCellStyleSubtitle 218 UITableViewCellStyleDefault 219 UITableViewCellStyleValue1 220 UITableViewCellStyleValue2 221 222 <UITableViewDelegate> 223 #pragma mark - 224 #pragma mark Table View Delegate Methods 225 //把每一行缩进级别设置为其行号 226 - (NSInteger)tableView:(UITableView *)tableView indentationLevelForRowAtIndexPath:(NSIndexPath *)indexPath 227 { 228 NSUInteger row = [indexPath row]; 229 return row; 230 } 231 //获取传递过来的indexPath值 232 - (NSIndexPath *)tableView:(UITableView *)tableView willSelectRowAtIndexPath:(NSIndexPath *)indexPath 233 { 234 NSUInteger row = [indexPath row]; 235 if (row == 0) 236 return nil; 237 return indexPath; 238 } 239 240 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 241 { 242 NSUInteger row = [indexPath row]; 243 NSString *rowValue = [listData objectAtIndex:row]; 244 NSString *message = [[NSString alloc] initWithFormat:@"You selected %@",rowValue]; 245 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Row Selected" 246 message:message 247 delegate:nil 248 cancelButtonTitle:@"Yes, I did!" 249 otherButtonTitles:nil]; 250 [alert show]; 251 [alert release]; 252 [message release]; 253 [tableView deselectRowAtIndexPath:indexPath animated:YES]; 254 } 255 256 //设置行的高度 257 - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 258 { 259 return 40; 260 } 261 262 NavigationController 推出push 推出pop 263 [self.navigationController pushViewController:_detailController animated:YES]; 264 [self.navigationController popViewControllerAnimated:YES]; 265 266 Debug: 267 NSLog(@"%s %d", __FUNCTION__, __LINE__); 268 269 点击textField外的地方回收键盘 270 271 先定义一个UIControl类型的对象,在上面可以添加触发事件,令SEL实践为回收键盘的方法,最后将UIControl的实例加到当前View上。 272 UIControl *m_control = [[UIControl alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; 273 [m_control addTarget:self action:@selector(keyboardReturn) 274 forControlEvents:UIControlEventTouchUpInside]; 275 [self.view addSubview:m_control]; 276 277 - (void) keyboardReturn 278 { 279 [aTextField resignFirstResponder]; 280 } 281 282 键盘覆盖输入框 283 当键盘调出时将输入框覆盖时,可以用下方法: 284 - (BOOL)textFieldShouldBeginEditing:(UITextField *)textField 285 { 286 [self.view setFrame:CGRectMake(0, -100, 320, 480) ]; 287 return YES; 288 } 289 - (BOOL)textFieldShouldEndEditing:(UITextField *)textField 290 { 291 [self.view setFrame:CGRectMake(0, 0, 320, 480)]; 292 return YES; 293 } 294 当准备输入时,将视图的位置上调100,这样键盘就不能覆盖到输入框。 295 296 当依赖注入方法不好使时,可以在AppDelegate内申明一个全局的控制器实例_anotherViewController,在另一个需要使用_anotherViewController的地方定义以下委托方法,使用共享的UIApplication实例来获取该委托的引用 297 SomeAppDelegate *appDelegate = (SomeAppDelegate *)[[UIApplication sharedApplication] delegate]; 298 _anotherViewController = appDelegate._anotherViewController; 299 300 UIViewController内建Table View 301 302 纯代码在UIViewController控制器内建Table View 303 @interface RootViewController : UIViewController <UITableViewDelegate, UITableViewDataSource> { 304 NSArray *timeZoneNames; 305 } 306 @property (nonatomic,retain) NSArray *timeZoneNames; 307 @end 308 309 (void) loadView 310 { 311 UITableView *tableView = [[UITableView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] style: UITableViewStylePlain]; 312 tableView.autoresizingMask = (UIViewAutoresizingFlexibleHeight | UIViewAutoresizingWidth); 313 tableView.delegate = self; 314 tableView.dataSource = self; 315 [tableView reloadData]; 316 317 self.view = tableView; 318 [tableView release]; 319 } 320 321 322 将plist文件中的数据赋给数组 323 NSString *thePath = [[NSBundle mainBundle] pathForResource:@"States" ofType:@"plist"]; 324 NSArray *array = [NSArray arrayWithContentsOfFile:thePath]; 325 326 UITouch 327 手指的触摸范围:64X64 328 329 #pragma mark - 330 #pragma mark Touch Events 331 332 - (void)touchesBegan:(NSSet *) touches withEvent:(UIEvent *) event { 333 originFrame = bookCover.frame; 334 NSLog(@"%s %d", __FUNCTION__,__LINE__); 335 336 if ([touches count] == 2) 337 { 338 NSArray *twoTouches = [touches allObjects]; 339 UITouch *firstTouch = [twoTouches objectAtIndex:0]; 340 UITouch *secondTouch = [twoTouches objectAtIndex:1]; 341 CGPoint firstPoint = [firstTouch locationInView:bookCover]; 342 CGPoint secondPoint = [secondTouch locationInView:bookCover]; 343 344 CGFloat deltaX = secondPoint.x - firstPoint.x; 345 CGFloat deltaY = secondPoint.y - firstPoint.y; 346 initialDistance = sqrt(deltaX * deltaX + deltaY * deltaY ); 347 frameX = bookCover.frame.origin.x; 348 frameY = bookCover.frame.origin.y; 349 frameW = bookCover.frame.size.width; 350 frameH = bookCover.frame.size.height; 351 NSLog(@"%s %d", __FUNCTION__,__LINE__); 352 } 353 } 354 355 - (void)touchesMoved:(NSSet *) touches withEvent:(UIEvent *) event { 356 357 if([touches count] == 2) 358 { 359 NSLog(@"%s %d", __FUNCTION__,__LINE__); 360 361 NSArray *twoTouches = [touches allObjects]; 362 UITouch *firstTouch = [twoTouches objectAtIndex:0]; 363 UITouch *secondTouch = [twoTouches objectAtIndex:1]; 364 365 CGPoint firstPoint = [firstTouch locationInView:bookCover]; 366 CGPoint secondPoint = [secondTouch locationInView:bookCover]; 367 368 CGFloat deltaX = secondPoint.x - firstPoint.x; 369 CGFloat deltaY = secondPoint.y - firstPoint.y; 370 CGFloat currentDistance = sqrt(deltaX * deltaX + deltaY * deltaY ); 371 372 if (initialDistance == 0) { 373 initialDistance = currentDistance; 374 } 375 else if (currentDistance != initialDistance) 376 { 377 CGFloat changedDistance = currentDistance - initialDistance; 378 NSLog(@"changedDistance = %f",changedDistance); 379 [bookCover setFrame:CGRectMake(frameX - changedDistance / 2, 380 frameY - (changedDistance * frameH) / (2 * frameW), 381 frameW + changedDistance, 382 frameH + (changedDistance * frameH) / frameW)]; 383 } 384 } 385 } 386 387 - (void)touchesEnded:(NSSet *) touches withEvent:(UIEvent *) event { 388 UITouch *touch = [touches anyObject]; 389 390 UITouch双击图片变大/还原 391 if ([touch tapCount] == 2) 392 { 393 NSLog(@"%s %d", __FUNCTION__,__LINE__); 394 395 if (!flag) { 396 [bookCover setFrame:CGRectMake(bookCover.frame.origin.x - bookCover.frame.size.width / 2, 397 bookCover.frame.origin.y - bookCover.frame.size.height / 2, 398 2 * bookCover.frame.size.width, 399 2 * bookCover.frame.size.height)]; 400 flag = YES; 401 } 402 else { 403 [bookCover setFrame:CGRectMake(bookCover.frame.origin.x + bookCover.frame.size.width / 4, bookCover.frame.origin.y + bookCover.frame.size.height / 4, 404 bookCover.frame.size.width / 2, bookCover.frame.size.height / 2)]; 405 flag = NO; 406 } 407 } 408 } 409 410 Get the Location of Touches 411 (CGPoint)locationInView:(UIView *)view 412 (CGPoint)previousLocationInView:(UIView *)view 413 view window 414 415 Getting Touch Attributes 416 tapCount(read only) timestamp(read only) phase(read only) 417 418 Getting a Touch Object's Gesture Recognizers 419 gestureRecognizers 420 421 Touch Phase 422 UITouchPhaseBegan 423 UITouchPhaseMoved 424 UITouchPhaseStationary 425 UITouchPhaseEnded 426 UITouchPhaseCancelled 427 428 从Plist里读内容 429 NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"book" ofType:@"plist"]; 430 NSDictionary *dictionary = [[NSDictionary alloc] initWithContentsOfFile:plistPath]; 431 NSString *book = [dictionary objectForKey:bookTitle]; 432 [textView setText:book]; 433 434 (void) initialize { 435 NSUserDefaults = [NSUserDefaults standardUserDefaults]; 436 NSDictionary *appDefaults = [NSDictionary dictionaryWithObject:@"YES" forKey:@"DeleteBackup"]; 437 [defaults registerDefaults:appDefaults]; 438 } 439 440 To get a value of a default, use the valueForKey: method: 441 [[theDefaultsController values] valueForKey:@"userName"]; 442 To set a value for a default, use setValue:forKey: 443 [[theDefaultsController values] setValue:newUserName forKey:@"userName"]; 444 445 [[NSUserDefaults standardUserDefaults] setValue:aVale forKey:aKey]; 446 [[NSUserDefaults standardUserDefaults] valueForKey:aKey]; 447 448 获取Documents目录 449 NSArray *paths = NSSearchPathForDictionariesInDomains(NSDocumentDirectory, 450 NSUserDomainMask, YES); 451 NSString *documentsDirectory = [paths objectAtIndex:0]; 452 NSString *filename = [documentsDirectory 453 stringByAppendingPathComponent:@"theFile.txt"]; 454 455 获取tmp目录 456 NSString *tempPath = NSTemporaryDirectory(); 457 NSString *tempFile = [tempPath stringByAppendingPathComponent:@"tempFile.txt"]; 458 459 [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"someKey"]; 460 [[NSUserDefaults standardUserDefaults] objectForKey:aKey]; 461 462 自定义NavigationBar 463 navigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0, 0, 320, 44)]; 464 [navigationBar setBarStyle:UIBarStyleBlackOpaque]; 465 466 myNavigationItem = [[UINavigationItem alloc] initWithTitle:@"Setting"]; 467 [navigationBar setItems:[NSArray arrayWithObject:myNavigationItem]]; 468 [self.view addSubview:navigationBar]; 469 470 backButton = [[UIBarButtonItem alloc] initWithTitle:@"Back" style:UIBarButtonItemStylePlain target:self action:@selector(back)]; 471 myNavigationItem.leftBarButtonItem = backButton; 472 473 474 利用Safari打开一个链接 475 NSURL *url = [NSURL URLWithString:@"http://www.cnblogs.com/tracy-e/"]; 476 [[UIApplication sharedApplication] openURL:url]; 477 478 利用UIWebView显示pdf文件、网页。。。 479 webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; 480 [webView setDelegate:self]; 481 [webView setScalesPageToFit:YES]; 482 [webView setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight]; 483 [webView setAllowsInlineMediaPlayback:YES]; 484 [self.view addSubview:webView]; 485 NSString *pdfPath = [[NSBundle mainBundle] pathForResource:@"ojc" ofType:@"pdf"]; 486 NSURL *url = [NSURL fileURLWithPath:pdfPath]; 487 NSURLRequest *request = [NSURLRequest requestWithURL:url 488 cachePolicy:NSURLRequestUseProtocolCachePolicy 489 timeoutInterval:5]; 490 [webView loadRequest:request]; 491 492 493 [myWebView loadRequest:[NSURLRequest requestWithURL:[NSURL 494 URLWithString: @"http://www.cnblogs.com/tracy-e/"]]]; 495 496 NSString *errorString = [NSString stringWithFormat:@"<html><center><font size= 497 +5 color ='red'>An Error Occurred:<br>%@</fone></center></html>",error]; 498 [myWebView loadHTMLString:errorString baseURL:nil]; 499 500 //Stopping a load request when the view is to disappear 501 - (void)viewWillDisappear:(BOOL)animate{ 502 if ([myWebView loading]){ 503 [myWebView stopLoading]; 504 } 505 myWebView.delegate = nil; 506 [UIApplication shareApplication].networkActivityIndicatorVisible = NO; 507 } 508 509 汉字转码 510 NSString *oriString = @"\u67aa\u738b"; 511 NSString *escapedString = [oriString 512 stringByReplacingPercentEscapesUsingEncoding: NSUTF8StringEncoding]; 513 514 515 Checking for background support on earlier versions of iOS 516 UIDevice *device = [UIDevice currentDevice]; 517 BOOL backgroundSupported = NO; 518 if ([device respondsToSelector:@selector(isMultitaskingSupported)]){ 519 backgroundSupported = device.multitaskingSupported; 520 } 521 522 Being a Responsible,Multitasking-Aware Application 523 # Do not make any OpenGL ES calls from your code. 524 # Cancel any Bonjour-related services before being suspended. 525 # Be prepared to handle connection failures in your network-based sockets. 526 # Save your application state before moving to the background. 527 # Release any unneeded memory when moving to the background. 528 # Stop using shared system resources before being suspended. 529 # Avoid updating your windows and views. 530 # Respond to connect and disconnect notification for external accessories. 531 # Clean up resource for active alerts when moving to the background. 532 # Remove sensitive information from views before moving to the background. 533 # Do minimal work while running in the background. 534 535 Handing the Keyboard notifications 536 //Call this method somewhere in your view controller setup code 537 - (void) registerForKeyboardNotifications{ 538 539 [[NSNotificationCenter defaultCenter] addObserver:self 540 selector:@selector(keyboardWasShown:) 541 name:UIKeyboardDidShowNotification 542 object:nil]; 543 [[NSNotificationCenter defaultCenter] addObserver:self 544 selector:@selector(keyboardWasHidden:) 545 name:UIKeyboardDidHideNotification 546 object:nil]; 547 548 } 549 550 //Called when the UIKeyboardDidShowNotification is sent 551 - (void)keyboardWasShown:(NSNotification *) aNotification{ 552 if(keyboardShown) 553 return; 554 NSDictionary *info = [aNotification userInfo]; 555 556 //get the size of the keyboard. 557 NSValue *aValue = [info objectForKey:UIKeyboardFrameBeginUserInfoKey]; 558 CGSize keyboardSize = [aValue CGRectValue].size; 559 560 //Resize the scroll view 561 CGRect viewFrame = [scrollView frame]; 562 viewFrame.size.height -= keyboardSize.height; 563 564 //Scroll the active text field into view 565 CGRect textFieldRect = [activeField frame]; 566 [scrollView scrollRectToVisible:textFieldRect animated:YES]; 567 568 keyboardShown = YES; 569 } 570 571 //Called when the UIKeyboardDidHideNotification is sent 572 - (void)keyboardWasHidden:(NSNotification *) aNotification{ 573 NSDictionary *info = [aNotification userInfo]; 574 575 //Get the size of the keyboard. 576 NSValue *aValue = [info objectForKey:UIKeyboardFrameEndUserInfoKey]; 577 CGSize keyboardSize = [aValue CGRectValue].size; 578 579 //Reset the height of the scroll view to its original value 580 CGRect viewFrame = [scrollView Frame]; 581 viewFrame.size.height += keyboardSize.height; 582 scrollView.frame = viewFrame; 583 584 keyboardShown = NO; 585 } 586 587 点击键盘的next按钮,在不同的textField之间换行 588 //首先给不同的textField赋不同的且相邻的tag值 589 - (BOOL)textFieldShouldReturn:(UITextField *)textField 590 { 591 if ([textField returnKeyType] != UIReturnKeyDone) 592 { 593 NSInteger nextTag = [textField tag] + 1; 594 UIView *nextTextField = [[self tableView] viewWithTag:nextTag]; 595 [nextTextField becomeFirstResponder]; 596 } 597 else { 598 [textField resignFirstResponder]; 599 } 600 return YES; 601 } 602 603 Configuring a date formatter 604 - (void)viewDidLoad { 605 [super viewDidLoad]; 606 dateFormatter = [[NSDateFormatter alloc] init]; 607 [dateFormatter setGeneratesCalendarDates:YES]; 608 [dateFormatter setLocale:[NSLocale currentLocale]]; 609 [dateFormatter setCalendar:[NSCalendar autoupdatingCurrentCalendar]]; 610 [dateFormatter setTimeZone:[NSTimeZone defaultTimeZone]]; 611 [dateFormatter setDateStyle:NSDateFormatterShortStyle]; 612 DOB.placeholder = [NSString stringWithFormat:@"Example: %@",[dateFormatter stringFromDate:[NSDate date]]]; 613 } 614 615 - (void)textFieldDidEndEditing:(UITextField *)textField{ 616 [textField resignFirstResponder]; 617 if ([textField.text isEqualToString:@""]) 618 return; 619 switch (textField.tag){ 620 case DOBField: 621 NSDate *theDate = [dateFormatter dateFromString:textField.text]; 622 if (theDate) 623 [inputDate setObject:theDate forKey:MyAppPersonDOBKey]; 624 break; 625 default: 626 break; 627 } 628 } 629 630 tableView的cell高度 631 632 tableView的cell高度除了在delegate中指定外,还可以在任意位置以[tableView setRowHeight:44]的方式指定 633 634 [[self navigationItem] setLeftBarButtonItem:[self editButtonItem]]; 635 636 - (void)setEditing:(BOOL)editing animated:(BOOL)animated{ 637 [super setEditing:editing animated:animated]; 638 if (editing){ 639 ...... 640 } 641 else{ 642 ...... 643 } 644 } 645 646 One added a subview to a view, release the subview to avoid the extra retain count of it, Because when you insert a view as a subview using addSubview:, the subview is retained by its superview. When you remove the subview from its superview using the removeFromSuperview: method, subview is autoreleased. 647 648 为UINavigationBar设置背景图片 649 在iPhone开发中, 有时候我们想给导航条添加背景图片, 实现多样化的导航条效果, 用其他方法往往无法达到理想的效果, 经过网上搜索及多次实验, 确定如下最佳实现方案: 650 为UINavigatonBar增加如下Category(类别:提供一种为某个类添加方法而又不必编写子类的途径,类别只能添加成员函数,不能添加数据成员): 651 652 @implementation UINavigationBar (CustomImage) 653 - (void)drawRect:(CGRect)rect { 654 UIImage *image = [UIImage imageNamed: @"NavigationBar.png"]; 655 [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 656 } 657 @end 658 659 例如, 在我的项目中, 添加如下代码: 660 ///////////////////////////////////////////////////////// 661 /* input: The image and a tag to later identify the view */ 662 @implementation UINavigationBar (CustomImage) 663 - (void)drawRect:(CGRect)rect { 664 UIImage *image = [UIImage imageNamed: @"title_bg.png"]; 665 [image drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 666 } 667 @end 668 ///////////////////////////////////////////////////////// 669 @implementation FriendsPageViewController 670 // Implement viewDidLoad to do additional setup after loading the view, typically from a nib. 671 - (void)viewDidLoad { 672 self.navigationBar.tintColor = [UIColor purpleColor]; 673 674 [self initWithRootViewController:[[RegPageViewController alloc] init]]; 675 [super viewDidLoad]; 676 } 677 ...... 678 实现的效果如下图: 679 680 681 转载,原文地址 http://blog.csdn.net/wave_1102/archive/2009/11/04/4768212.aspx 682 683 为UINavigationBar添加自定义背景 684 685 @implementation UINavigationBar (UINavigationBarCategory) 686 687 - (void)drawRect:(CGRect)rect { 688 //颜色填充 689 // UIColor *color = [UIColor redColor]; 690 // CGContextRef context = UIGraphicsGetCurrentContext(); 691 // CGContextSetFillColor(context, CGColorGetComponents( [color CGColor])); 692 // CGContextFillRect(context, rect); 693 // self.tintColor = color; 694 //图片填充 695 UIColor *color = [UIColor colorWithRed:46.0f/255.0f 696 green:87.0f/255.0f blue:29.0f/255.0f alpha:1.0f]; 697 698 UIImage *img = [UIImage imageNamed: @"bg.png"]; 699 [img drawInRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height)]; 700 701 self.tintColor = color; 702 } 703 704 @end 705 706 加载图片要及时release 707 708 你还在使用myImage = [UIImage imageNamed:@"icon.png"]; 吗? 709 710 如题,是不是大家为了方便都这样加载图片啊 711 712 myImage = [UIImage imageNamed:@"icon.png"]; 713 714 那么小心了 715 716 这种方法在一些图片很少,或者图片很小的程序里是ok的。 717 718 但是,在大量加载图片的程序里,请千万不要这样做。 719 720 为什么呢 ??????? 721 722 这种方法在application bundle的顶层文件夹寻找由供应的名字的图象。 如果找到图片,装载到iPhone系统缓存图象。那意味图片是(理论上)放在内存里作为cache的。 723 724 试想你图片多了,是什么后果? 725 726 图片cache极有可能不会响应 memory warnings and release its objects 727 728 所以,用图片的时候一定要小心的alloc和release。 729 730 推荐使用 NSString *path = [[NSBundle mainBundle] pathForResource:@"icon" ofType:@"png"]; 731 732 myImage = [UIImage imageWithContentsOfFile:path]; 733 734 // Todo use of myImage 735 736 [myImage release]; 737 738 From: http://www.cocoachina.com/bbs/simple/?t27420.html 739 740 uiwebview打开doc,pdf文件 741 UIWebView *webView = [[UIWebView alloc]initWithFrame:CGRectMake(0, 55, 320, 300)]; 742 webView.delegate = self; 743 webView.multipleTouchEnabled = YES; 744 webView.scalesPageToFit = YES; 745 746 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 747 NSString *documentsDirectory = [paths objectAtIndex:0]; 748 NSString *docPath = [documentsDirectory stringByAppendingString:@"/doc2003_1.doc"]; NSLog(@"#######%@",docPath); 749 750 NSURL *url = [NSURL fileURLWithPath:docPath]; 751 NSURLRequest *request = [NSURLRequest requestWithURL:url]; 752 [webView loadRequest:request]; 753 754 [self.view addSubview:webView]; 755 [webView release]; 756 757 From:http://blog.csdn.net/dadalan/archive/2010/10/22/5959301.aspx 758 759 iPhone游戏中既播放背景音乐又播放特效声音的办法 760 761 有时候在 iPhone 游戏中,既要播放背景音乐,同时又要播放比如枪的开火音效。此时您可以试试以下方法 762 763 NSString *musicFilePath = [[NSBundle mainBundle] pathForResource:fileName ofType:@"wav"]; //创建音乐文件路径 764 NSURL *musicURL = [[NSURL alloc] initFileURLWithPath:musicFilePath]; 765 AVAudioPlayer* musicPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:musicURL error:nil]; 766 [musicURL release]; 767 [musicPlayer prepareToPlay]; 768 //[musicPlayer setVolume:1]; //设置音量大小 769 //musicPlayer .numberOfLoops = -1;//设置音乐播放次数 -1为一直循环 770 771 要导入框架 AVFoundation.framework,头文件中 #import <AVFoundation/AVFoundation.h>;做成类的话则更方便。 772 773 From: http://blog.csdn.net/dadalan/archive/2010/10/19/5950493.aspx 774 775 NSNotificationCenter用于增加回调函数 776 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_willBecomeActive) name:UIApplicationDidBecomeActiveNotification object:nil]; 777 778 UINavigationBar 背景Hack 779 LOGO_320×44.png 图片显示在背景上, 780 781 @implementation UINavigationBar (UINavigationBarCategory) 782 - (void)drawRect:(CGRect)rect { 783 //加入旋转坐标系代码 784 // Drawing code 785 UIImage *navBarImage = [UIImage imageNamed:@"LOGO_320×44.png"]; 786 CGContextRef context = UIGraphicsGetCurrentContext(); 787 CGContextTranslateCTM(context, 0.0, self.frame.size.height); 788 CGContextScaleCTM(context, 1.0, -1.0); 789 790 CGPoint center=self.center; 791 792 CGImageRef cgImage= CGImageCreateWithImageInRect(navBarImage.CGImage, CGRectMake(0, 0, 1, 44)); 793 CGContextDrawImage(context, CGRectMake(center.x-160-80, 0, 80, self.frame.size.height), cgImage); 794 CGContextDrawImage(context, CGRectMake(center.x-160, 0, 320, self.frame.size.height), navBarImage.CGImage); 795 CGContextDrawImage(context, CGRectMake(center.x+160, 0, 80, self.frame.size.height), cgImage); 796 } 797 @end 798 799 old code 800 CGContextDrawImage(context, CGRectMake(0, 0, self.frame.size.width, self.frame.size.height), navBarImage.CGImage); 801 802 hack 过logo 不再拉伸 803 804 From: http://blog.163.com/fengyi1103@126/blog/static/13835627420106279102671/ 805 806 清除电话号码中的其他符号(源码) 807 808 最近从通讯录读取电话号码,读出得号码如:134-1814-****。 809 而我需要的为11位纯数字,一直找方法解决此问题,今天终于找到了。。 810 分享一下…… 811 812 代码如下: 813 814 NSString *originalString = @"(123) 123123 abc"; 815 NSMutableString *strippedString = [NSMutableString 816 stringWithCapacity:originalString.length]; 817 818 NSScanner *scanner = [NSScanner scannerWithString:originalString]; 819 NSCharacterSet *numbers = [NSCharacterSet 820 characterSetWithCharactersInString:@"0123456789"]; 821 822 while ([scanner isAtEnd] == NO) { 823 NSString *buffer; 824 if ([scanner scanCharactersFromSet:numbers intoString:&buffer]) { 825 [strippedString appendString:buffer]; 826 } 827 // --------- Add the following to get out of endless loop 828 else { 829 [scanner setScanLocation:([scanner scanLocation] + 1)]; 830 } 831 // --------- End of addition 832 } 833 834 NSLog(@"%@", strippedString); // "123123123" 835 836 From: http://stackoverflow.com/questions/1129521/remove-all-but-numbers-from-nsstring 837 838 839 正则判断:字符串只包含字母和数字 840 841 NSString *mystring = @"Letter1234"; 842 NSString *regex = @"[a-z][A-Z][0-9]"; 843 844 NSPredicate *predicate = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; 845 846 if ([predicate evaluateWithObject:mystring] == YES) { 847 //implement 848 } 849 850 851 一行代码设置 UITableViewCell 与导航条间距 852 853 UITableView 的 cell 默认出现在 uitableview 的第一行,如果你想自定义 UITableViewCell 与导航条间距的话,可以使用下面这行代码 854 855 tableview.tableHeaderView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 5, 20)]autorelease]; 856 857 From: http://blog.163.com/fengyi1103@126/blog/static/1383562742010101611107492/ 858 859 860 修改 UITableview 滚动条颜色的方法 861 862 UITableview 的滚动条默认颜色是黑色的,如果 UItableview 背景也是深颜色,则滚动条会变的很不明显。您可以用下面这行代码来改变滚动条的颜色 863 864 self.tableView.indicatorStyle=UIScrollViewIndicatorStyleWhite; 865 866 当然,最后的 “White” 也可以换成其它颜色。 867 868 869 下文件之前获取到文件大小的代码 870 871 下面这段代码,能实现在下载文件之前获得文件大小,应用在软件里,能在很大程度上改善用户体验 872 873 [m_pASIHTTPRequest setDidReceiveResponseHeadersSelector:@selector(didReceiveResponseHeaders:)]; 874 875 - (void)didReceiveResponseHeaders:(ASIHTTPRequest *)request 876 { 877 NSLog(@"didReceiveResponseHeaders %@",[m_request.responseHeaders valueForKey:@"Content-Length"]); 878 } 879 880 网络编程总结 iphone 881 882 一:确认网络环境3G/WIFI 883 884 1. 添加源文件和framework 885 886 开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息。如果没有处理它们,是不会通过Apple的审(我们的)查的。 887 Apple 的 例程 Reachability 中介绍了取得/检测网络状态的方法。要在应用程序程序中使用Reachability,首先要完成如下两部: 888 889 1.1. 添加源文件: 890 在你的程序中使用 Reachability 只须将该例程中的 Reachability.h 和 Reachability.m 拷贝到你的工程中。如下图: 891 892 893 894 1.2.添加framework: 895 将SystemConfiguration.framework 添加进工程。如下图: 896 897 898 2. 网络状态 899 900 Reachability.h中定义了三种网络状态: 901 typedef enum { 902 NotReachable = 0, //无连接 903 ReachableViaWiFi, //使用3G/GPRS网络 904 ReachableViaWWAN //使用WiFi网络 905 } NetworkStatus; 906 907 因此可以这样检查网络状态: 908 909 Reachability *r = [Reachability reachabilityWithHostName:@“www.apple.com”]; 910 switch ([r currentReachabilityStatus]) { 911 case NotReachable: 912 // 没有网络连接 913 break; 914 case ReachableViaWWAN: 915 // 使用3G网络 916 break; 917 case ReachableViaWiFi: 918 // 使用WiFi网络 919 break; 920 } 921 922 3.检查当前网络环境 923 程序启动时,如果想检测可用的网络环境,可以像这样 924 // 是否wifi 925 + (BOOL) IsEnableWIFI { 926 return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable); 927 } 928 929 // 是否3G 930 + (BOOL) IsEnable3G { 931 return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable); 932 } 933 例子: 934 - (void)viewWillAppear:(BOOL)animated { 935 if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) && 936 ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) { 937 self.navigationItem.hidesBackButton = YES; 938 [self.navigationItem setLeftBarButtonItem:nil animated:NO]; 939 } 940 } 941 942 4. 链接状态的实时通知 943 网络连接状态的实时检查,通知在网络应用中也是十分必要的。接续状态发生变化时,需要及时地通知用户: 944 945 Reachability 1.5版本 946 // My.AppDelegate.h 947 #import "Reachability.h" 948 949 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 950 NetworkStatus remoteHostStatus; 951 } 952 953 @property NetworkStatus remoteHostStatus; 954 955 @end 956 957 // My.AppDelegate.m 958 #import "MyAppDelegate.h" 959 960 @implementation MyAppDelegate 961 @synthesize remoteHostStatus; 962 963 // 更新网络状态 964 - (void)updateStatus { 965 self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus]; 966 } 967 968 // 通知网络状态 969 - (void)reachabilityChanged:(NSNotification *)note { 970 [self updateStatus]; 971 if (self.remoteHostStatus == NotReachable) { 972 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil) 973 message:NSLocalizedString (@"NotReachable", nil) 974 delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 975 [alert show]; 976 [alert release]; 977 } 978 } 979 980 // 程序启动器,启动网络监视 981 - (void)applicationDidFinishLaunching:(UIApplication *)application { 982 983 // 设置网络检测的站点 984 [[Reachability sharedReachability] setHostName:@"www.apple.com"]; 985 [[Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES]; 986 // 设置网络状态变化时的通知函数 987 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) 988 name:@"kNetworkReachabilityChangedNotification" object:nil]; 989 [self updateStatus]; 990 } 991 992 - (void)dealloc { 993 // 删除通知对象 994 [[NSNotificationCenter defaultCenter] removeObserver:self]; 995 [window release]; 996 [super dealloc]; 997 } 998 999 Reachability 2.0版本 1000 1001 1002 // MyAppDelegate.h 1003 @class Reachability; 1004 1005 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 1006 Reachability *hostReach; 1007 } 1008 1009 @end 1010 1011 // MyAppDelegate.m 1012 - (void)reachabilityChanged:(NSNotification *)note { 1013 Reachability* curReach = [note object]; 1014 NSParameterAssert([curReach isKindOfClass: [Reachability class]]); 1015 NetworkStatus status = [curReach currentReachabilityStatus]; 1016 1017 if (status == NotReachable) { 1018 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AppName"" 1019 message:@"NotReachable" 1020 delegate:nil 1021 cancelButtonTitle:@"YES" otherButtonTitles:nil]; 1022 [alert show]; 1023 [alert release]; 1024 } 1025 } 1026 1027 - (void)applicationDidFinishLaunching:(UIApplication *)application { 1028 // ... 1029 1030 // 监测网络情况 1031 [[NSNotificationCenter defaultCenter] addObserver:self 1032 selector:@selector(reachabilityChanged:) 1033 name: kReachabilityChangedNotification 1034 object: nil]; 1035 hostReach = [[Reachability reachabilityWithHostName:@"www.google.com"] retain]; 1036 hostReach startNotifer]; 1037 // ... 1038 } 1039 1040 1041 二:使用NSConnection下载数据 1042 1043 1.创建NSConnection对象,设置委托对象 1044 1045 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]]]; 1046 [NSURLConnection connectionWithRequest:request delegate:self]; 1047 1048 2. NSURLConnection delegate委托方法 1049 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; 1050 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; 1051 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; 1052 - (void)connectionDidFinishLoading:(NSURLConnection *)connection; 1053 1054 3. 实现委托方法 1055 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 1056 // store data 1057 [self.receivedData setLength:0]; //通常在这里先清空接受数据的缓存 1058 } 1059 1060 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 1061 /* appends the new data to the received data */ 1062 [self.receivedData appendData:data]; //可能多次收到数据,把新的数据添加在现有数据最后 1063 } 1064 1065 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 1066 // 错误处理 1067 } 1068 1069 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 1070 // disconnect 1071 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 1072 NSString *returnString = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; 1073 NSLog(returnString); 1074 [self urlLoaded:[self urlString] data:self.receivedData]; 1075 firstTimeDownloaded = YES; 1076 } 1077 1078 三:使用NSXMLParser解析xml文件 1079 1080 1. 设置委托对象,开始解析 1081 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //或者也可以使用initWithContentsOfURL直接下载文件,但是有一个原因不这么做: 1082 // It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable 1083 // because it gives less control over the network, particularly in responding to connection errors. 1084 [parser setDelegate:self]; 1085 [parser parse]; 1086 1087 2. 常用的委托方法 1088 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 1089 namespaceURI:(NSString *)namespaceURI 1090 qualifiedName:(NSString *)qName 1091 attributes:(NSDictionary *)attributeDict; 1092 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 1093 namespaceURI:(NSString *)namespaceURI 1094 qualifiedName:(NSString *)qName; 1095 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; 1096 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError; 1097 1098 static NSString *feedURLString = @"http://www.yifeiyang.net/test/test.xml"; 1099 1100 3. 应用举例 1101 - (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error 1102 { 1103 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL]; 1104 [parser setDelegate:self]; 1105 [parser setShouldProcessNamespaces:NO]; 1106 [parser setShouldReportNamespacePrefixes:NO]; 1107 [parser setShouldResolveExternalEntities:NO]; 1108 [parser parse]; 1109 NSError *parseError = [parser parserError]; 1110 if (parseError && error) { 1111 *error = parseError; 1112 } 1113 [parser release]; 1114 } 1115 1116 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1117 qualifiedName:(NSString*)qName attributes:(NSDictionary *)attributeDict{ 1118 // 元素开始句柄 1119 if (qName) { 1120 elementName = qName; 1121 } 1122 if ([elementName isEqualToString:@"user"]) { 1123 // 输出属性值 1124 NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]); 1125 } 1126 } 1127 1128 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1129 qualifiedName:(NSString *)qName 1130 { 1131 // 元素终了句柄 1132 if (qName) { 1133 elementName = qName; 1134 } 1135 } 1136 1137 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 1138 { 1139 // 取得元素的text 1140 } 1141 1142 NSError *parseError = nil; 1143 [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError]; 1144 1145 Iphone 实现画折线图 1146 1147 iphone里面要画图一般都是通过CoreGraphics.framwork和QuartzCore.framwork实现,apple的官方sdk demon中包含了QuartzCore的基本用法, 1148 1149 1150 具体demo请参考http://developer.apple.com/library/ios/#samplecode/QuartzDemo/ 1151 折线图 1152 1153 1154 要实现折线图也就把全部的点连起来,movePointLineto,具体的调用里面的api就可以实现了,但是画坐标就比较麻烦了,里面需要去转很多,好在国外有人开源了一个画折线图的开发包,首先看看效果吧,具体怎么用可以参考作者git版本库中的wiki。 1155 http://github.com/devinross/tapkulibrary/wiki/How-To-Use-This-Library 1156 1157 这个包还提供了其他的很好看的UI,都可以调来用,但是我们只需要一个画图要把整个包都导进去,工程太大了,既然是开源的那就想办法提取出来吧,原先之前也有人干过这样的事。http://duivesteyn.net/2010/03/07/iphone-sdk-implementing-the-tapku-graph-in-your-application/ 1158 我对源代码进行简单的修改,使其显示坐标之类的,更加符合工程的需要,但是还没有实现画多组数据,只能画一组数据,不用viewContol,而使用addsubview,直接添加到当前的窗口,最终效果如下。 1159 使用方法: 1160 1161 1.工程添加tk库里面的如下文件 1162 1163 2. 添加QuartzCore framework 1164 #import <QuartzCore/QuartzCore.h> 1165 添加TapkuLibrary.bundle资源文件 1166 3.代码中完成实例,数据初始化就可以用了 1167 1168 下载修改后的版本。下次有时间在整理一个工程版本出来。 1169 1170 让iPhone屏幕常亮不变暗的方法 1171 1172 如果您希望运行自己开发的App时,iPhone的屏幕不再自动变暗,可以使用以下方法让屏幕常亮: iPhone OS用一个布尔值用来控制是否取消应用程序空闲时间:@property(nonatomic, getter=isIdleTime 1173 1174 如果您希望运行自己开发的App时,iPhone的屏幕不再自动变暗,可以使用以下方法让屏幕常亮: 1175 1176 iPhone OS用一个布尔值用来控制是否取消应用程序空闲时间:@property(nonatomic, getter=isIdleTimerDisabled) BOOL idleTimerDisabled。这个值的默认属性是"NO"。当大多数应用程序没有接收到用户输入信息的时候,系统会把设备设置成“休眠”状态,iPhone屏幕也会变暗。这样做是为了保存更多电量。事实上,应用程序在运行加速度游戏的时候是不需要用户输入的,当然这里只是一个假设,把这个变量设置为"YES",来取消系统休眠的“空闲时间”。 1177 1178 重点是:你必须当真正需要的时候才打开这个属性当你不用的时候马上还愿成"NO"。大多数应用程序在休眠时间到的时候让系统关闭屏幕。这个包括了有音频的应用程 序。在Audio Session Services中使用适当的回放和记录功能不会被间断当屏幕关闭时。只有地图应用程序,游戏或者一些不间断的用户交互程序可以取消这个属性。 1179 1180 苹果开发网络编程知识总结 1181 1182 以下苹果开发网络编程知识由 CocoaChina 会员 cocoa_yang 总结,希望能为苹果开发新手梳理知识脉络,节省入门时间。一:确认网络环境3G/WIFI 1. 添加源文件和framework 开发Web等网络应用程序 1183 1184 以下苹果开发网络编程知识由 CocoaChina 会员 “cocoa_yang” 总结,希望能为苹果开发新手梳理知识脉络,节省入门时间。 1185 1186 一:确认网络环境3G/WIFI 1187 1188 1. 添加源文件和framework 1189 1190 开发Web等网络应用程序的时候,需要确认网络环境,连接情况等信息。如果没有处理它们,是不会通过Apple的审查的。 1191 Apple 的 例程 Reachability 中介绍了取得/检测网络状态的方法。要在应用程序程序中使用Reachability,首先要完成如下两部: 1192 1193 1.1. 添加源文件: 1194 在你的程序中使用 Reachability 只须将该例程中的 Reachability.h 和 Reachability.m 拷贝到你的工程中。如下图: 1195 1196 1.2.添加framework: 1197 将SystemConfiguration.framework 添加进工程。如下图: 1198 1199 1200 2. 网络状态 1201 1202 Reachability.h中定义了三种网络状态: 1203 typedef enum { 1204 NotReachable = 0, //无连接 1205 ReachableViaWiFi, //使用3G/GPRS网络 1206 ReachableViaWWAN //使用WiFi网络 1207 } NetworkStatus; 1208 1209 因此可以这样检查网络状态: 1210 1211 Reachability *r = [Reachability reachabilityWithHostName:@“www.apple.com”]; 1212 switch ([r currentReachabilityStatus]) { 1213 case NotReachable: 1214 // 没有网络连接 1215 break; 1216 case ReachableViaWWAN: 1217 // 使用3G网络 1218 break; 1219 case ReachableViaWiFi: 1220 // 使用WiFi网络 1221 break; 1222 } 1223 1224 3.检查当前网络环境 1225 1226 程序启动时,如果想检测可用的网络环境,可以像这样 1227 // 是否wifi 1228 + (BOOL) IsEnableWIFI { 1229 return ([[Reachability reachabilityForLocalWiFi] currentReachabilityStatus] != NotReachable); 1230 } 1231 1232 // 是否3G 1233 + (BOOL) IsEnable3G { 1234 return ([[Reachability reachabilityForInternetConnection] currentReachabilityStatus] != NotReachable); 1235 } 1236 例子: 1237 - (void)viewWillAppear:(BOOL)animated { 1238 if (([Reachability reachabilityForInternetConnection].currentReachabilityStatus == NotReachable) && 1239 ([Reachability reachabilityForLocalWiFi].currentReachabilityStatus == NotReachable)) { 1240 self.navigationItem.hidesBackButton = YES; 1241 [self.navigationItem setLeftBarButtonItem:nil animated:NO]; 1242 } 1243 } 1244 1245 4. 链接状态的实时通知 1246 1247 网络连接状态的实时检查,通知在网络应用中也是十分必要的。接续状态发生变化时,需要及时地通知用户: 1248 1249 Reachability 1.5版本 1250 // My.AppDelegate.h 1251 #import "Reachability.h" 1252 1253 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 1254 NetworkStatus remoteHostStatus; 1255 } 1256 1257 @property NetworkStatus remoteHostStatus; 1258 1259 @end 1260 1261 // My.AppDelegate.m 1262 #import "MyAppDelegate.h" 1263 1264 @implementation MyAppDelegate 1265 @synthesize remoteHostStatus; 1266 1267 // 更新网络状态 1268 - (void)updateStatus { 1269 self.remoteHostStatus = [[Reachability sharedReachability] remoteHostStatus]; 1270 } 1271 1272 // 通知网络状态 1273 - (void)reachabilityChanged:(NSNotification *)note { 1274 [self updateStatus]; 1275 if (self.remoteHostStatus == NotReachable) { 1276 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"AppName", nil) 1277 message:NSLocalizedString (@"NotReachable", nil) 1278 delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil]; 1279 [alert show]; 1280 [alert release]; 1281 } 1282 } 1283 1284 // 程序启动器,启动网络监视 1285 - (void)applicationDidFinishLaunching:(UIApplication *)application { 1286 1287 // 设置网络检测的站点 1288 [[Reachability sharedReachability] setHostName:@"www.apple.com"]; 1289 [[Reachability sharedReachability] setNetworkStatusNotificationsEnabled:YES]; 1290 // 设置网络状态变化时的通知函数 1291 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(reachabilityChanged:) 1292 name:@"kNetworkReachabilityChangedNotification" object:nil]; 1293 [self updateStatus]; 1294 } 1295 1296 - (void)dealloc { 1297 // 删除通知对象 1298 [[NSNotificationCenter defaultCenter] removeObserver:self]; 1299 [window release]; 1300 [super dealloc]; 1301 } 1302 1303 Reachability 2.0版本 1304 1305 1306 // MyAppDelegate.h 1307 @class Reachability; 1308 1309 @interface MyAppDelegate : NSObject <UIApplicationDelegate> { 1310 Reachability *hostReach; 1311 } 1312 1313 @end 1314 1315 // MyAppDelegate.m 1316 - (void)reachabilityChanged:(NSNotification *)note { 1317 Reachability* curReach = [note object]; 1318 NSParameterAssert([curReach isKindOfClass: [Reachability class]]); 1319 NetworkStatus status = [curReach currentReachabilityStatus]; 1320 1321 if (status == NotReachable) { 1322 UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"AppName"" 1323 message:@"NotReachable" 1324 delegate:nil 1325 cancelButtonTitle:@"YES" otherButtonTitles:nil]; 1326 [alert show]; 1327 [alert release]; 1328 } 1329 } 1330 1331 - (void)applicationDidFinishLaunching:(UIApplication *)application { 1332 // ... 1333 1334 // 监测网络情况 1335 [[NSNotificationCenter defaultCenter] addObserver:self 1336 selector:@selector(reachabilityChanged:) 1337 name: kReachabilityChangedNotification 1338 object: nil]; 1339 hostReach = [[Reachability reachabilityWithHostName:@"www.google.com"] retain]; 1340 hostReach startNotifer]; 1341 // ... 1342 } 1343 1344 1345 二:使用NSConnection下载数据 1346 1347 1.创建NSConnection对象,设置委托对象 1348 1349 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[self urlString]]]; 1350 [NSURLConnection connectionWithRequest:request delegate:self]; 1351 1352 2. NSURLConnection delegate委托方法 1353 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response; 1354 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error; 1355 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data; 1356 - (void)connectionDidFinishLoading:(NSURLConnection *)connection; 1357 1358 3. 实现委托方法 1359 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { 1360 // store data 1361 [self.receivedData setLength:0]; //通常在这里先清空接受数据的缓存 1362 } 1363 1364 - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { 1365 /* appends the new data to the received data */ 1366 [self.receivedData appendData:data]; //可能多次收到数据,把新的数据添加在现有数据最后 1367 } 1368 1369 - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { 1370 // 错误处理 1371 } 1372 1373 - (void)connectionDidFinishLoading:(NSURLConnection *)connection { 1374 // disconnect 1375 [UIApplication sharedApplication].networkActivityIndicatorVisible = NO; 1376 NSString *returnString = [[NSString alloc] initWithData:self.receivedData encoding:NSUTF8StringEncoding]; 1377 NSLog(returnString); 1378 [self urlLoaded:[self urlString] data:self.receivedData]; 1379 firstTimeDownloaded = YES; 1380 } 1381 1382 三:使用NSXMLParser解析xml文件 1383 1384 1. 设置委托对象,开始解析 1385 NSXMLParser *parser = [[NSXMLParser alloc] initWithData:data]; //或者也可以使用initWithContentsOfURL直接下载文件,但是有一个原因不这么做: 1386 // It's also possible to have NSXMLParser download the data, by passing it a URL, but this is not desirable 1387 // because it gives less control over the network, particularly in responding to connection errors. 1388 [parser setDelegate:self]; 1389 [parser parse]; 1390 1391 2. 常用的委托方法 1392 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName 1393 namespaceURI:(NSString *)namespaceURI 1394 qualifiedName:(NSString *)qName 1395 attributes:(NSDictionary *)attributeDict; 1396 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName 1397 namespaceURI:(NSString *)namespaceURI 1398 qualifiedName:(NSString *)qName; 1399 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string; 1400 - (void)parser:(NSXMLParser *)parser parseErrorOccurred:(NSError *)parseError; 1401 1402 static NSString *feedURLString = @"http://www.yifeiyang.net/test/test.xml"; 1403 1404 3. 应用举例 1405 - (void)parseXMLFileAtURL:(NSURL *)URL parseError:(NSError **)error 1406 { 1407 NSXMLParser *parser = [[NSXMLParser alloc] initWithContentsOfURL:URL]; 1408 [parser setDelegate:self]; 1409 [parser setShouldProcessNamespaces:NO]; 1410 [parser setShouldReportNamespacePrefixes:NO]; 1411 [parser setShouldResolveExternalEntities:NO]; 1412 [parser parse]; 1413 NSError *parseError = [parser parserError]; 1414 if (parseError && error) { 1415 *error = parseError; 1416 } 1417 [parser release]; 1418 } 1419 1420 - (void)parser:(NSXMLParser *)parser didStartElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1421 qualifiedName:(NSString*)qName attributes:(NSDictionary *)attributeDict{ 1422 // 元素开始句柄 1423 if (qName) { 1424 elementName = qName; 1425 } 1426 if ([elementName isEqualToString:@"user"]) { 1427 // 输出属性值 1428 NSLog(@"Name is %@ , Age is %@", [attributeDict objectForKey:@"name"], [attributeDict objectForKey:@"age"]); 1429 } 1430 } 1431 1432 - (void)parser:(NSXMLParser *)parser didEndElement:(NSString *)elementName namespaceURI:(NSString *)namespaceURI 1433 qualifiedName:(NSString *)qName 1434 { 1435 // 元素终了句柄 1436 if (qName) { 1437 elementName = qName; 1438 } 1439 } 1440 1441 - (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string 1442 { 1443 // 取得元素的text 1444 } 1445 1446 NSError *parseError = nil; 1447 [self parseXMLFileAtURL:[NSURL URLWithString:feedURLString] parseError:&parseError]; 1448 1449 如何隐藏状态栏 1450 [ UIApplication sharedApplication ].statusBarHidden = YES; 1451 1452 .m 文件与.mm文件的区别 1453 .m文件是object-c文件 1454 .mm文件相当于c++或者c文件 1455 1456 NSLog(@"afd")与 NSLog("afd") 1457 1458 细微差别会导致程序崩溃。 1459 1460 但是我不太明白为何苹果要把编译器做的对这两种常量有区别。 1461 1462 不过值得一提的是可能为了方便苹果自身的NSObject对象的格式化输出。 1463 1464 safari其实没有把内存的缓存写到存储卡上 1465 1466 NSURLCache doesn't seem to support writing to disk on iPhone. The documentation for NSCachedURLResponse says that the NSURLCacheStoragePolicy "NSURLCacheStorageAllowed" is treated as "NSURLCacheStorageAllowedInMemoryOnly" by iPhone OS. 1467 1468 官方文档是这么说的。 1469 1470 为了证明这个,我找到了一个目录。 1471 1472 /private/var/mobile/Library/Caches/Safari/Thumbnails 1473 1474 随机数的使用 1475 1476 头文件的引用 1477 #import <time.h> 1478 #import <mach/mach_time.h> 1479 1480 srandom()的使用 1481 srandom((unsigned)(mach_absolute_time() & 0xFFFFFFFF)); 1482 1483 直接使用 random() 来调用随机数 1484 1485 在UIImageView 中旋转图像 1486 1487 float rotateAngle = M_PI; 1488 CGAffineTransform transform =CGAffineTransformMakeRotation(rotateAngle); 1489 imageView.transform = transform; 1490 1491 以上代码旋转imageView, 角度为rotateAngle, 方向可以自己测试哦! 1492 1493 1494 在Quartz中如何设置旋转点 1495 1496 UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bg.png"]]; 1497 imageView.layer.anchorPoint = CGPointMake(0.5, 1.0); 1498 1499 这个是把旋转点设置为底部中间。记住是在QuartzCore.framework中才得到支持。 1500 1501 创建.plist文件并存储 1502 1503 NSString *errorDesc; //用来存放错误信息 1504 NSMutableDictionary *rootObj = [NSMutableDictionary dictionaryWithCapacity:4]; //NSDictionary, NSData等文件可以直接转化为plist文件 1505 NSDictionary *innerDict; 1506 NSString *name; 1507 Player *player; 1508 NSInteger saveIndex; 1509 1510 for(int i = 0; i < [playerArray count]; i++) { 1511 player = nil; 1512 player = [playerArray objectAtIndex:i]; 1513 if(player == nil) 1514 break; 1515 name = player.playerName;// This "Player1" denotes the player name could also be the computer name 1516 innerDict = [self getAllNodeInfoToDictionary:player]; 1517 [rootObj setObject:innerDict forKey:name]; // This "Player1" denotes the person who start this game 1518 } 1519 player = nil; 1520 NSData *plistData = [NSPropertyListSerialization dataFromPropertyList:(id)rootObj format:NSPropertyListXMLFormat_v1_0 errorDescription:&errorDesc]; 1521 1522 红色部分可以忽略,只是给rootObj添加一点内容。这个plistData为创建好的plist文件,用其writeToFile方法就可以写成文件。下面是代码: 1523 1524 /*得到移动设备上的文件存放位置*/ 1525 NSString *documentsPath = [self getDocumentsDirectory]; 1526 NSString *savePath = [documentsPath stringByAppendingPathComponent:@"save.plist"]; 1527 1528 /*存文件*/ 1529 if (plistData) { 1530 [plistData writeToFile:savePath atomically:YES]; 1531 } 1532 else { 1533 NSLog(errorDesc); 1534 [errorDesc release]; 1535 } 1536 1537 - (NSString *)getDocumentsDirectory { 1538 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 1539 return [paths objectAtIndex:0]; 1540 } 1541 1542 读取plist文件并转化为NSDictionary 1543 1544 NSString *documentsPath = [self getDocumentsDirectory]; 1545 NSString *fullPath = [documentsPath stringByAppendingPathComponent:@"save.plist"]; 1546 NSMutableDictionary* plistDict = [[NSMutableDictionary alloc] initWithContentsOfFile:fullPath]; 1547 1548 读取一般性文档文件 1549 1550 NSString *tmp; 1551 NSArray *lines; /*将文件转化为一行一行的*/ 1552 lines = [[NSString stringWithContentsOfFile:@"testFileReadLines.txt"] 1553 componentsSeparatedByString:@"\n"]; 1554 1555 NSEnumerator *nse = [lines objectEnumerator]; 1556 1557 // 读取<>里的内容 1558 while(tmp = [nse nextObject]) { 1559 NSString *stringBetweenBrackets = nil; 1560 NSScanner *scanner = [NSScanner scannerWithString:tmp]; 1561 [scanner scanUpToString:@"<" intoString:nil]; 1562 [scanner scanString:@"<" intoString:nil]; 1563 [scanner scanUpToString:@">" intoString:&stringBetweenBrackets]; 1564 1565 NSLog([stringBetweenBrackets description]); 1566 } 1567 1568 对于读写文件,还有补充,暂时到此。随机数和文件读写在游戏开发中经常用到。所以把部分内容放在这,以便和大家分享,也当记录,便于查找。 1569 1570 隐藏NavigationBar 1571 [self.navigationController setNavigationBarHidden:YES animated:YES]; 1572 1573 在想隐藏的ViewController中使用就可以了。 1574 1575 如何在iPhone程序中调用外部命令 1576 1577 下面是如何在iPhone非官方SDK程序中调用外部命令的方法。 1578 1579 - ( NSString * ) executeCommand : ( NSString * ) cmd { NSString * output = [ NSString string ] ; FILE * pipe = popen ( [ cmd cStringUsingEncoding : NSASCIIStringEnc 1580    1581 下面是如何在iPhone非官方SDK程序中调用外部命令的方法。 1582 1583 - (NSString *)executeCommand: (NSString *)cmd 1584 { 1585 NSString *output = [NSString string]; 1586 FILE *pipe = popen([cmd cStringUsingEncoding: NSASCIIStringEncoding], "r"); 1587 if (!pipe) return; 1588 1589 char buf[1024]; 1590 while(fgets(buf, 1024, pipe)) { 1591 output = [output stringByAppendingFormat: @"%s", buf]; 1592 } 1593 1594 pclose(pipe); 1595 return output; 1596 } 1597 1598 NSString *yourcmd = [NSString stringWithFormat: @"your command"]; 1599 [self executeCommand: yourcmd]; 1600 1601 如何在iPhone程序读取数据时显示进度窗 1602 1603 下面代码说明如何使用iPhone 非官方SDK在读取数据时显示进度条。 1604 1605 以下代码参考了MobileRss。 1606 1607 定义头文件: 1608 1609 #import "uikit/UIProgressHUD.h" 1610 1611 @interface EyeCandy : UIApplication { 1612 UIProgressHUD *progress; 1613 } 1614 1615 - (void) showProgressHUD:(NSString *)label withWindow:(UIWindow *)w withView:(UIView *)v withRect:(struct CGRect)rect; 1616 - (void) hideProgressHUD; 1617 1618 .@end 1619 1620 上面的引号要改成<>。 1621 1622 import "EyeCandy.h" 1623 1624 @implementation EyeCandy 1625 - (void)showProgressHUD:(NSString *)label withWindow:(UIWindow *)w withView:(UIView *)v withRect:(struct CGRect)rect 1626 { 1627 progress = [[UIProgressHUD alloc] initWithWindow: w]; 1628 [progress setText: label]; 1629 [progress drawRect: rect]; 1630 [progress show: YES]; 1631 1632 [v addSubview:progress]; 1633 } 1634 1635 - (void)hideProgressHUD 1636 { 1637 [progress show: NO]; 1638 [progress removeFromSuperview]; 1639 } 1640 1641 @end 1642 1643 使用下面代码调用: 1644 1645 // Setup Eye Candy View 1646 _eyeCandy = [[[EyeCandy alloc] init] retain]; 1647 1648 // Call loading display 1649 [_eyeCandy showProgressHUD:@"Loading …" withWindow:window withView:mainView withRect:CGRectMake(0.0f, 100.0f, 320.0f, 50.0f)]; 1650 1651 // When finished for hiding the "loading text" 1652 [_eyeCandy hideProgressHUD]; 1653 1654 WebKit的基本用法 1655 1656 WebKit是苹果开发中比较常用的浏览器引擎,Safari使用的正是WebKit引擎。WebKit基于KDE的KHTML加以再开发,解析速度超过了以往所有的浏览器。这里简单记录一下WebKit的基本用法。 1657 1658 WebKit由下面的结构组成: 1659 1660 •DomCore 1661 •JavaScriptCore 1662 •WebCore 1663 一般浏览 1664 1665 要打开网页,可以这样做: 1666 1667 1.[[webView mainFrame] loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlText]]]; 1668 DomCore 1669 1670 DomCore用于处理DOM文档,包括: 1671 1672 •DOMDocument 1673 •DOMNamedNodeMap 1674 •DOMNode 1675 •DOMNodeList 1676 要获取一个DOMDocument,可以这样做: 1677 1678 1.DOMDocument *myDOMDocument = [[webView mainFrame] DOMDocument]; 1679 要用于HTML处理,可以使用DOMHTMLDocument(Mac OS X 10.4之后),获取方式相同: 1680 1681 1.DOMHTMLDocument *myDOMDocument = (DOMHTMLDocument*)[[webView mainFrame] DOMDocument]; 1682 方法定义: 1683 1684 苹果的WebKit更新说明 1685 1686 JavaScriptCore 1687 1688 在WebKit中执行脚本的方法: 1689 1690 1.WebScriptObject *myscript = [webView windowScriptObject]; 1691 2.NSString *script = @"alert('hello');"; 1692 3.[myscript evaluateWebScript script]; 1693 参考: 1694 1695 http://www.macgood.com/thread-24636-1-1.html 1696 1697 http://www.cocoadev.com/index.pl?WebKit 1698 1699 为什么不要做iPhone上面的应用 1700 1701 简单来说就是因为两国的文化不同,或者说生活方式的不同。美国不管多穷的人都有车,他们平时的生活方式和国内绝对是完全不同的。做应用和做游戏不一样,应用需要满足人们某一 1702   简单来说就是因为两国的文化不同,或者说生活方式的不同。美国不管多穷的人都有车,他们平时的生活方式和国内绝对是完全不同的。做应用和做游戏不一样,应用需要满足人们某一部分的需求,比如,一个计算小费的软件,在国内不会有市场,可是美国人都有一个。 1703 大家可以设身处地的想一下,谁会需要你做的软件,这样的人有多少,这样的人又有iPhone的又有多少。 1704 1705 对于应用来说,针对商务人士的又比针对普通人的好,基本上商务人士不太在乎几块钱一个软件,这也是backup assistant卖得最好的一个原因。这个软件一年的年费24美元,大约有数千万美元一年的收入。什么样的应用软件是这些人需要的?连笔者自己也不太清楚,笔者虽然已经在美国工作了多年,但是对于美国文化的了解还处于一知半解状态,更不用说正在留学的学生了。 1706 1707 还有一个能成功的应用软件是你已经有非常多的数据,比如你有当地的所有加油站的信息,做一个油价的地图软件,显然市场会不错。不过数据要是美国的数据,国内的没有太大的帮助。 1708 1709 综上所述,游戏比应用好做很多,如果要作应用的话,可以从单机的小应用开始。要在美国运营一个支持10万人的网络应用,没有30万美元绝对没戏。如果非要上,只能早死早超生了。 1710 1711 获取iPhone用户手机号 1712 1713 使用下面的函数可以返回用户的手机号: 1714 1715 extern NSString *CTSettingCopyMyPhoneNumber(); 1716 1717 然后调用即可。 1718 1719 由于这个函数是包含在CoreTelephony中,所以只能用于非官方iPhone SDK。 1720 1721 在程序中关闭iPhone 1722 首先在程序中引用 #include sys/reboot.h 然后使用 reboot(RB_HALT); 就可以直接将iPhone关机。 1723    1724 首先在程序中引用 1725 1726 #include <sys/reboot.h> 1727 1728 然后使用 1729 1730 reboot(RB_HALT); 1731 1732 就可以直接将iPhone关机。 1733 1734 convert the contents of an NSData object to an NSString 1735 1736 1. NSString *stringFromASC = [NSString stringWithCString:[ascData bytes] length:[ascData length]]; 1737 1738 If the NSData object contains unichar characters then do this: 1739 1740 NSString *stringFromUnichar = [NSString stringWithCharacters:[unicharData bytes] length:[unicharData length] / sizeof(unichar)]; 1741 1742 2. - (id)initWithData:(NSData *)data encoding:(NSStringEncoding)encoding 1743 1744 iPhone的特殊URL 1745 在iPhone中,可以直接用UIApp打开URL地址。如下所示: 1746 1747 1.[ UIApp openURL: [ NSURL URLWithString:@"http://www.apple.com" ] ]; 1748 或者: 1749 1750 1.[ UIApp openURL: [ NSURL URLWithString:@"mailto:apple@mac.com?Subject=hello" ] ]; 1751 与此同时,iPhone还包含一些其他除了http://或者mailto:之外的URL: 1752 1753 sms:// 可以调用短信程序 1754 1755 tel:// 可以拨打电话 1756 1757 itms:// 可以打开MobileStore.app 1758 1759 audio-player-event:// 可以打开iPod 1760 1761 audio-player-event://?uicmd=show-purchased-playlist 可以打开iPod播放列表 1762 1763 video-player-event:// 可以打开iPod中的视频 1764 1765 1766 get iphone uniqueIdentifier 1767 1768 I also find that I can get uniqueIdentifier using: 1769 1770 UIDevice *myDevice = [UIDevice currentDevice];NSString *identifier = myDevice.uniqueIdentifier; 1771 1772 1773 打开本地网页,与远程网页 1774 1775 fileURLWithPath:Initializes and returns a newly created NSURL object as a file URL with a specified path. 1776 1777 + (id)fileURLWithPath:(NSString *)path 1778 1779 URLWithString: 1780 Creates and returns an NSURL object initialized with a provided string. 1781 1782 + (id)URLWithString:(NSString *)URLString 1783 1784 教你如何使用UIWebView 1785 1786 Start by opening up the WebBrowserTutorialAppDelegate.h file and editing the @interface line to read: 1787 1788 @interface WebBrowserTutorialAppDelegate : NSObject <UIWebViewDelegate> { 1789 What we have done is to make the main AppDelegate a delegate for the UIWebView as well. 1790 1791 Now we need to set our webView to have the main AppDelegate as its delegate, you can do this by opening up WebBrowserTutorialAppDelegate.m and putting the following line just inside theapplicationDidFinishLaunching function: 1792 1793 webView.delegate = self; 1794 That is all pretty self explanatory, it just sets the delegate of our webView to self, which in this case is our main application delegate. 1795 1796 Now we are pretty much done, we just need to add the function to catch the link clicks. To do this we need to add a new function, copy the content below to the WebBrowserTutorialAppDelegate.m file: 1797 1798 - (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType { 1799 NSURL *url = request.URL; 1800 NSString *urlString = url.absoluteString; 1801 NSLog(urlString); 1802 return YES; 1803 } 1804 This function will catch all requests and allow you to either manipulate them and pass them on or to perform your own custom action and stop the event from bubbling. 1805 1806 The first line gets the URL of the request, this is the contents inside the href attribute in the anchor tag. 1807 The next line converts the URL to a string so we can log it out. You can access many parts of the NSURL, here are some of them and brief description of what they do. 1808 1809 * absoluteString - An absolute string for the URL. Creating by resolving the receiver’s string against its base. 1810 * absoluteURL - An absolute URL that refers to the same resource as the receiver. If the receiver is already absolute, returns self. 1811 * baseURL - The base URL of the receiver. If the receiver is an absolute URL, returns nil. 1812 * host - The host of the URL. 1813 * parameterString - The parameter string of the URL. 1814 * password - The password of the URL (i.e. http://user:pass@www.test.com would return pass) 1815 * path - Returns the path of a URL. 1816 * port - The port number of the URL. 1817 * query - The query string of the URL. 1818 * relativePath - The relative path of the URL without resolving against the base URL. If the receiver is an absolute URL, this method returns the same value as path. 1819 * relativeString - string representation of the relative portion of the URL. If the receiver is an absolute URL this method returns the same value as absoluteString. 1820 * scheme - The resource specifier of the URL (i.e. http, https, file, ftp, etc). 1821 * user - The user portion of the URL. 1822 1823 Then the third line simply logs the URL to the console, so you will new to open up the console while you run this in the simulator to see the results. 1824 1825 Finally the forth line returns YES, this will allow the UIWebView to follow the link, if you would just like to catch a link and stop the UIWebView from following it then simply return NO. 1826 1827 UIBUtton title image 不能同时显示 1828 1829 [ leftbutton setTitle:_(@"About") forState:UIControlStateNormal ]; 1830 1831 1832 [ leftbutton setImage:image forState:UIControlStateNormal ]; 1833 1834 不能同时显示。 1835 1836 其他控件如:UINavigatonItem 1837 1838 不要在语言包里面设置空格 1839 有时,为了界面的需要,我们不要在语言包里面加空格,要在程序中进行控制。 1840 buttonTitle = [ NSString stringWithFormat:@" %@", _(@"updateWeb") ]; 1841 1842 NSNotificationCenter 带参数发送 1843 1844 MPMoviePlayerController* theMovie = [[MPMoviePlayerController alloc]initWithContentURL:[NSURL fileURLWithPath:[[[tableTitles objectForKey:keyIndex] objectAtIndex:row] objectAtIndex:3] ]]; 1845 1846 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myMovieFinishedCallback:) name:MPMoviePlayerPlaybackDidFinishNotification object:theMovie]; 1847 1848 [theMovie play]; 1849 1850 -(void)myMovieFinishedCallback:(NSNotification*)aNotification 1851 1852 { 1853 1854 MPMoviePlayerController *theMovie = [aNotification object]; 1855 1856 [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:theMovie]; 1857 1858 // Release the movie instance [theMovie release]; 1859 1860 } 1861 1862 ------------ 1863 1864 MPMoviePlayerController* theMovie = [[MPMoviePlayerController alloc]initWithContentURL:[NSURL fileURLWithPath:[[[tableTitles objectForKey:keyIndex] objectAtIndex:row] objectAtIndex:3] ]]; 1865 1866 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(myMovieFinishedCallback:) name:MPMoviePlayerPlaybackDidFinishNotification object:theMovie userInfo:dic]; 1867 1868 [theMovie play]; 1869 1870 -(void)myMovieFinishedCallback:(NSNotification*)aNotification 1871 1872 { 1873 1874 MPMoviePlayerController *theMovie = [aNotification object]; 1875 1876 [[NSNotificationCenter defaultCenter] removeObserver:self name:MPMoviePlayerPlaybackDidFinishNotification object:theMovie]; 1877 1878 // Release the movie instance [theMovie release]; 1879 1880 } 1881 1882 延时一段时间执行某一函数 1883 1884 [self performSelector:@selector(dismissModal) withObject:self afterDelay:1.0]; 1885 1886 无99美金证书联机开发 1887 第一步:进入 cd /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.1.sdk/ sudo vi SDKSettings.plist,将CODE_SIGNING_REQUIRED的值改成NO. 保存后退出. 1888 1889 第二步:重新启动XCode项目. 1890 1891 第三步:右击项目GetInfo.将Code Signing下的Code Signing Identity值设置成Don't Code Sign, 将Code Signing Identity下的Any iOS Device的值设置成空. 1892 1893 获取IOS设备的基本信息 1894 系统唯一标识 1895 是什么设备:iPad还是iPhone等 1896 iOS版本号 1897 系统名称 1898 1899 [[UIDevice currentDevice] uniqueIdentifier], 1900 [[UIDevice currentDevice] localizedModel], 1901 [[UIDevice currentDevice] systemVersion], 1902 [[UIDevice currentDevice] systemName], 1903 [[UIDevice currentDevice] model]]; 1904 1905 用NSDateFormatter调整时间格式的代码 1906 1907 在开发iOS程序时,有时候需要将时间格式调整成自己希望的格式,这个时候我们可以用NSDateFormatter类来处理。 1908 例如: 1909 1910 //实例化一个NSDateFormatter对象 1911 1912 NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; 1913 1914 //设定时间格式,这里可以设置成自己需要的格式 1915 1916 [dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; 1917 1918 //用[NSDate date]可以获取系统当前时间 1919 1920 NSString *currentDateStr = [dateFormatter stringFromDate:[NSDate date]]; 1921 1922 //输出格式为:2010-10-27 10:22:13 1923 1924 NSLog(@”%@”,currentDateStr); 1925 1926 //alloc后对不使用的对象别忘了release 1927 1928 [dateFormatter release]; 1929 1930 UIView设置成圆角方法 1931 1932 m_mainImgView.layer.cornerRadius = 6; 1933 m_mainImgView.layer.masksToBounds = YES; 1934 1935 iPhone里的frame和bounds区别 1936 1937 1938 1939 Objective-C内存管理 1940 1941 在使用Objective-C的工作中内存管理是首先要学会的一项技能,是如此重要,就好比是男人就要追漂亮姑娘一样~~下面就来聊聊Apple官网上的内存管理的事情。 1942 1943 Objective-C的对象内存管理是一件非常有意思的事情,由其是在iPhone嵌入式设备中. 1944 1945 想玩的省心点,就得熟知它的管理规则,由其是内存的管理机制。了解它的品性了才能在Cocoa的世界里如鱼得水。否则,反之(如水得鱼!!^_^)。 1946 1947 首先,要牢记Apple的官网上的内存管理三定律: 1948 1949 1,一个对象可以有一个或多个拥有者 1950 1951 2,当它一个拥有都都没有时,它就会被回收 1952 1953 3,如果想保留一个对象不被回收,你就必需成为它的拥有者 1954 1955 1956 所有内存管理的原则全在这里!! 1957 1958 简单??哈哈! 1959 1960 名人曰:“大道至简” 1961 1962 这儿玩意儿说起来比过家家还容易,但其实有些事情真正做起来并不是简单的事儿~~ 1963 1964 咱们首先来说怎么样才能成为一个对象的拥有者。Cocoa提供了一个机制叫"reference counting",翻译过来就是“关联记数器”(自己翻译的,真不知叫啥,如果有官方的翻译请通知我)。每一个对象都有一个关联记数的值。当它被创建时,它的值为“1”。当值减少到“0”时,就会被回收(调用它的deallocate方法,如果没有写,则调用从NSObject继承而来的回收方法,下文有说,一定要重写该方法)。以下几个方法可以操作这个记数: 1965 1966 1,alloc 1967 为对象分配内存,记数设为“1”,并返回此对象。 1968 1969 2,copy 1970 复制一个对象,此对象记数为“1”,返回此对象。你将成为此克隆对象的拥有者 1971 1972 3,retain 1973 对象“关联记数”加“1”,并成为此对象的拥有者。 1974 1975 4,release 1976 对象“关联记数”减“1”,并丢掉此对象。 1977 1978 5,autorelease 1979 1980 在未来的某一时刻,对象“关联记数”减“1”。并在未来的某个时间放弃此对象。 1981 1982 有了上面的几个方法(当然这也是所有的内存操作的方法,简单吧,哈哈哈)你就可以随意操作一个对象的记数。并部分或完全的控制它的生命周期。但实际应用中,随意乱写上面的任何一个方法都可能会带来严重的内存泄露。混乱的内存分配等于没完没了的麻烦工作,你不想在情人节的日子还在为记数之类的鸟问题而丢了老婆吧~~哈哈哈,为了美丽温柔贤惠又善解人意的准老婆请牢记以下四条: 1983 1984 1,一个代码块内要确保copy, alloc 和 retain 的使用数量与 release 和 autorelease 的数量。 1985 1986 2,在使用以“alloc”或“new”开头或包含“copy”的方法,或“retain”一个对象时,你就会变为它的拥有者。 1987 1988 3,实现“dealloc”方法,并施放所有的实例变量。(其实这里还有很多的巧儿门!!) 1989 1990 4,永不自己调用“dealloc”方法,这是系统当“retain”减到“0”时,自动调用的。手动调用会引起retain count记数错误(多一次的release)。 1991 1992 其实做到这些也不难, 1993 1994 retain count 增加与减少的方法对应,板丁板做到了就行了。 1995 1996 来自:http://blog.csdn.net/dboylx/archive/2009/02/13/3888746.aspx 1997 1998 iphone更改键盘右下角按键的type 1999 2000 以UISearchBar为例。 2001 2002 2003 创建mySearchBar: 2004 2005 mySearchBar = [[UISearchBar alloc] initWithFrame:CGRectMake(0.0, 0,320, SEARCH_HEIGHT)]; 2006 mySearchBar.placeholder = curPath; 2007 [mySearchBar setDelegate:self]; 2008 //tableView.tableHeaderView =mySearchBar; 2009 [self.view addSubview:mySearchBar]; 2010 2011 2012 更改按键的keyType(默认是return,这里将它更改成done,当然还可以更改成其他的): 2013 UITextField *searchField = [[mySearchBar subviews] lastObject]; 2014 [searchField setReturnKeyType:UIReturnKeyDone]; 2015 [mySearchBar release];
文章
Web App开发  ·  缓存  ·  开发工具  ·  Android开发  ·  iOS开发
2013-08-01
kickstart无人值守自动安装操作系统
PXE是什么? PXE(Pre-boot Execution     Environment,预启动执行环境)是由Intel公司开发的最新技术,工作于Client/Server的网络模式,支持工作站通过网络从远端服务器下载映像,并由此支持通过网络启动操作系统,在启动过程中,终端要求服务器分配IP地址,再用TFTP(trivial     file transfer protocol)或MTFTP(multicast trivial file transfer     protocol)协议下载一个启动软件包到本机内存中执行,由这个启动软件包完成终端基本软件设置,从而引导预先安装在服务器中的终端操作系统。 严格来说,PXE 并不是一种安装方式,而是一种引导方式。进行 PXE 安装的必要条件是在要安装的计算机中必须包含一个 PXE 支持的网卡(NIC),即网卡中必须要有 PXE     Client。PXE 协议可以使计算机通过网络启动。此协议分为     Client端和 Server 端,而PXE     Client则在网卡的 ROM 中。当计算机引导时,BIOS 把 PXE     Client 调入内存中执行,然后由 PXE Client 将放置在远端的文件通过网络下载到本地运行。运行 PXE 协议需要设置 DHCP 服务器和 TFTP 服务器。DHCP 服务器会给 PXE     Client(将要安装系统的主机)分配一个 IP 地址,由于是给 PXE     Client 分配 IP 地址,所以在配置 DHCP 服务器时需要增加相应的 PXE 设置。此外,在 PXE     Client 的 ROM 中,已经存在了 TFTP     Client,那么它就可以通过 TFTP 协议到 TFTP     Server 上下载所需的文件了。 pxe小结: PXE,全称Pre-boot     Execution Environment 预启动执行环境 通过网络接口启动计算机,不依赖本地存储设备或本地已安装的操作系统 C/S的工作模式 由intel公司开发的最新技术 PXE客户端会调用IP,UDP,DHCP,TFTP等网络协议 PXE客户端其实是指网卡有PXE     client,存放在网卡的ROM中,当服务器启动时候bios会把pxe     client调到内存中执行   PXE的工作原理 PXE client从自己的PXE网卡启动,向本网络中DHCP服务器请求IP DHCP 服务器返回给客户机IP以及PXE文件放置位置(该文件放置在TFTP上) PXE client向本网络中的TFTP服务器索取pxelinux.0,pxelinux.cfg/default、vmlinuz、initrd.img等文件 根据pxelinux.0得到的结果,执行该文件 根据pxelinux.0的执行结果,通过TFTP服务器加载内核和文件系统 进入安装画面,此时可以通过选择HTTP、FTP、NFS方式进行安装 图解: 什么是kickstart Kickstart是一种无人值守的安装方式。它的工作原理是在安装过程中记录典型的需要人工干预填写的各种参数,并生成一个名为ks.cfg的文件。如果在安装过程中(不只局限于生成Kickstart安装文件的机器)出现要填写参数的情况,安装程序首先会去查找Kickstart生成的文件,如果找到合适的参数,就采用所找到的参数;如果没有找到合适的参数,便需要安装者手工干预了。所以,如果Kickstart文件涵盖了安装过程中可能出现的所有需要填写的参数,那么安装者完全可以只告诉安装程序从何处取ks.cfg文件,然后就去忙自己的事情。等安装完毕,安装程序会根据ks.cfg中的设置重启系统,并结束安装。 图解:(借鉴与网上) 系统环境 实验环境:VMware Workstations 11 系统平台: [root@m01 ~]# cat /etc/redhat-release CentOS release 6.7 (Final) [root@m01 ~]# uname -rm 2.6.32-573.el6.x86_64 x86_64 [root@m01 ~]# getenforce Disabled [root@m01 ~]# /etc/init.d/iptables status iptables:未运行防火墙。 网络模式:NAT模式 注意:   虚拟机网卡采用NAT模式,不要使用桥接模式,因为稍后我们会搭建DHCP服务器,在同一局域网多个DHCP服务会有冲突。 VMware的NAT模式的dhcp服务也关闭,避免干扰。 安装服务程序 从上图的pxe+kickstart工作原理图可以看出,这里需要DHCP,TFTP,HTTP根据架构需求有时候还需要NFS服务,下面我们先安装这个几个服务 [root@m01 ~]# yum install -y httpd dhcp tftp-server [root@m01 ~]# rpm -qa httpd dhcp tftp-server tftp-server-0.49-8.el6.x86_64 dhcp-4.1.1-51.P1.el6.centos.x86_64 httpd-2.2.15-53.el6.centos.x86_64 [root@m01 ~]# DHCP服务配置 [root@m01 ~]# vim /etc/dhcp/dhcpd.conf ddns-update-style interim; ignore client-updates; filename "pxelinux.0";             #pxelinux 启动文件位置; next-server 172.16.1.61;   subnet 172.16.1.0 netmask 255.255.255.0 {           option routers                  172.16.1.61;         option subnet-mask              255.255.255.0;           range dynamic-bootp 172.16.1.100 172.16.1.200;         default-lease-time 21600;         max-lease-time 43200; } range  172.16.1.100 172.16.1.200         # 可分配的起始IP-结束IP option subnet-mask 255.255.255.0;    # 设定netmask default-lease-time 21600;            # 设置默认的IP租用期限 max-lease-time 43200;                # 设置最大的IP租用期限 next-server 10.0.0.7;                # 告知客户端TFTP服务器的ip filename "/pxelinux.0";              # 告知客户端从TFTP根目录下载pxelinux.0文件 [root@m01 ~]# /etc/init.d/dhcpd start 正在启动 dhcpd:                                           [确定] [root@m01 ~]# netstat -lntup|grep dhcp udp        0      0 0.0.0.0:67                  0.0.0.0:*                               1528/dhcpd ** 多网卡默认监听eth0,指定DHCP监听eth1网卡** [root@m01 ~] vim /etc/sysconfig/dhcpd # Command line options here DHCPDARGS=eth1  # 指定监听网卡 配置TFTP服务 TFTP简介 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。 [root@m01 ~]# vim /etc/xinetd.d/tftp   # default: off # description: The tftp server serves files using the trivial file transfer \ #       protocol.  The tftp protocol is often used to boot diskless \ #       workstations, download configuration files to network-aware printers, \ #       and to start the installation process for some operating systems. service tftp {         socket_type             = dgram         protocol                = udp         wait                    = yes         user                    = root         server                  = /usr/sbin/in.tftpd         server_args             = -s /var/lib/tftpboot         disable                 = no         per_source              = 11         cps                     = 100 2         flags                   = IPv4 } [root@m01 ~]# /etc/init.d/xinetd start 正在启动 xinetd:                                          [确定] [root@m01 ~]# netstat -lntup|grep 69 udp        0      0 0.0.0.0:69                  0.0.0.0:*                               1584/xinetd server_args一行是配置服务器的文件存放的位置,就是进行tftp传输的时候,都是从该文件夹中搜索文件的 配置HTTP服务 [root@m01 ~]# cd /var/www/html/ [root@m01 html]# mkdir CentOS-6.7 [root@m01 html]# mount /dev/cdrom /var/www/html/CentOS-6.7/ mount: block device /dev/sr0 is write-protected, mounting read-only [root@m01 html]# df -h Filesystem      Size  Used Avail Use% Mounted on /dev/sda3       8.8G  1.5G  7.0G  17% / tmpfs           491M     0  491M   0% /dev/shm /dev/sda1       190M   36M  145M  20% /boot /dev/sr0        3.7G  3.7G     0 100% /var/www/html/CentOS-6.7 [root@m01 html]# /etc/init.d/httpd start 正在启动 httpd:httpd: apr_sockaddr_info_get() failed for m01 httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName                                                            [确定] [root@m01 html]# sed -i "277i ServerName 127.0.0.1:80" /etc/httpd/conf/httpd.conf 这个命令就是消除上面那个报错的 [root@m01 html]# /etc/init.d/httpd restart 停止 httpd:                                               [确定] 正在启动 httpd: 浏览器访问pxe服务器,测试配置是否正确 配置支持PXE的启动程序 PXE引导配置(bootstrap) syslinux是一个功能强大的引导加载程序,而且兼容各种介质。syslinux是一个小型的Linux操作系统,它的目的是简化首次安装Linux的时间,并建立维护或其他特殊用途的启动盘。如果没有找到pxelinux.0这个文件,可以安装一下syslinux。 [root@m01~]# yum install -y syslinux [root@m01~]# rpm -qa syslinux syslinux-4.04-3.el6.x86_64 复制pxelinux.0文件至tftp的默认目录中去/var/lib/tftpboot [root@m01~]# cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ 复制iso 镜像中的/isolinux/*.msg 至/var/lib/tftpboot/ 文件夹中 [root@m01 ~]# cp/var/www/html/CentOS-6.7/isolinux/*.msg /var/lib/tftpboot/ 复制iso 镜像中的/image/pxeboot/initrd.img和vmlinux 至/var/lib/tftpboot/ 文件夹中 [root@m01 ~]# cp/var/www/html/CentOS-6.7/images/pxeboot/initrd.img /var/lib/tftpboot/ [root@m01 ~]# cp/var/www/html/CentOS-6.7/images/pxeboot/vmlinuz /var/lib/tftpboot 将iso 镜像中的/isolinux目录中的isolinux.cfg复制到pxelinux.cfg目录中,同时更改文件名称为default 这里也可以直接全部复制过去: cp-a /var/www/html/CentOS-6.7/isolinux/* /var/lib/tftpboot/   [root@m01~]# mkdir -p /var/lib/tftpboot/pxelinux.cfg [root@m01~]# cp /var/www/html/CentOS-6.7/isolinux/isolinux.cfg/var/lib/tftpboot/pxelinux.cfg/default pxe配置文件default解析 [root@m01 ~]# vim/var/lib/tftpboot/pxelinux.cfg/default default ks#默认启动的是 'label ks' 中标记的启动内核 default vesamenu.c32  # 默认加载一个菜单 #prompt 1             # 开启会显示命令行'boot:'提示符。prompt值为0时则不提示,将会直接启动'default'参数中指定的内容。 timeout 600           # timeout时间是引导时等待用户手动选择的时间,设为1可直接引导,单位为1/10秒。 display boot.msg#显示某个文件的内容,注意文件的路径。默认是在/var/lib/tftpboot/ 目录下。也可以指定位类似 '/install/boot.msg'这样的,路径+文件名。 F1 boot.msg #按下 'F1' 这样的键后显示的文件。 F2 options.msg  F3 general.msg  F4 param.msg  F5 rescue.msg # 菜单背景图片、标题、颜色。 menubackground splash.jpg menutitle Welcome to CentOS 6.7! menucolor border 0 #ffffffff #00000000 menucolor sel 7 #ffffffff #ff000000 menucolor title 0 #ffffffff #00000000 menucolor tabmsg 0 #ffffffff #00000000 menucolor unsel 0 #ffffffff #00000000 menucolor hotsel 0 #ff000000 #ffffffff menucolor hotkey 7 #ffffffff #ff000000 menucolor scrollbar 0 #ffffffff #00000000 # label指定在boot:提示符下输入的关键字,比如boot:linux[ENTER],这个会启动labellinux下标记的kernel和initrd.img文件。 label linux      # 一个标签就是前面图片的一行选项。   menu label ^Install or upgrade an existingsystem   menu default  kernel vmlinuz  # 指定要启动的内核。同样要注意路径,默认是/tftpboot目录。  append initrd=initrd.img # 指定追加给内核的参数,initrd.img是一个最小的linux系统 labelvesa   menu label Install system with ^basic videodriver   kernel vmlinuz   append initrd=initrd.img nomodeset labelrescue   menu label ^Rescue installed system   kernel vmlinuz   append initrd=initrd.img rescue labellocal   menu label Boot from ^local drive   localboot 0xffff labelmemtest86   menu label ^Memory test   kernel memtest   append - 新开虚拟机测试 这里可以新开一个虚拟机网卡设置为NAT模式,开机新的虚拟机,发现会获取到172.16.1.x网段的一个IP地址 在Installation Method这一步,如果是选择URL,后面我要输入http://172.16.1.61/CentOS-6.7/ 在Installation Method这一步,如果是选择NFS directory,后面的写法是nfs:172.16.1.61:/data/sys/kickstart/ks.cfg 到这里的测试你发现还是需要手动的,所以我们要继续操作达到一键自动安装 创建ks.cfg文件 通常,我们在安装操作系统的过程中,需要大量的和服务器交互操作,为了减少这个交互过程,kickstart就诞生了。使用这种kickstart,只需事先定义好一个Kickstart自动应答配置文件ks.cfg(通常存放在安装服务器上),并让安装程序知道该配置文件的位置,在安装过程中安装程序就可以自己从该文件中读取安装配置,这样就避免了在安装过程中多次的人机交互,从而实现无人值守的自动化安装。 生成kickstart配置文件的三种方法: 方法1、     每安装好一台Centos机器,Centos安装程序都会创建一个kickstart配置文件,记录你的真实安装配置。如果你希望实现和某系统类似的安装,可以基于该系统的kickstart配置文件来生成你自己的kickstart配置文件。(生成的文件名字叫anaconda-ks.cfg位于/root/anaconda-ks.cfg) 方法2、Centos提供了一个图形化的kickstart配置工具。在任何一个安装好的Linux系统上运行该工具,就可以很容易地创建你自己的kickstart配置文件。kickstart配置工具命令为redhat-config-kickstart(RHEL3)或system-config-kickstart(RHEL4,RHEL5).网上有很多用CentOS桌面版生成ks文件的文章,如果有现成的系统就没什么可说。但没有现成的,也没有必要去用桌面版,命令行也很简单。 方法3、阅读kickstart配置文件的手册。用任何一个文本编辑器都可以创建你自己的kickstart配置文件。 查看anaconda-ks.cfg文件 [root@m01 ~]# cat anaconda-ks.cfg # Kickstart file automatically generated by anaconda.   #version=DEVEL install cdrom lang en_US.UTF-8 keyboard us network --onboot no --device eth0 --bootproto dhcp --noipv6 network --onboot no --device eth1 --bootproto dhcp --noipv6 rootpw  --iscrypted $6$S5zy08GhFmCSFoJg$IUzRPrNmiIWv2S.nFSpDqN7yuaIvZxBr0Y9s9sh2F5rFZrkbJW0uOIbSUK3eTPOnKgQENgXmkSHMF2tII0Zwb1 firewall --service=ssh authconfig --enableshadow --passalgo=sha512 selinux --enforcing timezone --utc Asia/Shanghai bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" # The following is the partition information you requested # Note that any partitions you deleted are not expressed # here so unless you clear all partitions first, this is # not guaranteed to work #clearpart --none   #part /boot --fstype=ext4 --asprimary --size=200 #part swap --asprimary --size=768 #part / --fstype=ext4 --grow --asprimary --size=200     repo --name="CentOS"  --baseurl=cdrom:sr0 --cost=100   %packages @base @compat-libraries @core @debugging @development @server-policy @workstation-policy python-dmidecode sgpio device-mapper-persistent-data systemtap-client %end[root@m01 ~]# ks.cfg详解 官网文档  CentOS5 : http://www.centos.org/docs/5/html/Installation_Guide-en-US/s1-kickstart2-options.html  CentOS6 : https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Installation_Guide/s1-kickstart2-options.html  官网自带中文版,选一下语言即可  ks.cfg文件组成大致分为3段 命令段           键盘类型,语言,安装方式等系统的配置,有必选项和可选项,如果缺少某项必选项,安装时会中断并提示用户选择此项的选项 软件包段   %packages @groupname:指定安装的包组 package_name:指定安装的包 -package_name:指定不安装的包 在安装过程中默认安装的软件包,安装软件时会自动分析依赖关系。 脚本段(可选)   %pre:安装系统前执行的命令或脚本(由于只依赖于启动镜像,支持的命令很少) %post:安装系统后执行的命令或脚本(基本支持所有命令) 关键字含义 install告知安装程序,这是一次全新安装,而不是升级upgrade。 url --url=" "通过FTP或HTTP从远程服务器上的安装树中安装。 url --url="http://10.0.0.7/CentOS-6.7/" url --url ftp://<username>:<password>@<server>/<dir> nfs从指定的NFS服务器安装。 nfs --server=nfsserver.example.com --dir=/tmp/install-tree text使用文本模式安装。 lang设置在安装过程中使用的语言以及系统的缺省语言。lang en_US.UTF-8 keyboard设置系统键盘类型。keyboard us zerombr清除mbr引导信息。 bootloader系统引导相关配置。 bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" --location=,指定引导记录被写入的位置.有效的值如下:mbr(缺省),partition(在包含内核的分区的第一个扇区安装引导装载程序)或none(不安装引导装载程序)。 --driveorder,指定在BIOS引导顺序中居首的驱动器。 --append=,指定内核参数.要指定多个参数,使用空格分隔它们。 network为通过网络的kickstart安装以及所安装的系统配置联网信息。 network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6 --hostname=CentOS6 --bootproto=[dhcp/bootp/static]中的一种,缺省值是dhcp。bootp和dhcp被认为是相同的。 static方法要求在kickstart文件里输入所有的网络信息。 network --bootproto=static --ip=10.0.0.100 --netmask=255.255.255.0 --gateway=10.0.0.2 --nameserver=10.0.0.2 请注意所有配置信息都必须在一行上指定,不能使用反斜线来换行。 --ip=,要安装的机器的IP地址. --gateway=,IP地址格式的默认网关. --netmask=,安装的系统的子网掩码. --hostname=,安装的系统的主机名. --onboot=,是否在引导时启用该设备. --noipv6=,禁用此设备的IPv6. --nameserver=,配置dns解析. timezone设置系统时区。timezone --utc Asia/Shanghai authconfig系统认证信息。authconfig --enableshadow --passalgo=sha512 设置密码加密方式为sha512 启用shadow文件。 rootpwroot密码 clearpart清空分区。clearpart --all --initlabel --all 从系统中清除所有分区,--initlable 初始化磁盘标签 part磁盘分区。 part /boot --fstype=ext4 --asprimary --size=200 part swap --size=1024 part / --fstype=ext4 --grow --asprimary --size=200 --fstype=,为分区设置文件系统类型.有效的类型为ext2,ext3,swap和vfat。 --asprimary,强迫把分区分配为主分区,否则提示分区失败。 --size=,以MB为单位的分区最小值.在此处指定一个整数值,如500.不要在数字后面加MB。 --grow,告诉分区使用所有可用空间(若有),或使用设置的最大值。 firstboot负责协助配置redhat一些重要的信息。 firstboot --disable selinux关闭selinux。selinux --disabled firewall关闭防火墙。firewall --disabled logging设置日志级别。logging --level=info reboot设定安装完成后重启,此选项必须存在,不然kickstart显示一条消息,并等待用户按任意键后才重新引导,也可以选择halt关机。 编写ks.cfg文件 [root@m01 ~]# grub-crypt Password: Retype password: $6$QWtrdZSfLPK6JMvB$/2.tLsLBb59StIJrPxpXkk3zSgzkKMTrvw8tnBNLKxnMEzkjrbNMhhe2cd0fd2bUi5y1f47gXB1T6gbBHApPX. [root@m01 ~]# mkdir -p /var/www/html/ks_config [root@m01 ~]# cd /var/www/html/ks_config/ # Kickstart Configurator for CentOS 6.7 by yao zhang install url --url="http://172.16.1.61/CentOS-6.7/" text lang en_US.UTF-8 keyboard us zerombr bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6 --hostname=CentOS6 timezone --utc Asia/Shanghai authconfig --enableshadow --passalgo=sha512 rootpw  --iscrypted $6$QWtrdZSfLPK6JMvB$/2.tLsLBb59StIJrPxpXkk3zSgzkKMTrvw8tnBNLKxnMEzkjrbNMhhe2cd0fd2bUi5y1f47gXB1T6gbBHApPX. clearpart --all --initlabel part /boot --fstype=ext4 --asprimary --size=200 part swap --size=1024 part / --fstype=ext4 --grow --asprimary --size=200 firstboot --disable selinux --disabled firewall --disabled logging --level=info reboot %packages @base @compat-libraries @debugging @development tree nmap sysstat lrzsz dos2unix telnet %post wget -O /tmp/optimization.sh http://172.16.1.61/ks_config/optimization.sh&>/dev/null /bin/sh /tmp/optimization.sh %end 编辑脚本:(使用的是老师张导的脚本) [root@m01 ks_config]# vim /var/www/html/ks_config/optimization.sh #!/bin/bash . /etc/init.d/functions Ip=172.16.1.61 Port=80 ConfigDir=ks_config # Judge Http server is ok? PortNum=`nmap $Ip  -p $Port 2>/dev/null|grep open|wc -l` [ $PortNum -lt 1 ] && {         echo "Http server is bad!"         exit 1 } # Defined result function function Msg(){         if [ $? -eq 0 ];then           action "$1" /bin/true         else           action "$1" /bin/false         fi } # Defined IP function function ConfigIP(){         Suffix=`ifconfig eth0|awk -F "[ .]+" 'NR==2 {print $6}'`         cat >/etc/sysconfig/network-scripts/ifcfg-eth0 <<-END         DEVICE=eth0         TYPE=Ethernet         ONBOOT=yes         NM_CONTROLLED=yes         BOOTPROTO=none         IPADDR=10.0.0.$Suffix         PREFIX=24         GATEWAY=10.0.0.2         DNS1=10.0.0.2         DEFROUTE=yes         IPV4_FAILURE_FATAL=yes         IPV6INIT=no         NAME="System eth0"         END         Msg "config eth0" } # Defined Yum source Functions function yum(){         YumDir=/etc/yum.repos.d         [ -f "$YumDir/CentOS-Base.repo" ] && cp $YumDir/CentOS-Base.repo{,.ori}         wget -O $YumDir/CentOS-Base.repo http://$Ip:$Port/$ConfigDir/CentOS-Base.repo&>/dev/null &&\         wget -O $YumDir/epel.repo http://$Ip:$Port/$ConfigDir/epel.repo&>/dev/null &&\         Msg "YUM source" } # Defined Hide the system version number Functions function HideVersion(){         [ -f "/etc/issue" ] && >/etc/issue         Msg "Hide issue"         [ -f "/etc/issue.net" ] && > /etc/issue.net         Msg "Hide issue.net" } # Defined OPEN FILES Functions function openfiles(){         [ -f "/etc/security/limits.conf" ] && {         echo '*  -  nofile  65535' >> /etc/security/limits.conf         Msg "open files"         } } # Defined Kernel parameters Functions function kernel(){         KernelDir=/etc         [ -f "$KernelDir/sysctl.conf" ] && /bin/mv $KernelDir/sysctl.conf{,.ori}         wget -O $KernelDir/sysctl.conf http://$Ip:$Port/$ConfigDir/sysctl.conf&>/dev/null         Msg "Kernel config" } # Defined System Startup Services Functions function boot(){         for oldboy in `chkconfig --list|grep "3:on"|awk '{print $1}'|grep -vE "crond|network|rsyslog|sshd|sysstat"`           do            chkconfig $oldboy off         done         Msg "BOOT config" } # Defined Time Synchronization Functions function Time(){         echo "#time sync by zhangyao at $(date +%F)" >>/var/spool/cron/root         echo '*/5 * * * * /usr/sbin/ntpdate time.nist.gov &>/dev/null' >>/var/spool/cron/root         Msg "Time Synchronization" } # Defined main Functions function main(){         ConfigIP         yum         HideVersion         openfiles         kernel         boot         Time } main # rz上传CentOS-Base.repo、epel.repo、sysctl.conf 编辑优化default文件 # 最精简配置 [root@linux-node1 ~]# vim /var/lib/tftpboot/pxelinux.cfg/default default ks prompt 0 label ks   kernel vmlinuz   append initrd=initrd.img ks=http://172.16.1.61/ks_config/CentOS-6.7-ks.cfg # 告诉安装程序ks.cfg文件在哪里 # append initrd=initrd.img ks=http://10.0.0.7/ks_config/CentOS-6.7-ks.cfg ksdevice=eth0 # ksdevice=eth0代表当客户端有多块网卡的时候,要实现自动化需要设置从eth1安装,不指定的话,安装的时候系统会让你选择,那就不叫全自动化了。 PXE配置文件default 由于多个客户端可以从一个PXE服务器引导,PXE引导映像使用了一个复杂的配置文件搜索方式来查找针对客户机的配置文件。如果客户机的网卡的MAC地址为8F:3H:AA:6B:CC:5D,对应的IP地址为10.0.0.195,那么客户机首先尝试以MAC地址为文件名匹配的配置文件,如果不存在就以IP地址来查找。根据上述环境针对这台主机要查找的以一个配置文件就是/tftpboot/pxelinux.cfg/01-8F:3H:AA:6B:CC:5D。如果该文件不存在,就会根据IP地址来查找配置文件了,这个算法更复杂些,PXE映像查找会根据IP地址16进制命名的客户机配置文件。例如:10.0.0.195对应的16进制的形式为C0A801C3。(可以通过syslinux软件包提供的gethostip命令将10进制的IP转换为16进制) 如果C0A801C3文件不存在,就尝试查找C0A801C文件,如果C0A801C也不存在,那么就尝试C0A801文件,依次类推,直到查找C文件,如果C也不存在的话,那么最后尝试default文件。 总体来说,pxelinux搜索的文件的顺序是:   /tftpboot/pxelinux.cfg/01-88-99-aa-bb-cc-dd /tftpboot/pxelinux.cfg/C0A801C3 /tftpboot/pxelinux.cfg/C0A801C /tftpboot/pxelinux.cfg/C0A801 /tftpboot/pxelinux.cfg/C0A80 /tftpboot/pxelinux.cfg/C0A8 /tftpboot/pxelinux.cfg/C0A /tftpboot/pxelinux.cfg/C0 /tftpboot/pxelinux.cfg/C /tftpboot/pxelinux.cfg/default 应用:如果已经从厂商获取了服务器MAC地址,就可以差异化定制安装服务器了。 本文转自 kesungang 51CTO博客,原文链接:http://blog.51cto.com/sgk2011/1794382,如需转载请自行联系原作者
文章
Web App开发  ·  Linux  ·  网络安全  ·  开发工具  ·  数据安全/隐私保护
2017-11-28
kickstart无人值守自动安装操作系统
PXE是什么? PXE(Pre-boot Execution     Environment,预启动执行环境)是由Intel公司开发的最新技术,工作于Client/Server的网络模式,支持工作站通过网络从远端服务器下载映像,并由此支持通过网络启动操作系统,在启动过程中,终端要求服务器分配IP地址,再用TFTP(trivial     file transfer protocol)或MTFTP(multicast trivial file transfer     protocol)协议下载一个启动软件包到本机内存中执行,由这个启动软件包完成终端基本软件设置,从而引导预先安装在服务器中的终端操作系统。 严格来说,PXE 并不是一种安装方式,而是一种引导方式。进行 PXE 安装的必要条件是在要安装的计算机中必须包含一个 PXE 支持的网卡(NIC),即网卡中必须要有 PXE     Client。PXE 协议可以使计算机通过网络启动。此协议分为     Client端和 Server 端,而PXE     Client则在网卡的 ROM 中。当计算机引导时,BIOS 把 PXE     Client 调入内存中执行,然后由 PXE Client 将放置在远端的文件通过网络下载到本地运行。运行 PXE 协议需要设置 DHCP 服务器和 TFTP 服务器。DHCP 服务器会给 PXE     Client(将要安装系统的主机)分配一个 IP 地址,由于是给 PXE     Client 分配 IP 地址,所以在配置 DHCP 服务器时需要增加相应的 PXE 设置。此外,在 PXE     Client 的 ROM 中,已经存在了 TFTP     Client,那么它就可以通过 TFTP 协议到 TFTP     Server 上下载所需的文件了。 pxe小结: PXE,全称Pre-boot     Execution Environment 预启动执行环境 通过网络接口启动计算机,不依赖本地存储设备或本地已安装的操作系统 C/S的工作模式 由intel公司开发的最新技术 PXE客户端会调用IP,UDP,DHCP,TFTP等网络协议 PXE客户端其实是指网卡有PXE     client,存放在网卡的ROM中,当服务器启动时候bios会把pxe     client调到内存中执行   PXE的工作原理 PXE client从自己的PXE网卡启动,向本网络中DHCP服务器请求IP DHCP 服务器返回给客户机IP以及PXE文件放置位置(该文件放置在TFTP上) PXE client向本网络中的TFTP服务器索取pxelinux.0,pxelinux.cfg/default、vmlinuz、initrd.img等文件 根据pxelinux.0得到的结果,执行该文件 根据pxelinux.0的执行结果,通过TFTP服务器加载内核和文件系统 进入安装画面,此时可以通过选择HTTP、FTP、NFS方式进行安装 图解: 什么是kickstart Kickstart是一种无人值守的安装方式。它的工作原理是在安装过程中记录典型的需要人工干预填写的各种参数,并生成一个名为ks.cfg的文件。如果在安装过程中(不只局限于生成Kickstart安装文件的机器)出现要填写参数的情况,安装程序首先会去查找Kickstart生成的文件,如果找到合适的参数,就采用所找到的参数;如果没有找到合适的参数,便需要安装者手工干预了。所以,如果Kickstart文件涵盖了安装过程中可能出现的所有需要填写的参数,那么安装者完全可以只告诉安装程序从何处取ks.cfg文件,然后就去忙自己的事情。等安装完毕,安装程序会根据ks.cfg中的设置重启系统,并结束安装。 图解:(借鉴与网上) 系统环境 实验环境:VMware Workstations 11 系统平台: [root@m01 ~]# cat /etc/redhat-release CentOS release 6.7 (Final) [root@m01 ~]# uname -rm 2.6.32-573.el6.x86_64 x86_64 [root@m01 ~]# getenforce Disabled [root@m01 ~]# /etc/init.d/iptables status iptables:未运行防火墙。 网络模式:NAT模式 注意:   虚拟机网卡采用NAT模式,不要使用桥接模式,因为稍后我们会搭建DHCP服务器,在同一局域网多个DHCP服务会有冲突。 VMware的NAT模式的dhcp服务也关闭,避免干扰。 安装服务程序 从上图的pxe+kickstart工作原理图可以看出,这里需要DHCP,TFTP,HTTP根据架构需求有时候还需要NFS服务,下面我们先安装这个几个服务 [root@m01 ~]# yum install -y httpd dhcp tftp-server [root@m01 ~]# rpm -qa httpd dhcp tftp-server tftp-server-0.49-8.el6.x86_64 dhcp-4.1.1-51.P1.el6.centos.x86_64 httpd-2.2.15-53.el6.centos.x86_64 [root@m01 ~]# DHCP服务配置 [root@m01 ~]# vim /etc/dhcp/dhcpd.conf ddns-update-style interim; ignore client-updates; filename "pxelinux.0";             #pxelinux 启动文件位置; next-server 172.16.1.61;   subnet 172.16.1.0 netmask 255.255.255.0 {           option routers                  172.16.1.61;         option subnet-mask              255.255.255.0;           range dynamic-bootp 172.16.1.100 172.16.1.200;         default-lease-time 21600;         max-lease-time 43200; } range  172.16.1.100 172.16.1.200         # 可分配的起始IP-结束IP option subnet-mask 255.255.255.0;    # 设定netmask default-lease-time 21600;            # 设置默认的IP租用期限 max-lease-time 43200;                # 设置最大的IP租用期限 next-server 10.0.0.7;                # 告知客户端TFTP服务器的ip filename "/pxelinux.0";              # 告知客户端从TFTP根目录下载pxelinux.0文件 [root@m01 ~]# /etc/init.d/dhcpd start 正在启动 dhcpd:                                           [确定] [root@m01 ~]# netstat -lntup|grep dhcp udp        0      0 0.0.0.0:67                  0.0.0.0:*                               1528/dhcpd ** 多网卡默认监听eth0,指定DHCP监听eth1网卡** [root@m01 ~] vim /etc/sysconfig/dhcpd # Command line options here DHCPDARGS=eth1  # 指定监听网卡 配置TFTP服务 TFTP简介 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。 [root@m01 ~]# vim /etc/xinetd.d/tftp   # default: off # description: The tftp server serves files using the trivial file transfer \ #       protocol.  The tftp protocol is often used to boot diskless \ #       workstations, download configuration files to network-aware printers, \ #       and to start the installation process for some operating systems. service tftp {         socket_type             = dgram         protocol                = udp         wait                    = yes         user                    = root         server                  = /usr/sbin/in.tftpd         server_args             = -s /var/lib/tftpboot         disable                 = no         per_source              = 11         cps                     = 100 2         flags                   = IPv4 } [root@m01 ~]# /etc/init.d/xinetd start 正在启动 xinetd:                                          [确定] [root@m01 ~]# netstat -lntup|grep 69 udp        0      0 0.0.0.0:69                  0.0.0.0:*                               1584/xinetd server_args一行是配置服务器的文件存放的位置,就是进行tftp传输的时候,都是从该文件夹中搜索文件的 配置HTTP服务 [root@m01 ~]# cd /var/www/html/ [root@m01 html]# mkdir CentOS-6.7 [root@m01 html]# mount /dev/cdrom /var/www/html/CentOS-6.7/ mount: block device /dev/sr0 is write-protected, mounting read-only [root@m01 html]# df -h Filesystem      Size  Used Avail Use% Mounted on /dev/sda3       8.8G  1.5G  7.0G  17% / tmpfs           491M     0  491M   0% /dev/shm /dev/sda1       190M   36M  145M  20% /boot /dev/sr0        3.7G  3.7G     0 100% /var/www/html/CentOS-6.7 [root@m01 html]# /etc/init.d/httpd start 正在启动 httpd:httpd: apr_sockaddr_info_get() failed for m01 httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName                                                            [确定] [root@m01 html]# sed -i "277i ServerName 127.0.0.1:80" /etc/httpd/conf/httpd.conf 这个命令就是消除上面那个报错的 [root@m01 html]# /etc/init.d/httpd restart 停止 httpd:                                               [确定] 正在启动 httpd: 浏览器访问pxe服务器,测试配置是否正确 配置支持PXE的启动程序 PXE引导配置(bootstrap) syslinux是一个功能强大的引导加载程序,而且兼容各种介质。syslinux是一个小型的Linux操作系统,它的目的是简化首次安装Linux的时间,并建立维护或其他特殊用途的启动盘。如果没有找到pxelinux.0这个文件,可以安装一下syslinux。 [root@m01~]# yum install -y syslinux [root@m01~]# rpm -qa syslinux syslinux-4.04-3.el6.x86_64 复制pxelinux.0文件至tftp的默认目录中去/var/lib/tftpboot [root@m01~]# cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ 复制iso 镜像中的/isolinux/*.msg 至/var/lib/tftpboot/ 文件夹中 [root@m01 ~]# cp/var/www/html/CentOS-6.7/isolinux/*.msg /var/lib/tftpboot/ 复制iso 镜像中的/image/pxeboot/initrd.img和vmlinux 至/var/lib/tftpboot/ 文件夹中 [root@m01 ~]# cp/var/www/html/CentOS-6.7/images/pxeboot/initrd.img /var/lib/tftpboot/ [root@m01 ~]# cp/var/www/html/CentOS-6.7/images/pxeboot/vmlinuz /var/lib/tftpboot 将iso 镜像中的/isolinux目录中的isolinux.cfg复制到pxelinux.cfg目录中,同时更改文件名称为default 这里也可以直接全部复制过去: cp-a /var/www/html/CentOS-6.7/isolinux/* /var/lib/tftpboot/   [root@m01~]# mkdir -p /var/lib/tftpboot/pxelinux.cfg [root@m01~]# cp /var/www/html/CentOS-6.7/isolinux/isolinux.cfg/var/lib/tftpboot/pxelinux.cfg/default pxe配置文件default解析 [root@m01 ~]# vim/var/lib/tftpboot/pxelinux.cfg/default default ks#默认启动的是 'label ks' 中标记的启动内核 default vesamenu.c32  # 默认加载一个菜单 #prompt 1             # 开启会显示命令行'boot:'提示符。prompt值为0时则不提示,将会直接启动'default'参数中指定的内容。 timeout 600           # timeout时间是引导时等待用户手动选择的时间,设为1可直接引导,单位为1/10秒。 display boot.msg#显示某个文件的内容,注意文件的路径。默认是在/var/lib/tftpboot/ 目录下。也可以指定位类似 '/install/boot.msg'这样的,路径+文件名。 F1 boot.msg #按下 'F1' 这样的键后显示的文件。 F2 options.msg  F3 general.msg  F4 param.msg  F5 rescue.msg # 菜单背景图片、标题、颜色。 menubackground splash.jpg menutitle Welcome to CentOS 6.7! menucolor border 0 #ffffffff #00000000 menucolor sel 7 #ffffffff #ff000000 menucolor title 0 #ffffffff #00000000 menucolor tabmsg 0 #ffffffff #00000000 menucolor unsel 0 #ffffffff #00000000 menucolor hotsel 0 #ff000000 #ffffffff menucolor hotkey 7 #ffffffff #ff000000 menucolor scrollbar 0 #ffffffff #00000000 # label指定在boot:提示符下输入的关键字,比如boot:linux[ENTER],这个会启动labellinux下标记的kernel和initrd.img文件。 label linux      # 一个标签就是前面图片的一行选项。   menu label ^Install or upgrade an existingsystem   menu default  kernel vmlinuz  # 指定要启动的内核。同样要注意路径,默认是/tftpboot目录。  append initrd=initrd.img # 指定追加给内核的参数,initrd.img是一个最小的linux系统 labelvesa   menu label Install system with ^basic videodriver   kernel vmlinuz   append initrd=initrd.img nomodeset labelrescue   menu label ^Rescue installed system   kernel vmlinuz   append initrd=initrd.img rescue labellocal   menu label Boot from ^local drive   localboot 0xffff labelmemtest86   menu label ^Memory test   kernel memtest   append - 新开虚拟机测试 这里可以新开一个虚拟机网卡设置为NAT模式,开机新的虚拟机,发现会获取到172.16.1.x网段的一个IP地址 在Installation Method这一步,如果是选择URL,后面我要输入http://172.16.1.61/CentOS-6.7/ 在Installation Method这一步,如果是选择NFS directory,后面的写法是nfs:172.16.1.61:/data/sys/kickstart/ks.cfg 到这里的测试你发现还是需要手动的,所以我们要继续操作达到一键自动安装 创建ks.cfg文件 通常,我们在安装操作系统的过程中,需要大量的和服务器交互操作,为了减少这个交互过程,kickstart就诞生了。使用这种kickstart,只需事先定义好一个Kickstart自动应答配置文件ks.cfg(通常存放在安装服务器上),并让安装程序知道该配置文件的位置,在安装过程中安装程序就可以自己从该文件中读取安装配置,这样就避免了在安装过程中多次的人机交互,从而实现无人值守的自动化安装。 生成kickstart配置文件的三种方法: 方法1、     每安装好一台Centos机器,Centos安装程序都会创建一个kickstart配置文件,记录你的真实安装配置。如果你希望实现和某系统类似的安装,可以基于该系统的kickstart配置文件来生成你自己的kickstart配置文件。(生成的文件名字叫anaconda-ks.cfg位于/root/anaconda-ks.cfg) 方法2、Centos提供了一个图形化的kickstart配置工具。在任何一个安装好的Linux系统上运行该工具,就可以很容易地创建你自己的kickstart配置文件。kickstart配置工具命令为redhat-config-kickstart(RHEL3)或system-config-kickstart(RHEL4,RHEL5).网上有很多用CentOS桌面版生成ks文件的文章,如果有现成的系统就没什么可说。但没有现成的,也没有必要去用桌面版,命令行也很简单。 方法3、阅读kickstart配置文件的手册。用任何一个文本编辑器都可以创建你自己的kickstart配置文件。 查看anaconda-ks.cfg文件 [root@m01 ~]# cat anaconda-ks.cfg # Kickstart file automatically generated by anaconda.   #version=DEVEL install cdrom lang en_US.UTF-8 keyboard us network --onboot no --device eth0 --bootproto dhcp --noipv6 network --onboot no --device eth1 --bootproto dhcp --noipv6 rootpw  --iscrypted $6$S5zy08GhFmCSFoJg$IUzRPrNmiIWv2S.nFSpDqN7yuaIvZxBr0Y9s9sh2F5rFZrkbJW0uOIbSUK3eTPOnKgQENgXmkSHMF2tII0Zwb1 firewall --service=ssh authconfig --enableshadow --passalgo=sha512 selinux --enforcing timezone --utc Asia/Shanghai bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" # The following is the partition information you requested # Note that any partitions you deleted are not expressed # here so unless you clear all partitions first, this is # not guaranteed to work #clearpart --none   #part /boot --fstype=ext4 --asprimary --size=200 #part swap --asprimary --size=768 #part / --fstype=ext4 --grow --asprimary --size=200     repo --name="CentOS"  --baseurl=cdrom:sr0 --cost=100   %packages @base @compat-libraries @core @debugging @development @server-policy @workstation-policy python-dmidecode sgpio device-mapper-persistent-data systemtap-client %end[root@m01 ~]# ks.cfg详解 官网文档  CentOS5 : http://www.centos.org/docs/5/html/Installation_Guide-en-US/s1-kickstart2-options.html  CentOS6 : https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Installation_Guide/s1-kickstart2-options.html  官网自带中文版,选一下语言即可  ks.cfg文件组成大致分为3段 命令段           键盘类型,语言,安装方式等系统的配置,有必选项和可选项,如果缺少某项必选项,安装时会中断并提示用户选择此项的选项 软件包段   %packages @groupname:指定安装的包组 package_name:指定安装的包 -package_name:指定不安装的包 在安装过程中默认安装的软件包,安装软件时会自动分析依赖关系。 脚本段(可选)   %pre:安装系统前执行的命令或脚本(由于只依赖于启动镜像,支持的命令很少) %post:安装系统后执行的命令或脚本(基本支持所有命令) 关键字 含义 install 告知安装程序,这是一次全新安装,而不是升级upgrade。 url --url=" " 通过FTP或HTTP从远程服务器上的安装树中安装。 url --url="http://10.0.0.7/CentOS-6.7/" url --url ftp://<username>:<password>@<server>/<dir> nfs 从指定的NFS服务器安装。 nfs --server=nfsserver.example.com --dir=/tmp/install-tree text 使用文本模式安装。 lang 设置在安装过程中使用的语言以及系统的缺省语言。lang en_US.UTF-8 keyboard 设置系统键盘类型。keyboard us zerombr 清除mbr引导信息。 bootloader 系统引导相关配置。 bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" --location=,指定引导记录被写入的位置.有效的值如下:mbr(缺省),partition(在包含内核的分区的第一个扇区安装引导装载程序)或none(不安装引导装载程序)。 --driveorder,指定在BIOS引导顺序中居首的驱动器。 --append=,指定内核参数.要指定多个参数,使用空格分隔它们。 network 为通过网络的kickstart安装以及所安装的系统配置联网信息。 network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6 --hostname=CentOS6 --bootproto=[dhcp/bootp/static]中的一种,缺省值是dhcp。bootp和dhcp被认为是相同的。 static方法要求在kickstart文件里输入所有的网络信息。 network --bootproto=static --ip=10.0.0.100 --netmask=255.255.255.0 --gateway=10.0.0.2 --nameserver=10.0.0.2 请注意所有配置信息都必须在一行上指定,不能使用反斜线来换行。 --ip=,要安装的机器的IP地址. --gateway=,IP地址格式的默认网关. --netmask=,安装的系统的子网掩码. --hostname=,安装的系统的主机名. --onboot=,是否在引导时启用该设备. --noipv6=,禁用此设备的IPv6. --nameserver=,配置dns解析. timezone 设置系统时区。timezone --utc Asia/Shanghai authconfig 系统认证信息。authconfig --enableshadow --passalgo=sha512 设置密码加密方式为sha512 启用shadow文件。 rootpw root密码 clearpart 清空分区。clearpart --all --initlabel --all 从系统中清除所有分区,--initlable 初始化磁盘标签 part 磁盘分区。 part /boot --fstype=ext4 --asprimary --size=200 part swap --size=1024 part / --fstype=ext4 --grow --asprimary --size=200 --fstype=,为分区设置文件系统类型.有效的类型为ext2,ext3,swap和vfat。 --asprimary,强迫把分区分配为主分区,否则提示分区失败。 --size=,以MB为单位的分区最小值.在此处指定一个整数值,如500.不要在数字后面加MB。 --grow,告诉分区使用所有可用空间(若有),或使用设置的最大值。 firstboot 负责协助配置redhat一些重要的信息。 firstboot --disable selinux 关闭selinux。selinux --disabled firewall 关闭防火墙。firewall --disabled logging 设置日志级别。logging --level=info reboot 设定安装完成后重启,此选项必须存在,不然kickstart显示一条消息,并等待用户按任意键后才重新引导,也可以选择halt关机。 编写ks.cfg文件 [root@m01 ~]# grub-crypt Password: Retype password: $6$QWtrdZSfLPK6JMvB$/2.tLsLBb59StIJrPxpXkk3zSgzkKMTrvw8tnBNLKxnMEzkjrbNMhhe2cd0fd2bUi5y1f47gXB1T6gbBHApPX. [root@m01 ~]# mkdir -p /var/www/html/ks_config [root@m01 ~]# cd /var/www/html/ks_config/ # Kickstart Configurator for CentOS 6.7 by yao zhang install url --url="http://172.16.1.61/CentOS-6.7/" text lang en_US.UTF-8 keyboard us zerombr bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6 --hostname=CentOS6 timezone --utc Asia/Shanghai authconfig --enableshadow --passalgo=sha512 rootpw  --iscrypted $6$QWtrdZSfLPK6JMvB$/2.tLsLBb59StIJrPxpXkk3zSgzkKMTrvw8tnBNLKxnMEzkjrbNMhhe2cd0fd2bUi5y1f47gXB1T6gbBHApPX. clearpart --all --initlabel part /boot --fstype=ext4 --asprimary --size=200 part swap --size=1024 part / --fstype=ext4 --grow --asprimary --size=200 firstboot --disable selinux --disabled firewall --disabled logging --level=info reboot %packages @base @compat-libraries @debugging @development tree nmap sysstat lrzsz dos2unix telnet %post wget -O /tmp/optimization.sh http://172.16.1.61/ks_config/optimization.sh&>/dev/null /bin/sh /tmp/optimization.sh %end 编辑脚本:(使用的是老师张导的脚本) [root@m01 ks_config]# vim /var/www/html/ks_config/optimization.sh #!/bin/bash . /etc/init.d/functions Ip=172.16.1.61 Port=80 ConfigDir=ks_config # Judge Http server is ok? PortNum=`nmap $Ip  -p $Port 2>/dev/null|grep open|wc -l` [ $PortNum -lt 1 ] && {         echo "Http server is bad!"         exit 1 } # Defined result function function Msg(){         if [ $? -eq 0 ];then           action "$1" /bin/true         else           action "$1" /bin/false         fi } # Defined IP function function ConfigIP(){         Suffix=`ifconfig eth0|awk -F "[ .]+" 'NR==2 {print $6}'`         cat >/etc/sysconfig/network-scripts/ifcfg-eth0 <<-END         DEVICE=eth0         TYPE=Ethernet         ONBOOT=yes         NM_CONTROLLED=yes         BOOTPROTO=none         IPADDR=10.0.0.$Suffix         PREFIX=24         GATEWAY=10.0.0.2         DNS1=10.0.0.2         DEFROUTE=yes         IPV4_FAILURE_FATAL=yes         IPV6INIT=no         NAME="System eth0"         END         Msg "config eth0" } # Defined Yum source Functions function yum(){         YumDir=/etc/yum.repos.d         [ -f "$YumDir/CentOS-Base.repo" ] && cp $YumDir/CentOS-Base.repo{,.ori}         wget -O $YumDir/CentOS-Base.repo http://$Ip:$Port/$ConfigDir/CentOS-Base.repo&>/dev/null &&\         wget -O $YumDir/epel.repo http://$Ip:$Port/$ConfigDir/epel.repo&>/dev/null &&\         Msg "YUM source" } # Defined Hide the system version number Functions function HideVersion(){         [ -f "/etc/issue" ] && >/etc/issue         Msg "Hide issue"         [ -f "/etc/issue.net" ] && > /etc/issue.net         Msg "Hide issue.net" } # Defined OPEN FILES Functions function openfiles(){         [ -f "/etc/security/limits.conf" ] && {         echo '*  -  nofile  65535' >> /etc/security/limits.conf         Msg "open files"         } } # Defined Kernel parameters Functions function kernel(){         KernelDir=/etc         [ -f "$KernelDir/sysctl.conf" ] && /bin/mv $KernelDir/sysctl.conf{,.ori}         wget -O $KernelDir/sysctl.conf http://$Ip:$Port/$ConfigDir/sysctl.conf&>/dev/null         Msg "Kernel config" } # Defined System Startup Services Functions function boot(){         for oldboy in `chkconfig --list|grep "3:on"|awk '{print $1}'|grep -vE "crond|network|rsyslog|sshd|sysstat"`           do            chkconfig $oldboy off         done         Msg "BOOT config" } # Defined Time Synchronization Functions function Time(){         echo "#time sync by zhangyao at $(date +%F)" >>/var/spool/cron/root         echo '*/5 * * * * /usr/sbin/ntpdate time.nist.gov &>/dev/null' >>/var/spool/cron/root         Msg "Time Synchronization" } # Defined main Functions function main(){         ConfigIP         yum         HideVersion         openfiles         kernel         boot         Time } main # rz上传CentOS-Base.repo、epel.repo、sysctl.conf 编辑优化default文件 # 最精简配置 [root@linux-node1 ~]# vim /var/lib/tftpboot/pxelinux.cfg/default default ks prompt 0 label ks   kernel vmlinuz   append initrd=initrd.img ks=http://172.16.1.61/ks_config/CentOS-6.7-ks.cfg # 告诉安装程序ks.cfg文件在哪里 # append initrd=initrd.img ks=http://10.0.0.7/ks_config/CentOS-6.7-ks.cfg ksdevice=eth0 # ksdevice=eth0代表当客户端有多块网卡的时候,要实现自动化需要设置从eth1安装,不指定的话,安装的时候系统会让你选择,那就不叫全自动化了。 PXE配置文件default 由于多个客户端可以从一个PXE服务器引导,PXE引导映像使用了一个复杂的配置文件搜索方式来查找针对客户机的配置文件。如果客户机的网卡的MAC地址为8F:3H:AA:6B:CC:5D,对应的IP地址为10.0.0.195,那么客户机首先尝试以MAC地址为文件名匹配的配置文件,如果不存在就以IP地址来查找。根据上述环境针对这台主机要查找的以一个配置文件就是/tftpboot/pxelinux.cfg/01-8F:3H:AA:6B:CC:5D。如果该文件不存在,就会根据IP地址来查找配置文件了,这个算法更复杂些,PXE映像查找会根据IP地址16进制命名的客户机配置文件。例如:10.0.0.195对应的16进制的形式为C0A801C3。(可以通过syslinux软件包提供的gethostip命令将10进制的IP转换为16进制) 如果C0A801C3文件不存在,就尝试查找C0A801C文件,如果C0A801C也不存在,那么就尝试C0A801文件,依次类推,直到查找C文件,如果C也不存在的话,那么最后尝试default文件。 总体来说,pxelinux搜索的文件的顺序是:   /tftpboot/pxelinux.cfg/01-88-99-aa-bb-cc-dd /tftpboot/pxelinux.cfg/C0A801C3 /tftpboot/pxelinux.cfg/C0A801C /tftpboot/pxelinux.cfg/C0A801 /tftpboot/pxelinux.cfg/C0A80 /tftpboot/pxelinux.cfg/C0A8 /tftpboot/pxelinux.cfg/C0A /tftpboot/pxelinux.cfg/C0 /tftpboot/pxelinux.cfg/C /tftpboot/pxelinux.cfg/default 应用:如果已经从厂商获取了服务器MAC地址,就可以差异化定制安装服务器了。 本文转自 kesungang 51CTO博客,原文链接:http://blog.51cto.com/sgk2011/1794381,如需转载请自行联系原作者
文章
Web App开发  ·  Linux  ·  网络安全  ·  开发工具  ·  数据安全/隐私保护
2017-11-28
kickstart无人值守自动安装操作系统
            本次文章部分参考老男孩博客张导文章 PXE是什么? PXE(Pre-boot Execution     Environment,预启动执行环境)是由Intel公司开发的最新技术,工作于Client/Server的网络模式,支持工作站通过网络从远端服务器下载映像,并由此支持通过网络启动操作系统,在启动过程中,终端要求服务器分配IP地址,再用TFTP(trivial     file transfer protocol)或MTFTP(multicast trivial file transfer     protocol)协议下载一个启动软件包到本机内存中执行,由这个启动软件包完成终端基本软件设置,从而引导预先安装在服务器中的终端操作系统。 严格来说,PXE 并不是一种安装方式,而是一种引导方式。进行 PXE 安装的必要条件是在要安装的计算机中必须包含一个 PXE 支持的网卡(NIC),即网卡中必须要有 PXE     Client。PXE 协议可以使计算机通过网络启动。此协议分为     Client端和 Server 端,而PXE     Client则在网卡的 ROM 中。当计算机引导时,BIOS 把 PXE     Client 调入内存中执行,然后由 PXE Client 将放置在远端的文件通过网络下载到本地运行。运行 PXE 协议需要设置 DHCP 服务器和 TFTP 服务器。DHCP 服务器会给 PXE     Client(将要安装系统的主机)分配一个 IP 地址,由于是给 PXE     Client 分配 IP 地址,所以在配置 DHCP 服务器时需要增加相应的 PXE 设置。此外,在 PXE     Client 的 ROM 中,已经存在了 TFTP     Client,那么它就可以通过 TFTP 协议到 TFTP     Server 上下载所需的文件了。 pxe小结: PXE,全称Pre-boot     Execution Environment 预启动执行环境 通过网络接口启动计算机,不依赖本地存储设备或本地已安装的操作系统 C/S的工作模式 由intel公司开发的最新技术 PXE客户端会调用IP,UDP,DHCP,TFTP等网络协议 PXE客户端其实是指网卡有PXE     client,存放在网卡的ROM中,当服务器启动时候bios会把pxe     client调到内存中执行   PXE的工作原理 PXE client从自己的PXE网卡启动,向本网络中DHCP服务器请求IP DHCP 服务器返回给客户机IP以及PXE文件放置位置(该文件放置在TFTP上) PXE client向本网络中的TFTP服务器索取pxelinux.0,pxelinux.cfg/default、vmlinuz、initrd.img等文件 根据pxelinux.0得到的结果,执行该文件 根据pxelinux.0的执行结果,通过TFTP服务器加载内核和文件系统 进入安装画面,此时可以通过选择HTTP、FTP、NFS方式进行安装 图解: 什么是kickstart Kickstart是一种无人值守的安装方式。它的工作原理是在安装过程中记录典型的需要人工干预填写的各种参数,并生成一个名为ks.cfg的文件。如果在安装过程中(不只局限于生成Kickstart安装文件的机器)出现要填写参数的情况,安装程序首先会去查找Kickstart生成的文件,如果找到合适的参数,就采用所找到的参数;如果没有找到合适的参数,便需要安装者手工干预了。所以,如果Kickstart文件涵盖了安装过程中可能出现的所有需要填写的参数,那么安装者完全可以只告诉安装程序从何处取ks.cfg文件,然后就去忙自己的事情。等安装完毕,安装程序会根据ks.cfg中的设置重启系统,并结束安装。 图解:(借鉴与网上) 系统环境 实验环境:VMware Workstations 11 系统平台: [root@m01 ~]# cat /etc/redhat-release CentOS release 6.7 (Final) [root@m01 ~]# uname -rm 2.6.32-573.el6.x86_64 x86_64 [root@m01 ~]# getenforce Disabled [root@m01 ~]# /etc/init.d/iptables status iptables:未运行防火墙。 网络模式:NAT模式 注意:   虚拟机网卡采用NAT模式,不要使用桥接模式,因为稍后我们会搭建DHCP服务器,在同一局域网多个DHCP服务会有冲突。 VMware的NAT模式的dhcp服务也关闭,避免干扰。 安装服务程序 从上图的pxe+kickstart工作原理图可以看出,这里需要DHCP,TFTP,HTTP根据架构需求有时候还需要NFS服务,下面我们先安装这个几个服务 [root@m01 ~]# yum install -y httpd dhcp tftp-server [root@m01 ~]# rpm -qa httpd dhcp tftp-server tftp-server-0.49-8.el6.x86_64 dhcp-4.1.1-51.P1.el6.centos.x86_64 httpd-2.2.15-53.el6.centos.x86_64 [root@m01 ~]# DHCP服务配置 [root@m01 ~]# vim /etc/dhcp/dhcpd.conf ddns-update-style interim; ignore client-updates; filename "pxelinux.0";             #pxelinux 启动文件位置; next-server 172.16.1.61;   subnet 172.16.1.0 netmask 255.255.255.0 {           option routers                  172.16.1.61;         option subnet-mask              255.255.255.0;           range dynamic-bootp 172.16.1.100 172.16.1.200;         default-lease-time 21600;         max-lease-time 43200; } range  172.16.1.100 172.16.1.200         # 可分配的起始IP-结束IP option subnet-mask 255.255.255.0;    # 设定netmask default-lease-time 21600;            # 设置默认的IP租用期限 max-lease-time 43200;                # 设置最大的IP租用期限 next-server 10.0.0.7;                # 告知客户端TFTP服务器的ip filename "/pxelinux.0";              # 告知客户端从TFTP根目录下载pxelinux.0文件 [root@m01 ~]# /etc/init.d/dhcpd start 正在启动 dhcpd:                                           [确定] [root@m01 ~]# netstat -lntup|grep dhcp udp        0      0 0.0.0.0:67                  0.0.0.0:*                               1528/dhcpd ** 多网卡默认监听eth0,指定DHCP监听eth1网卡** [root@m01 ~] vim /etc/sysconfig/dhcpd # Command line options here DHCPDARGS=eth1  # 指定监听网卡 配置TFTP服务 TFTP简介 TFTP(Trivial File Transfer Protocol,简单文件传输协议)是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议,提供不复杂、开销不大的文件传输服务。端口号为69。 [root@m01 ~]# vim /etc/xinetd.d/tftp   # default: off # description: The tftp server serves files using the trivial file transfer \ #       protocol.  The tftp protocol is often used to boot diskless \ #       workstations, download configuration files to network-aware printers, \ #       and to start the installation process for some operating systems. service tftp {         socket_type             = dgram         protocol                = udp         wait                    = yes         user                    = root         server                  = /usr/sbin/in.tftpd         server_args             = -s /var/lib/tftpboot         disable                 = no         per_source              = 11         cps                     = 100 2         flags                   = IPv4 } [root@m01 ~]# /etc/init.d/xinetd start 正在启动 xinetd:                                          [确定] [root@m01 ~]# netstat -lntup|grep 69 udp        0      0 0.0.0.0:69                  0.0.0.0:*                               1584/xinetd server_args一行是配置服务器的文件存放的位置,就是进行tftp传输的时候,都是从该文件夹中搜索文件的 配置HTTP服务 [root@m01 ~]# cd /var/www/html/ [root@m01 html]# mkdir CentOS-6.7 [root@m01 html]# mount /dev/cdrom /var/www/html/CentOS-6.7/ mount: block device /dev/sr0 is write-protected, mounting read-only [root@m01 html]# df -h Filesystem      Size  Used Avail Use% Mounted on /dev/sda3       8.8G  1.5G  7.0G  17% / tmpfs           491M     0  491M   0% /dev/shm /dev/sda1       190M   36M  145M  20% /boot /dev/sr0        3.7G  3.7G     0 100% /var/www/html/CentOS-6.7 [root@m01 html]# /etc/init.d/httpd start 正在启动 httpd:httpd: apr_sockaddr_info_get() failed for m01 httpd: Could not reliably determine the server's fully qualified domain name, using 127.0.0.1 for ServerName                                                            [确定] [root@m01 html]# sed -i "277i ServerName 127.0.0.1:80" /etc/httpd/conf/httpd.conf 这个命令就是消除上面那个报错的 [root@m01 html]# /etc/init.d/httpd restart 停止 httpd:                                               [确定] 正在启动 httpd: 浏览器访问pxe服务器,测试配置是否正确 配置支持PXE的启动程序 PXE引导配置(bootstrap) syslinux是一个功能强大的引导加载程序,而且兼容各种介质。syslinux是一个小型的Linux操作系统,它的目的是简化首次安装Linux的时间,并建立维护或其他特殊用途的启动盘。如果没有找到pxelinux.0这个文件,可以安装一下syslinux。 [root@m01~]# yum install -y syslinux [root@m01~]# rpm -qa syslinux syslinux-4.04-3.el6.x86_64 复制pxelinux.0文件至tftp的默认目录中去/var/lib/tftpboot [root@m01~]# cp /usr/share/syslinux/pxelinux.0 /var/lib/tftpboot/ 复制iso 镜像中的/isolinux/*.msg 至/var/lib/tftpboot/ 文件夹中 [root@m01 ~]# cp/var/www/html/CentOS-6.7/isolinux/*.msg /var/lib/tftpboot/ 复制iso 镜像中的/image/pxeboot/initrd.img和vmlinux 至/var/lib/tftpboot/ 文件夹中 [root@m01 ~]# cp/var/www/html/CentOS-6.7/images/pxeboot/initrd.img /var/lib/tftpboot/ [root@m01 ~]# cp/var/www/html/CentOS-6.7/images/pxeboot/vmlinuz /var/lib/tftpboot 将iso 镜像中的/isolinux目录中的isolinux.cfg复制到pxelinux.cfg目录中,同时更改文件名称为default 这里也可以直接全部复制过去: cp-a /var/www/html/CentOS-6.7/isolinux/* /var/lib/tftpboot/   [root@m01~]# mkdir -p /var/lib/tftpboot/pxelinux.cfg [root@m01~]# cp /var/www/html/CentOS-6.7/isolinux/isolinux.cfg/var/lib/tftpboot/pxelinux.cfg/default pxe配置文件default解析 [root@m01 ~]# vim/var/lib/tftpboot/pxelinux.cfg/default default ks#默认启动的是 'label ks' 中标记的启动内核 default vesamenu.c32  # 默认加载一个菜单 #prompt 1             # 开启会显示命令行'boot:'提示符。prompt值为0时则不提示,将会直接启动'default'参数中指定的内容。 timeout 600           # timeout时间是引导时等待用户手动选择的时间,设为1可直接引导,单位为1/10秒。 display boot.msg#显示某个文件的内容,注意文件的路径。默认是在/var/lib/tftpboot/ 目录下。也可以指定位类似 '/install/boot.msg'这样的,路径+文件名。 F1 boot.msg #按下 'F1' 这样的键后显示的文件。 F2 options.msg  F3 general.msg  F4 param.msg  F5 rescue.msg # 菜单背景图片、标题、颜色。 menubackground splash.jpg menutitle Welcome to CentOS 6.7! menucolor border 0 #ffffffff #00000000 menucolor sel 7 #ffffffff #ff000000 menucolor title 0 #ffffffff #00000000 menucolor tabmsg 0 #ffffffff #00000000 menucolor unsel 0 #ffffffff #00000000 menucolor hotsel 0 #ff000000 #ffffffff menucolor hotkey 7 #ffffffff #ff000000 menucolor scrollbar 0 #ffffffff #00000000 # label指定在boot:提示符下输入的关键字,比如boot:linux[ENTER],这个会启动labellinux下标记的kernel和initrd.img文件。 label linux      # 一个标签就是前面图片的一行选项。   menu label ^Install or upgrade an existingsystem   menu default  kernel vmlinuz  # 指定要启动的内核。同样要注意路径,默认是/tftpboot目录。  append initrd=initrd.img # 指定追加给内核的参数,initrd.img是一个最小的linux系统 labelvesa   menu label Install system with ^basic videodriver   kernel vmlinuz   append initrd=initrd.img nomodeset labelrescue   menu label ^Rescue installed system   kernel vmlinuz   append initrd=initrd.img rescue labellocal   menu label Boot from ^local drive   localboot 0xffff labelmemtest86   menu label ^Memory test   kernel memtest   append - 新开虚拟机测试 这里可以新开一个虚拟机网卡设置为NAT模式,开机新的虚拟机,发现会获取到172.16.1.x网段的一个IP地址 在Installation Method这一步,如果是选择URL,后面我要输入http://172.16.1.61/CentOS-6.7/ 在Installation Method这一步,如果是选择NFS directory,后面的写法是nfs:172.16.1.61:/data/sys/kickstart/ks.cfg 到这里的测试你发现还是需要手动的,所以我们要继续操作达到一键自动安装 创建ks.cfg文件 通常,我们在安装操作系统的过程中,需要大量的和服务器交互操作,为了减少这个交互过程,kickstart就诞生了。使用这种kickstart,只需事先定义好一个Kickstart自动应答配置文件ks.cfg(通常存放在安装服务器上),并让安装程序知道该配置文件的位置,在安装过程中安装程序就可以自己从该文件中读取安装配置,这样就避免了在安装过程中多次的人机交互,从而实现无人值守的自动化安装。 生成kickstart配置文件的三种方法: 方法1、     每安装好一台Centos机器,Centos安装程序都会创建一个kickstart配置文件,记录你的真实安装配置。如果你希望实现和某系统类似的安装,可以基于该系统的kickstart配置文件来生成你自己的kickstart配置文件。(生成的文件名字叫anaconda-ks.cfg位于/root/anaconda-ks.cfg) 方法2、Centos提供了一个图形化的kickstart配置工具。在任何一个安装好的Linux系统上运行该工具,就可以很容易地创建你自己的kickstart配置文件。kickstart配置工具命令为redhat-config-kickstart(RHEL3)或system-config-kickstart(RHEL4,RHEL5).网上有很多用CentOS桌面版生成ks文件的文章,如果有现成的系统就没什么可说。但没有现成的,也没有必要去用桌面版,命令行也很简单。 方法3、阅读kickstart配置文件的手册。用任何一个文本编辑器都可以创建你自己的kickstart配置文件。 查看anaconda-ks.cfg文件 [root@m01 ~]# cat anaconda-ks.cfg # Kickstart file automatically generated by anaconda.   #version=DEVEL install cdrom lang en_US.UTF-8 keyboard us network --onboot no --device eth0 --bootproto dhcp --noipv6 network --onboot no --device eth1 --bootproto dhcp --noipv6 rootpw  --iscrypted $6$S5zy08GhFmCSFoJg$IUzRPrNmiIWv2S.nFSpDqN7yuaIvZxBr0Y9s9sh2F5rFZrkbJW0uOIbSUK3eTPOnKgQENgXmkSHMF2tII0Zwb1 firewall --service=ssh authconfig --enableshadow --passalgo=sha512 selinux --enforcing timezone --utc Asia/Shanghai bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" # The following is the partition information you requested # Note that any partitions you deleted are not expressed # here so unless you clear all partitions first, this is # not guaranteed to work #clearpart --none   #part /boot --fstype=ext4 --asprimary --size=200 #part swap --asprimary --size=768 #part / --fstype=ext4 --grow --asprimary --size=200     repo --name="CentOS"  --baseurl=cdrom:sr0 --cost=100   %packages @base @compat-libraries @core @debugging @development @server-policy @workstation-policy python-dmidecode sgpio device-mapper-persistent-data systemtap-client %end[root@m01 ~]# ks.cfg详解 官网文档  CentOS5 : http://www.centos.org/docs/5/html/Installation_Guide-en-US/s1-kickstart2-options.html  CentOS6 : https://access.redhat.com/knowledge/docs/en-US/Red_Hat_Enterprise_Linux/6/html/Installation_Guide/s1-kickstart2-options.html  官网自带中文版,选一下语言即可  ks.cfg文件组成大致分为3段 命令段           键盘类型,语言,安装方式等系统的配置,有必选项和可选项,如果缺少某项必选项,安装时会中断并提示用户选择此项的选项 软件包段   %packages @groupname:指定安装的包组 package_name:指定安装的包 -package_name:指定不安装的包 在安装过程中默认安装的软件包,安装软件时会自动分析依赖关系。 脚本段(可选)   %pre:安装系统前执行的命令或脚本(由于只依赖于启动镜像,支持的命令很少) %post:安装系统后执行的命令或脚本(基本支持所有命令) 关键字含义 install告知安装程序,这是一次全新安装,而不是升级upgrade。 url --url=" "通过FTP或HTTP从远程服务器上的安装树中安装。 url --url="http://10.0.0.7/CentOS-6.7/" url --url ftp://<username>:<password>@<server>/<dir> nfs从指定的NFS服务器安装。 nfs --server=nfsserver.example.com --dir=/tmp/install-tree text使用文本模式安装。 lang设置在安装过程中使用的语言以及系统的缺省语言。lang en_US.UTF-8 keyboard设置系统键盘类型。keyboard us zerombr清除mbr引导信息。 bootloader系统引导相关配置。 bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" --location=,指定引导记录被写入的位置.有效的值如下:mbr(缺省),partition(在包含内核的分区的第一个扇区安装引导装载程序)或none(不安装引导装载程序)。 --driveorder,指定在BIOS引导顺序中居首的驱动器。 --append=,指定内核参数.要指定多个参数,使用空格分隔它们。 network为通过网络的kickstart安装以及所安装的系统配置联网信息。 network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6 --hostname=CentOS6 --bootproto=[dhcp/bootp/static]中的一种,缺省值是dhcp。bootp和dhcp被认为是相同的。 static方法要求在kickstart文件里输入所有的网络信息。 network --bootproto=static --ip=10.0.0.100 --netmask=255.255.255.0 --gateway=10.0.0.2 --nameserver=10.0.0.2 请注意所有配置信息都必须在一行上指定,不能使用反斜线来换行。 --ip=,要安装的机器的IP地址. --gateway=,IP地址格式的默认网关. --netmask=,安装的系统的子网掩码. --hostname=,安装的系统的主机名. --onboot=,是否在引导时启用该设备. --noipv6=,禁用此设备的IPv6. --nameserver=,配置dns解析. timezone设置系统时区。timezone --utc Asia/Shanghai authconfig系统认证信息。authconfig --enableshadow --passalgo=sha512 设置密码加密方式为sha512 启用shadow文件。 rootpwroot密码 clearpart清空分区。clearpart --all --initlabel --all 从系统中清除所有分区,--initlable 初始化磁盘标签 part磁盘分区。 part /boot --fstype=ext4 --asprimary --size=200 part swap --size=1024 part / --fstype=ext4 --grow --asprimary --size=200 --fstype=,为分区设置文件系统类型.有效的类型为ext2,ext3,swap和vfat。 --asprimary,强迫把分区分配为主分区,否则提示分区失败。 --size=,以MB为单位的分区最小值.在此处指定一个整数值,如500.不要在数字后面加MB。 --grow,告诉分区使用所有可用空间(若有),或使用设置的最大值。 firstboot负责协助配置redhat一些重要的信息。 firstboot --disable selinux关闭selinux。selinux --disabled firewall关闭防火墙。firewall --disabled logging设置日志级别。logging --level=info reboot设定安装完成后重启,此选项必须存在,不然kickstart显示一条消息,并等待用户按任意键后才重新引导,也可以选择halt关机。 编写ks.cfg文件 [root@m01 ~]# grub-crypt Password: Retype password: $6$QWtrdZSfLPK6JMvB$/2.tLsLBb59StIJrPxpXkk3zSgzkKMTrvw8tnBNLKxnMEzkjrbNMhhe2cd0fd2bUi5y1f47gXB1T6gbBHApPX. [root@m01 ~]# mkdir -p /var/www/html/ks_config [root@m01 ~]# cd /var/www/html/ks_config/ # Kickstart Configurator for CentOS 6.7 by yao zhang install url --url="http://172.16.1.61/CentOS-6.7/" text lang en_US.UTF-8 keyboard us zerombr bootloader --location=mbr --driveorder=sda --append="crashkernel=auto rhgb quiet" network --bootproto=dhcp --device=eth0 --onboot=yes --noipv6 --hostname=CentOS6 timezone --utc Asia/Shanghai authconfig --enableshadow --passalgo=sha512 rootpw  --iscrypted $6$QWtrdZSfLPK6JMvB$/2.tLsLBb59StIJrPxpXkk3zSgzkKMTrvw8tnBNLKxnMEzkjrbNMhhe2cd0fd2bUi5y1f47gXB1T6gbBHApPX. clearpart --all --initlabel part /boot --fstype=ext4 --asprimary --size=200 part swap --size=1024 part / --fstype=ext4 --grow --asprimary --size=200 firstboot --disable selinux --disabled firewall --disabled logging --level=info reboot %packages @base @compat-libraries @debugging @development tree nmap sysstat lrzsz dos2unix telnet %post wget -O /tmp/optimization.sh http://172.16.1.61/ks_config/optimization.sh&>/dev/null /bin/sh /tmp/optimization.sh %end 编辑脚本:(使用的是老师张导的脚本) [root@m01 ks_config]# vim /var/www/html/ks_config/optimization.sh #!/bin/bash . /etc/init.d/functions Ip=172.16.1.61 Port=80 ConfigDir=ks_config # Judge Http server is ok? PortNum=`nmap $Ip  -p $Port 2>/dev/null|grep open|wc -l` [ $PortNum -lt 1 ] && {         echo "Http server is bad!"         exit 1 } # Defined result function function Msg(){         if [ $? -eq 0 ];then           action "$1" /bin/true         else           action "$1" /bin/false         fi } # Defined IP function function ConfigIP(){         Suffix=`ifconfig eth0|awk -F "[ .]+" 'NR==2 {print $6}'`         cat >/etc/sysconfig/network-scripts/ifcfg-eth0 <<-END         DEVICE=eth0         TYPE=Ethernet         ONBOOT=yes         NM_CONTROLLED=yes         BOOTPROTO=none         IPADDR=10.0.0.$Suffix         PREFIX=24         GATEWAY=10.0.0.2         DNS1=10.0.0.2         DEFROUTE=yes         IPV4_FAILURE_FATAL=yes         IPV6INIT=no         NAME="System eth0"         END         Msg "config eth0" } # Defined Yum source Functions function yum(){         YumDir=/etc/yum.repos.d         [ -f "$YumDir/CentOS-Base.repo" ] && cp $YumDir/CentOS-Base.repo{,.ori}         wget -O $YumDir/CentOS-Base.repo http://$Ip:$Port/$ConfigDir/CentOS-Base.repo&>/dev/null &&\         wget -O $YumDir/epel.repo http://$Ip:$Port/$ConfigDir/epel.repo&>/dev/null &&\         Msg "YUM source" } # Defined Hide the system version number Functions function HideVersion(){         [ -f "/etc/issue" ] && >/etc/issue         Msg "Hide issue"         [ -f "/etc/issue.net" ] && > /etc/issue.net         Msg "Hide issue.net" } # Defined OPEN FILES Functions function openfiles(){         [ -f "/etc/security/limits.conf" ] && {         echo '*  -  nofile  65535' >> /etc/security/limits.conf         Msg "open files"         } } # Defined Kernel parameters Functions function kernel(){         KernelDir=/etc         [ -f "$KernelDir/sysctl.conf" ] && /bin/mv $KernelDir/sysctl.conf{,.ori}         wget -O $KernelDir/sysctl.conf http://$Ip:$Port/$ConfigDir/sysctl.conf&>/dev/null         Msg "Kernel config" } # Defined System Startup Services Functions function boot(){         for oldboy in `chkconfig --list|grep "3:on"|awk '{print $1}'|grep -vE "crond|network|rsyslog|sshd|sysstat"`           do            chkconfig $oldboy off         done         Msg "BOOT config" } # Defined Time Synchronization Functions function Time(){         echo "#time sync by zhangyao at $(date +%F)" >>/var/spool/cron/root         echo '*/5 * * * * /usr/sbin/ntpdate time.nist.gov &>/dev/null' >>/var/spool/cron/root         Msg "Time Synchronization" } # Defined main Functions function main(){         ConfigIP         yum         HideVersion         openfiles         kernel         boot         Time } main # rz上传CentOS-Base.repo、epel.repo、sysctl.conf 编辑优化default文件 # 最精简配置 [root@linux-node1 ~]# vim /var/lib/tftpboot/pxelinux.cfg/default default ks prompt 0 label ks   kernel vmlinuz   append initrd=initrd.img ks=http://172.16.1.61/ks_config/CentOS-6.7-ks.cfg # 告诉安装程序ks.cfg文件在哪里 # append initrd=initrd.img ks=http://10.0.0.7/ks_config/CentOS-6.7-ks.cfg ksdevice=eth0 # ksdevice=eth0代表当客户端有多块网卡的时候,要实现自动化需要设置从eth1安装,不指定的话,安装的时候系统会让你选择,那就不叫全自动化了。 PXE配置文件default 由于多个客户端可以从一个PXE服务器引导,PXE引导映像使用了一个复杂的配置文件搜索方式来查找针对客户机的配置文件。如果客户机的网卡的MAC地址为8F:3H:AA:6B:CC:5D,对应的IP地址为10.0.0.195,那么客户机首先尝试以MAC地址为文件名匹配的配置文件,如果不存在就以IP地址来查找。根据上述环境针对这台主机要查找的以一个配置文件就是/tftpboot/pxelinux.cfg/01-8F:3H:AA:6B:CC:5D。如果该文件不存在,就会根据IP地址来查找配置文件了,这个算法更复杂些,PXE映像查找会根据IP地址16进制命名的客户机配置文件。例如:10.0.0.195对应的16进制的形式为C0A801C3。(可以通过syslinux软件包提供的gethostip命令将10进制的IP转换为16进制) 如果C0A801C3文件不存在,就尝试查找C0A801C文件,如果C0A801C也不存在,那么就尝试C0A801文件,依次类推,直到查找C文件,如果C也不存在的话,那么最后尝试default文件。 总体来说,pxelinux搜索的文件的顺序是:   /tftpboot/pxelinux.cfg/01-88-99-aa-bb-cc-dd /tftpboot/pxelinux.cfg/C0A801C3 /tftpboot/pxelinux.cfg/C0A801C /tftpboot/pxelinux.cfg/C0A801 /tftpboot/pxelinux.cfg/C0A80 /tftpboot/pxelinux.cfg/C0A8 /tftpboot/pxelinux.cfg/C0A /tftpboot/pxelinux.cfg/C0 /tftpboot/pxelinux.cfg/C /tftpboot/pxelinux.cfg/default 应用:如果已经从厂商获取了服务器MAC地址,就可以差异化定制安装服务器了。 本文转自 kesungang 51CTO博客,原文链接:http://blog.51cto.com/sgk2011/1832206,如需转载请自行联系原作者
文章
Web App开发  ·  Linux  ·  网络安全  ·  开发工具  ·  数据安全/隐私保护
2017-11-28
WebSocket学习
WebSocket学习 为什么需要WebSocket 以往使用的HTTP协议存在一个缺陷,通信只能由客户端发起。 这种单向请求的特点,如果有一个添加好友的业务场景存在,那就注定客户端必须采用轮询的机制,去设置间隔时间,不断地去请求服务端,无疑对客户端存在延时操作,同时也是对服务端的一种极大的损耗。 效率低,浪费资源(因为必须不停地连接,或者HTTP连接始终打开) 轮询(Polling) 长连接 长轮询 流技术 这是最早的一种实现实时 Web应用的方案。客户端以一定的时间间隔向服务端发出请求,以频繁请求的方式来保持客户端和服务器端的同步。这种同步方案的最大问题是,当客户端以固定频率向服务器发起请求的时候,服务器端的数据可能并没有更新,这样会带来很多无谓的网络传输,所以这是一种非常低效的实时方案。 轮询(Polling)是指不管服务器端有没有更新,客户端(通常是指浏览器)都定时的发送请求进行查询,轮询的结果可能是服务器端有新的更新过来,也可能什么也没有,只是返回个空的信息。不管结果如何,客户端处理完后到下一个定时时间点将继续下一轮的轮询。 推送或叫长连接(Long-Polling)的服务其客户端是不做轮询的,客户端在发起一次请求后立即挂起,一直到服务器端有更新的时候,服务器才会主动推送信息到客户端。 在服务器端有更新并推送信息过来之前这个周期内,客户端不会有新的多余的请求发生,服务器端对此客户端也啥都不用干,只保留最基本的连接信息,一旦服务器有更新将推送给客户端,客户端将相应的做出处理,处理完后再重新发起下一轮请求。 分为长轮询和流2种: 长轮询:长轮询是对定时轮询的改进和提高,目地是为了降低无效的网络传输。当服务器端没有数据更新的时候,连接会保持一段时间周期直到数据或状态改变或者时间过期,通过这种机制来减少无效的客户端和服务器间的交互。当然,如果服务端的数据变更非常频繁的话,这种机制和定时轮询比较起来没有本质上的性能的提高。 WebSocket机制 借助Spring WebSockets文档的原话:WebSocket通过单个TCP连接在客户端和服务器之间建立全双工,双向通信通道。它是来自HTTP的一种不同的TCP协议,但被设计为通过HTTP工作,使用端口80和443并允许重新使用现有的防火墙规则。 WebSocket的交互其实基于HTTP的"Upgrade"头进行升级HTTP请求,或者在此情况下切换到WebSocket协议: GET /spring-websocket-portfolio/portfolio HTTP/1.1 Host: localhost:8080 Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: Uc9l9TMkWGbHFD2qnFHltg== Sec-WebSocket-Protocol: v10.stomp, v11.stomp Sec-WebSocket-Version: 13 Origin: http://localhost:8080 相较于其他HTTP请求成功时返回200,在使用WebSocket请求连接基于HTTP握手的时候,******服务端会返回101状态码******( 服务器已经理解了客户端的请求,并将通过Upgrade 消息头通知客户端采用不同的协议来完成这个请求。在发送完这个响应最后的空行后,服务器将会切换到在Upgrade 消息头中定义的那些协议。 只有在切换新的协议更有好处的时候才应该采取类似措施。例如,切换到新的HTTP版本比旧版本更有优势,或者切换到一个实时且同步的协议以传送利用此类特性的资源。) 下面是响应头 HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: 1qVdfYHU9hPOl4JYYNXF623Gzn0= Sec-WebSocket-Protocol: v10.stomp 这段响应码的意思是说:服务端接收到WebSocket握手请求后,同意切换协议,切换至websocket协议,并且使用V10.stomp 握手成功后,HTTP升级请求的TCP套接字将保持打开状态,以便客户端和服务器继续发送和接收消息。 服务器,如果它支持的协议,回复与同一Upgrade: WebSocket和Connection: Upgrade页眉和完成握手。握手成功完成后,数据传输开始。 HTTP vs WebSocket 尽管WebSocket被设计为与HTTP兼容并以HTTP请求开始,但了解这两种协议导致非常不同的体系结构和应用程序编程模型是很重要的。 在HTTP和REST中,应用程序被建模为尽可能多的URL。要与应用程序客户端交互访问这些URL,请求 - 响应样式。服务器根据HTTP URL,方法和标头将请求路由到适当的处理程序。 相比之下,在WebSockets中,初始连接通常只有一个URL,随后所有应用程序消息都会在同一个TCP连接上流动。这指向一个完全不同的异步,事件驱动的消息体系结构。 WebSocket也是一种低级传输协议,它不像HTTP那样规定消息内容的任何语义。这意味着除非客户端和服务器对消息语义达成一致,否则无法路由或处理消息。 WebSocket客户端和服务器可以通过"Sec-WebSocket-Protocol"HTTP握手请求中的头部来协商使用更高级别的消息传递协议(例如STOMP),或者在没有他们需要提出自己的约定的情况下进行协商。 在之后会为大家介绍STOMP协议 WebSocket的特点 最大的特点是:服务端可以主动向客户端推送信息,客户端也可以主动向服务端发送信息,是一种双向通信,也属于服务器的额推送技术之一。 建立在TCP协议上,服务端的实现比较容易 与HTTP协议有着很好的兼容性,并且握手阶段采用HTTP协议,因此握手时不容易屏蔽,能通过各种HTTP代理服务器 数据格式比较轻量,性能开销小,通信高效。 可以发送文本,也可以发送二进制数据。 没有同源限制,客户端可以与任意服务器通信。 协议标识符是ws如果加密为wss 例如 ws://localhost:8080/GoTogether/websocket                                  协议图 SSM项目使用Spring Websocket 今天想在SSM项目中带入websocket试着使用一下,但是一直有些问题没能解决。 也借着今天这个机会能够深入理解一下websocket和普通的http请求有什么区别,下面总结一下今天踩的坑。 在Spring中使用Websocket 首先需要添加如下依赖 <!--websocket--> <!-- https://mvnrepository.com/artifact/org.springframework/spring-websocket --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-websocket</artifactId> <version>5.0.5.RELEASE</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-messaging --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-messaging</artifactId> <version>5.0.5.RELEASE</version> </dependency> 最好还是保证版本号一致吧,至少能少一点bug 在springContext.xml中配置 <bean id="websocket" class="com.bsb.handler.MyHandler"/> <websocket:handlers allowed-origins="http://www.blue-zero.com"> <websocket:mapping path="/websocket" handler="websocket"/> <websocket:handshake-interceptors> <bean class="org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor"/> </websocket:handshake-interceptors> </websocket:handlers> 这里的allowed-origins一会儿在做描述 这里附上自己实现的MyHandler类 package com.bsb.handler; import org.springframework.web.socket.TextMessage; import org.springframework.web.socket.WebSocketSession; import org.springframework.web.socket.handler.TextWebSocketHandler; public class MyHandler extends TextWebSocketHandler { @Override protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception { super.handleTextMessage(session, message); TextMessage textMessage = new TextMessage(message.getPayload() + " received at server"); session.sendMessage(textMessage); } } 这里的MyHandler类很简单,继承TextWebSocketHandler类,重写handleTextMessage方法,将客户端发送至我的消息又发送给客户端进行通信。 下面和大家分享一下在项目中使用时遇到的问题 下面是得知websocket建立连接遵循HTTP连接的三次握手后,自己写的握手的拦截器,目的是为了检测握手的动态。 package com.bsb.interceptor; import org.springframework.http.server.ServerHttpRequest; import org.springframework.http.server.ServerHttpResponse; import org.springframework.web.socket.WebSocketHandler; import org.springframework.web.socket.server.support.HttpSessionHandshakeInterceptor ; import java.util.Map; public class HandShakeInterceptor extends HttpSessionHandshakeInterceptor { @Override public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { System.out.println("before handshake"); return super.beforeHandshake(request, response, wsHandler, attributes); } @Override public void afterHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Exception ex) { System.out.println("after handshake"); super.afterHandshake(request, response, wsHandler, ex); } } 到这里就开始出问题了,我开始测试websocket的连接 使用的是 http://www.blue-zero.com/WebSocket/ 一个别人写好的websocket的测试页面,接下来看具体情况 上面提到了allowed-origins属性,一开始我在没有配置它的时候使用连接是这样的: 你 0:45:10 等待服务器握手包... 服务器 0:45:10 和服务器断开连接! //下面是idea打印的日志 [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7904 ]-[ DEBUG ]-DispatcherServlet with name 'dispatcher' processing GET request for [/GoTogether/websocket] [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7907 ]-[ DEBUG ]-Looking up handler method for path /websocket [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7910 ]-[ DEBUG ]-Did not find handler method for [/websocket] [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7915 ]-[ DEBUG ]-Mapping [/websocket] to HandlerExecutionChain with handler [org.springframework.web.socket.server.support.WebSocketHttpRequestHandler@7df5a3e] and 1 interceptor [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7920 ]-[ DEBUG ]-Last-Modified value for [/GoTogether/websocket] is: -1 [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7961 ]-[ DEBUG ]-GET /GoTogether/websocket [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7961 ]-[ DEBUG ]-Handshake request rejected, Origin header value http://www.blue-zero.com not allowed [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7961 ]-[ DEBUG ]-org.springframework.web.socket.server.support.OriginHandshakeInterceptor@2474dfc0 returns false from beforeHandshake - precluding handshake [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7961 ]-[ DEBUG ]-Null ModelAndView returned to DispatcherServlet with name 'dispatcher': assuming HandlerAdapter completed request handling [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7962 ]-[ DEBUG ]-Successfully completed request [2018-05-08 12:45:10] - [ http-nio-8080-exec-1:7966 ]-[ DEBUG ]-Returning cached instance of singleton bean 'sqlSessionFactory' 可以看到错误出在这里: Handshake request rejected, Origin header value http://www.blue-zero.com not allowed 大概意思是说,握手失败,建立连接失败,Origin这个请求头字段的这个值不被允许。这跟web页面返回给我们信息一致,就是建立不了连接,差了很多结果都没有用,接下来甚至还了解了一下web的跨域是怎么回事。 迷迷糊糊正准备配置ssm的跨域配置,最后看到了spring websocet的官方文档后,豁然开朗! Spring WebSockets官方文档 可以看到4.2.5节的介绍 Allowed origins Same in Spring WebFlux list of origins. This check is mostly designed for browser clients. There is nothing As of Spring Framework 4.1.5, the default behavior for WebSocket and SockJS is to accept only same origin requests. It is also possible to allow all or a specified preventing other types of clients from modifying the Origin header value (see RFC 6454: The Web Origin Concept for more details). The 3 possible behaviors are: Allow only same origin requests (default): in this mode, when SockJS is enabled, the Iframe HTTP response header X-Frame-Options is set to SAMEORIGIN, and JSONP transport is disabled since it does not allow to check the origin of a request. As a consequence, IE6 and IE7 are not supported when this mode is enabled. Allow a specified list of origins: each provided allowed origin must start with http:// or https://. In this mode, when SockJS is enabled, both IFrame and JSONP based transports are disabled. As a consequence, IE6 through IE9 are not supported when this mode is enabled. Allow all origins: to enable this mode, you should provide * as the allowed origin value. In this mode, all transports are available. WebSocket and SockJS allowed origins can be configured as shown bellow: 并且还给了一段Config类和xml配置 java类不说了,看看xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:websocket="http://www.springframework.org/schema/websocket" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd"> <websocket:handlers allowed-origins="http://mydomain.com"> <websocket:mapping path="/myHandler" handler="myHandler" /> </websocket:handlers> <bean id="myHandler" class="org.springframework.samples.MyHandler"/> </beans> 大概意思就是在说allowed-origins属性是允许指定来源的列表,Origin和Referer的区别在这里也就不提了,需要了解的可以自己去搜索。并且一个请求头的Origin是没有办法被修改的。也可以设置为*作为允许的原始值,在这种情况下,所有传输都可以使用。 关于WebSocket的一些具体在项目中的应用后面会补上。 STOMP协议 STOMP即Simple (or Streaming) Text Orientated Messaging Protocol,简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。 假设HTTP协议不存在,只能使用TCP套接字来编写WEB应用,或许能完成目标,但是这需要自行设计客户端和服务端都认可的协议,从而实现有效通信。 同时也正是因为有了HTTP协议,才解决了Web浏览器发起请求以及Web服务器响应请求的细节。 直接使用WebSocket(或SockJS)就很类似于使用TCP套接字来编写Web应用。 因为没有高层的线路协议,因此这就需要我们定义应用之间所发送消息的语义,还需要确保连接两端都能遵守这些语义。 就像HTTP在TCP套接字上添加了请求-响应模型层一样,STOMP在WebSocket上提供了一个基于帧的线路格式层,用来定义消息的语义。 乍看上去STOMP的消息格式非常类似HTTP的请求结构。与HTTP请求和响应类似, STOMP帧由命令、一个或多个头信息以及负载组成。 例如如下一个STOMP帧 SEND destination:/app/test content-length:20 {\"message\":\test!!\"} STOMP命令是send,表明会发送一些内容。紧接着是两个头信息:一个用来表示消息要发送到哪里的目的地,另一个则包含了负载的大小,然后紧接着是一个空行,STOMP帧的最后内容是负载的内容,如上的帧中的负载就是一个JSON数据。 STOMP中最有意思的是destination头信息,它表明STOMP是一个消息协议,消息会发布到某个目的地,这个目的地实际上可能真的有消息代理作为支撑,另一方面,消息处理器也可能监听这些目的地,接收所发送的消息。 Spring为STOMP提供基于Spring MVC的编程模型 一会儿会为控制器的方法上添加@MessageMapping注解,使其处理STOMP消息,它与带有@RequestMapping注解的方法处理HTTP请求的方式类似,但是与其不同的是,@MessageMapping的功能无法通过@EnableWebMVC启用,Spring的Web消息功能基于消息代理(message broker)构建立,因此我们需要自己的配置类来配置一个消息代理和其它一些消息的目的地。 @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer { /** * 将"/hello"路径注册为STOMP端点,这个路径与发送和接收消息的目的路径有所不同,这是一个端点 * 客户端在订阅或者发布消息到目的地址前,要连接该端点 * 即用户发送请求到"/GoTogether/hello"与STOMP server进行连接。之后再转发到订阅的url。 * 端点的作用 - 客户端在订阅或发布信息之前,要握手连接端点 * @param registry */ @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/hello").setAllowedOrigins("*").withSockJS(); } /** * 配置了一个简单的消息代理,如果不重载,默认情况下回自动配置一个简单的内存消息代理,用来处理以"/topic"为 前缀的消息。 * 这里重载configureMessageBroker()方法,消息代理将会处理前缀为"/topic"和"/queue"的消息。 * @param registry */ @Override public void configureMessageBroker(MessageBrokerRegistry registry) { registry.enableSimpleBroker("/topic", "/user"); registry.setApplicationDestinationPrefixes("/app"); registry.setUserDestinationPrefix("/user"); } } @EnableWebSocketMessageBroker注解表明了配置类不仅配置了WebSocket,还配置了基于代理的STOMP消息。 对配置中的SockJS说明(SockJS是一个浏览器JavaScript库,它提供了一个类似于网络的对象。SockJS提供了一个连贯的、跨浏览器的Javascript API,它在浏览器和web服务器之间创建了一个低延迟、全双工、跨域通信通道。)测试使用的客户端是JSP页面中的JS客户端。 再附上Controller的代码 @RestController public class GreetingController { @Autowired private SimpMessageSendingOperations simpMessageSendingOperations; /** * 表示服务端可以接收客户端通过主题“/app/hello”发送过来的消息,客户端需要在主题"/topic/hello"上监听并接收服务端发回的消息 * @param topic * @param headers */ @MessageMapping("/hello") @SendTo("/topic/greetings") public void greeting(@Header("atytopic") String topic, @Headers Map<String, Object> headers) { System.out.println("connected successfully"); System.out.println(topic); System.out.println(headers); } /** * 这里用的是@SendToUser,这就是发送给单一客户端的标志。本例中, * 客户端接收一对一消息的主题应该是“/user/” + 用户Id + “/message” * 这里的用户id可以是一个普通的字符串,只要每个用户端都使用自己的id并且服务端知道每个用户的id就行。 * @return */ @MessageMapping("/message") @SendToUser("/message") public Greeting handleSubscribe() { System.out.println("this is the @SubscribeMapping('/marco')"); return new Greeting("I am a msg from SubscribeMapping('/macro')."); } /** * 测试对指定用户发送消息方法 * @return */ @RequestMapping(path = "/send", method = RequestMethod.GET) public Greeting send() { simpMessageSendingOperations.convertAndSendToUser("1", "/message", new Greeting("I am a msg from SubscribeMapping('/macro').")); return new Greeting("I am a msg from SubscribeMapping('/macro')."); } } //以及Pojo类Greeting public class Greeting { private String content; public Greeting(String content) { this.content = content; } public String getContent() { return content; } } 下面来看一下本地jsp页面使用js请求服务端连接websocket的HTTP请求报文 General Request URL: ws://localhost:8080/GoTogether/hello/639/0curp41b/websocket Request Method: GET Status Code: 101 Switching Protocols Response Header Connection: upgrade Date: Tue, 08 May 2018 12:50:47 GMT Sec-WebSocket-Accept: oQZ9jtefXu3s5+39vmbR94u0KgI= Server: Apache-Coyote/1.1 Upgrade: websocket Request Header Accept-Encoding: gzip, deflate, br Accept-Language: zh-CN,zh;q=0.9 Cache-Control: no-cache Connection: Upgrade Cookie: JSESSIONID=D1528D00C99C36EB1A756CE85AAAC137; Idea-7e7b0b41=9e9d5672-53b7-4270-9805-aac cb74742e3; Idea-7cec4644=6d097fc1-24ca-47ce-8c6 e-3cf6184bb47d Host: localhost:8080 Origin: http://localhost:8080 Pragma: no-cache Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits Sec-WebSocket-Key: BYmRGPG9QctFlQuAJ49veQ== Sec-WebSocket-Version: 13 Upgrade: websocket User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 Safari/537.36 通过上面的讲解,应该也就能读懂这个报文是什么意思了 那么对于WebSocket的分析以及STOMP的使用就到这里 向着明天的自己奔跑,加油!
文章
JavaScript  ·  网络协议  ·  Java  ·  数据格式  ·  Spring
2018-05-08
跳转至:
开发与运维
5184 人关注 | 125226 讨论 | 181705 内容
+ 订阅
  • Redis哨兵原理,我忍你很久了!(1)
  • Win 独享 WSL 并搭配 Oh My Zsh
  • 最简单的Markdown教程
查看更多 >
安全
1031 人关注 | 23273 讨论 | 51320 内容
+ 订阅
  • Win 独享 WSL 并搭配 Oh My Zsh
  • 终结初学者对ElasticSearch、Kibana、Logstash安装的种种困难《玩转ElasticSearch 1》-1
  • Win 终端 putty & pscp & kitty 使用
查看更多 >
数据库
248725 人关注 | 44347 讨论 | 54799 内容
+ 订阅
  • Redis哨兵原理,我忍你很久了!(1)
  • 终结初学者对ElasticSearch、Kibana、Logstash安装的种种困难《玩转ElasticSearch 1》-3
  • SpringBoot入门整合 上手 简单易解
查看更多 >
人工智能
2593 人关注 | 9266 讨论 | 61158 内容
+ 订阅
  • 终结初学者对ElasticSearch、Kibana、Logstash安装的种种困难《玩转ElasticSearch 1》-3
  • 【贪心思想】兄弟总爱贪小便宜,原来是把贪心算法掌握得如此熟练【经典例题讲解】
  • 【算法基础1】舍友课间上了个厕所,回来就告诉我他掌握了二分查找【内附搜索模板】
查看更多 >
云计算
21599 人关注 | 57837 讨论 | 36000 内容
+ 订阅
  • iOS-底层原理 34:界面优化方案
  • 面试题24解析-详谈DNS域名解析过程
  • iOS-底层原理 33:内存管理(三)AutoReleasePool & NSRunLoop 底层分析
查看更多 >