需求分析:从开发者的角度去理解和分析需求.对于IOS的消息推送的功能和性能测试,大致可分为如下几种:1).推送平台QPS/RT的性能指标2).BadDeviceToken对服务的影响评估3).证书对服务的影响评估4).推送可靠性评估(推送弱ack机制,丢消息和消息重复之间的折中)通过记录日志来评估QPS/RT和服务的质量,引入黑名单机制来模拟baddevicetoken对推送服务的影响评估.
技术分析:对APNS服务的理解和自身的功能/性能测试需求:1).APNS推送服务采用SSL长连接/二进制流/异步的方式来实现,追求推送消息的吞吐量.2).APNS支持V1/V2两种二进制协议,遇到异常时,APNS的默认行为不一样.3).APNS客户端是TSL(SSL)的单向认证(客户端携带证书,服务端信任检查).结合桩的定位,我们采用OneConnectionPerThread的线程池模式去模拟处理它,一方面能基本满足需求,另一方面实现高效简单.同时为了方便测试,服务端关闭对客户端认证机制.
服务实现:APNS模拟桩的实现过程1).服务端证书引入
keytool-genkey-v-aliasssl-server-keyalgRSA-keystore./server_ks-storepassserver-keypass123456-dname"CN=Unknown"生成效果如图2).自定义TrustManager的实现类
privateclassMyX509TrustManagerimplementsX509TrustManager{@OverridepublicX509Certificate[]getAcceptedIssuers(){returnnull;}//对服务端证书的认证,抛出异常表示不通过@OverridepublicvoidcheckServerTrusted(X509Certificate[]chain,StringauthType)throwsCertificateException{}//对客户端证书进行认证,抛出异常表示不通过@OverridepublicvoidcheckClientTrusted(X509Certificate[]chain,StringauthType)throwsCertificateException{}};评注:这边提供空实现,对客户端的证书不进行任何校验3).创建SSLServerSocket代码片段
SSLContextctx=SSLContext.getInstance("SSL");//*)创建KeyManagerFactory类实例KeyManagerFactorykmf=KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());//*)初始化KeyStore,这边的KEY_PASSWORD为"123456"KeyStoreks=KeyStore.getInstance(KeyStore.getDefaultType());ks.load(ApnsStubServer.class.getResourceAsStream("/server_ks"),null);kmf.init(ks,KEY_PASSWOR.toCharArray());//*)进行SSLContext类的初始化工作ctx.init(kmf.getKeyManagers(),newTrustManager[]{newMyX509TrustManager()},newSecureRandom());//*)SSLServerSocket的生成SSLServerSocketserverSocket=(SSLServerSocket)ctx.getServerSocketFactory().createServerSocket(serverPort);serverSocket.setReuseAddress(true);//*)设置Client认证开关关闭serverSocket.setNeedClientAuth(false);评注:把server_ks代码放到classpath目录下,同时这边的key_password为"123456",而不是keystore的密码"server",注意keypass和storepass的区别4).服务端连接处理代码
//OneConnectionPerThread的机制ExecutorServiceworkerPools=Executors.newCachedThreadPool();while(true){finalSocketcliSocket=sslServerSocket.accept();workerPools.execute(newRunnable(){@Overridepublicvoidrun(){onHandle(cliSocket);}});}评注:serverSocket用于接受客户端连接,并放入工作池去处理onHandle函数定义如下:
privatevoidonHandle(SocketcliSocket){DeviceTokenManagerdtm=apnsStubController.getDeviceTokenManager();DataInputStreamdis=newDataInputStream(cliSocket.getInputStream());intch=0;while((ch=dis.read())!=-1){IVResult
由外置黑名单文件来指定
publicclassDeviceTokenManager{//用于配置参数的初始化publicvoidinit(Propertiesprop);//判断是否为baddevicetokenpublicbooleanjudgeBadDeviceToken(StringdeviceToken);//载入baddevicetoken名单privatevoidloadBadDeviceTokenFile(Stringfilename);}总结:难点在于JSSE和证书的理解,至于APNS的网络协议,处理还是相对简单的.
后记:感觉自己还是没有把自己想表达的事情说清楚,甚是遗憾.无论如何,还是希望对读者有些帮助,对我而言,则是充满了回忆.Fighting,Letitgo!!!