高级知识点之进阶

 

1、什么是Socket?

Socket又称之为“套接字”,是系统提供的用于网络通信的方法。它的实质并不是一种协议,没有规定计算机应当怎么样传递消息,只是给程序员提供了一个发送消息的接口,程序员使用这个接口提供的方法,发送与接收消息。

Socket描述了一个IP、端口对。它简化了程序员的操作,知道对方的IP以及PORT就可以给对方发送消息,再由服务器端来处理发送的这些消息。所以,Socket一定包含了通信的双发,即客户端(Client)与服务端(server)。

 

2、Socket的通信过程?

每一个应用或者说服务,都有一个端口。比如DNS的53端口,http的80端口。我们能由DNS请求到查询信息,是因为DNS服务器时时刻刻都在监听53端口,当收到我们的查询请求以后,就能够返回我们想要的IP信息。所以,从程序设计上来讲,应该包含以下步骤:

1)服务端利用Socket监听端口;

2)客户端发起连接;

3)服务端返回信息,建立连接,开始通信;

4)客户端,服务端断开连接。

 

3、Socket双方如何建立起连接?

以下过程用代码表示:

Server端:

1 intport = 2000;
2 IPEndPointServerEP = newIPEndPoint(IPAddress.Any,port);
3 Socketserver = newSocket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
4 server.Bind(ServerEP);
5 server.Listen(0);

 

Client端:

1 intport = 2000;
2 IPAddressserverip = IPAddress.Parse("192.168.1.100");
3 IPEndPointEP = newIPEndPoint(server,port);
4 Socketserver = newSocket(AddressFamily.InterNetwork, SocketType.Stream,ProtocolType.Tcp);
5 server.Bind(EP);

当服务器端接收到来自客户端的连接以后,需要新建一个socket来处理远端的信息。

下面一段代码应该在服务器端:

1  Socketclient =server.Accept();

以上很简单的几行代码,将在以后的网络编程中经常用到,后面还会有同步通讯、异步通讯、线程、委托与事件等等

 

4、套接字(socket)概念

套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

 

5、建立socket连接

建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket,另一个运行于服务器端,称为ServerSocket。

套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求。

客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求。

连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求。

 

6、SOCKET连接与TCP连接

创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

 

7、Socket连接与HTTP连接

由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。

而HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。

很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。

 

8、说说对环信的理解

    环信是一款即时通讯的服务提供商,环信使用的是XMPP协议,他是对XMPP的二次开发;

    环信实现了视频、语音等附件的发送功能,给使用者节省了时间成本,不需要公司自己搭建聊天服务器;

    环信实现了数据缓存,会把聊天记录添加到数据库,会把附件下载到本地

 

9、环信中的图片消息及语音消息是怎么实现的?

    图片消息:首先从相册或者相机获取图片对象,将其存到沙盒或者转换成NSData,然后构造图片消息(EMImageMessageBody:initWithData/initWithLocalPath);当收到图片消息时,我们能够从消息体中解析出图片的路径(本地、网络),然后根据路径得到对应的图片

    语音消息:首先通过AVAudioRecorder进行录音,然后将录音文件保存到沙盒或转换成NSData,构造语音消息(EMVoiceMessageBody:initWithData/initWithLocalPath);当接收到语音消息时,我们可以通过消息体解析出附件的路径(本地、网络),然后通过AVAudioPlayer进行播放

 

10、环信中是怎么实现好友管理的?

    环信中的好友管理都与IEMContactManager有关

    获取好友列表:getContactsFormServer

    添加好友:addContact

    收到好友请求:didReceiveFriendInvitation

    删除好友:deleteContact

    加入黑名单:addUserToBlackList

 

11、环信与公司自己的服务器是怎么结合使用的?

    环信中有自己的一套用户信息,但是比较少,此时我们需要在自己的服务器中创建自己的用户表,该表保存了用户所有的信息(用户名、密码、性别等),同时还保存了环信的账号和密码,当用户登录时,会先登录自己的服务器,成功后再登录环信

 

12、环信中单聊与群聊是怎么区分的?

    环信中的消息有三种类型:单聊(EMChatTypeChat)/群聊(EMChatTypeGroupChat)/聊天室(EMChatTypeRoom),然后我们根据消息的chatType进行区分

 

13、环信中消息的分发

    每条消息都有自己的会话ID,我们可以根据会话ID来进行区分

 

14、怎么在环信中实现聊天记录

    环信中自带聊天记录的功能,如果我们想要自己实现,我们可以将聊天信息放到本地数据库或服务器

 

15、怎么通过环信实现阅后即焚功能?

    我们可以通过消息扩展配合已读回执进行实现

    流程:

    A-->B 发送阅后即焚消息

    1)在消息中标明,该消息需要阅后即焚,用到EMMessage的ext属性,该属性是一个字典,我们可以在字典中设置两个key,一个代表是否阅后即焚,一个代表消息的ID

    2)当B接收到消息之后,我们需要对该消息进行分析,看它是否需要阅后即焚,如果需要,则在B阅读了该消息之后,调用sendHaseReadResponse,发送已读回执

    3)当A收到已读回执后,根据消息的ID,将消息从会话中删除

 

16、离线消息

    用户只是退到了后台,并未退出账号:远程推送

    用户退出了账号:环信有处理该情况的方法

 

17、环信中气泡聊天拉气泡而不改变气泡的形状

1-(UIImage*)stretchableImageWithLeftCapWidth:(NSInteger)leftCapWithtopCapHeight:(NSInteger)topCapHeight;(iOS 5之前)
    2-(UIImage*)resizableImageWithCapInsets:(UIEdgeInsets)capInsets;(iOS 5)
    3)-(UIImage *)resizableImageWithCapInsets:(UIEdgeInsets)capInsetsresizingMode:(UIImageResizeingMode)resizingMode;(iOS 6以后)

    以上三种方法,均可以实现将图片从中间区域拉伸,而保证图片的四周保持不变   

 

18、iOS内购中,获取商品列表时,获取返回的商品数量为0

1、查看一下后台itunesConnect中该商品的状态,若颜色为红色则重新编辑一下商品信息。

  2.确保商品ID作为参数是否正确,调试一下传值过程中是否被重置为空。

 

19、iOS内购中,此APPID尚未在iTunesStore使用过。点一下“检查”登录。

1.更换设备(有可能是越狱设备,能装上提审的ipa包)

2.ipa包archive的是否正确(是用发布还是测试签名生成的)

3.新的内购商品后台编辑上架后,若服务端收不到验证需要在后台新开版本。

 

20、iOS内购中,出现无法连接appstore商店提示

确保打包的时候用的是测试签名而不是发布签名(由于越狱机器是可以安装上发布包的,所以测试的时候最好使用未越狱的机器)。 

 

21、iOS内购中,如果遇到消耗型的提示已经购买过的,那是因为你没有设置完成交易,导致系统认为你的交易没有完成所以认为你还在买同一个单子?

正确做法应该是在交易成功时,即SKPaymentTransactionStatePurchased下调用[[SKPaymentQueue defaultQueue] finishTransaction:transaction];


22、iOS内购中,在app里添加IAP,必须要注册自己的产品标识符(product identifiers)。产品标识符是什么?

产品标识符(Product Identifiers)是一串字符串,它用来识别你在应用内贩卖的每件商品。App Store用产品标识符来检索产品信息,标识符只能包含大小写字母(A-Z)、数字(0-9)、下划线(-)、以及圆点(.)。你可以任意排列这些元素,但我们建议你创建标识符时使用反向域名,比如 com.companyname.application.productid

备注:产品标识符和Apple ID以及Bundle ID没有关系,它们看起来可能比较像Bundle ID,但是两者是不一样的。所以,在代码里你不能用Apple ID或者Bundle ID代替产品标识符。

 

22、iOS内购中,怎么创建产品标识符?

IAP表单(TheIn-App Purchases form)是用来生成IAP产品的,它包含了产品ID的字段,这个字段必须要填到表里。这个字段可以为你的产品指定产品标识符。你可以按下面的步骤来创建产品标识符:

1.登入iTunes Connect, 点击主页面上的Manage YourApplications模块。

2.进入Manage Your Apps 页面,你可以看到你所有的应用列表。选择你想要创建IAP的产品的app,在下个页面中点击Manage In-App Purchases按键,然后在点击创建。

3.选择IAP产品的类型。iTunes Connect会带你进入IAP表单,在这个表单里有“保存”按键。完整填写Product ID以及表单里的其他字段。

注意事项:产品标识符一旦创建无法修改,此外,如果应用审核没有通过,这个产品标识符也无法再次使用。


24、iOS内购中,如何在app中如何使用产品标识符?

首先创建SKProductsRequest,然后把产品标识符列表传至initWithProductIdentifiers 来读取产品信息。

当在Sandbox 环境测试In-App Purchase 时,为什么我得到的是“Payment requests are restricted to products returned as valid viaStore Kit’s didReceiveResponse method”错误信息?

执行In-App Purchase的app的用户界面必须有App Store允许的可供购买的产品。在你决定在用户界面展示用于购买的产品之前,你的app必须先向App Store发送一个产品请求。

StoreKit提供了两种支付支付请求的解决办法:

[SKPaymentpaymentWithProductIdentifier:PRODUCT_ID] [SKPaymentpaymentWithProduct:YOUR_SKPRODUCT_OBJECT] 苹果建议您使用[SKPayment paymentWithProduct:YOUR_SKPRODUCT_OBJECT] 使用这个方法可以确保你一直处于有效的产品支付请求状态,同时也确保用户可以购买你的产品。所以,务必只展现App Store返回的产品信息。了解更多有关于app内产品展现信息,请查看In-App Purchase 编程指南的 Feature Delivery 部分。

 

25、iOS内购中,In-App Purchase有几种类型?

In-AppPurchase共有3中类型

Consumable:一次性购买,最简单的类型,不用保存历史记录。

Nonconsumable:每个产品,用户只买一次,此后就可以在自己的所有设备上看到该产品。

Subscriptions:订阅模式允许多次购买末一个产品,但是购买后,用户可以在自己的所有设备上看到该产品。


26、iOS内购中,iOS 中使用 IAP 方式在程序内购买的内容在重装系统后还需要再次购买吗? 比如Camera+内的滤镜。

不必。以 Camera+ 为例,Menu 里最下方的选项 Restore purchases 即可帮你解锁已经购买的滤镜。任何实现了 IAP 功能的 App 基本都会提供这一选项,或者在第二次购买时提示已购。消耗类(如游戏金币)需要购买。 功能类不需要购买,有些应用提供“Restore purchases”,没有的可以再次尝试购买,会提示已付费。

27、iOS内购中,IAP 能做限时免费吗? 想做一个免费下载、部分内容免费,但是阅读更多内容需要付费解锁的阅读应用。这样可以把IAP的价格限时免费为0吗?

可以的,你可以设定价格为0时就不走IAP了。

 

28、iOS内购中,创建产品ID的时候,选择多少钱的时候选错了,程序还未提交,还能修改吗?

可以的,在应用程序的信息中。

升级iOS5 GM的过程中恢复备份出了问题,导致In-App Purchase也丢失了。有没有办法恢复?在iPad上曾经进行过一些In-App Purchase,但是在升级iOS5 GM的过程中恢复备份出了问题,导致除了恢复升级前的所有应用程序之外,其余个人信息一概丢失。iTunes上可以查询到购买记录。具体来说,买的是Splashtop的把iPad作为第二显示器的软件,Xdisplay。

In-AppPurchase 分好几种,最常见的是 Non-Consumable,就是只需要用户购买一次的。如果是这种类型的,再购买一次同一个商品就能够恢复了,不会收取额外费用。如果 app 做得好的话,应该提供一个 Restore 功能,以专门恢复以前购买过的 Non-Consumable 的商品。

 

29、iOS内购中,如何核实receipt(iOS)?

第一次一般使用产品的URL核实收据。如果你收到一个21007状态代码,那么接下来要用sandbox URL。当app处于测试状态或者在sandbox环境下进行检测,或者上架App Store,你可以使用这种方法,从而避免在URL之间进行切换,注明:21007 状态码表明receipt是一个sandbox receipt。

 

30、支付宝错误

          

在 openssl_wrapper.h中#import <Foundation/Foundation.h>库即可

31、支付宝错误Util/openssl_wrapper.m:11:9:‘rsa.h’ file not found

(1),万年老坑,只要你接入支付宝百分百要遇到的问题,所以习以为常吧

(2),在Build setting中搜索search,找到Header Search Paths,添加$(PROJECT_DIR)/openssl和$(PROJECT_DIR) 如下图:

(3),重要 问题说三遍,这是网络找到的到答案后继续有同样的坑,自己的解决方案,

HeaderSearch Paths   $(PROJECT_DIR)/ali中输入这个

FrameworkSearch Paths  和 Library Search Paths 继续是$(inherited)  和  $(PROJECT_DIR)/ali

‘rsa.h’file not found  的解决方案

(4),由于后期多项目的接入,让我知道一个算是万能方法吧,就是始终保持HeaderSearch Paths 和 Library Search Paths 都能找到你导入的openssl的正确路径即可,已尝试多遍,是能解决以上问题(求黑)


32、微信支付错误:拉起微信支付后,在微信支付注册在友盟之后仍然跳转到微信还是一个确定按钮,点击确定按钮回到自己的应用

第一步获取prepayId,这一步往往都不会有什么错误,根着官方文档都不会出现什么问题,坑在第二步发送跳转

1、注意一下 nonceStr 需要是第一步里生成的 nonceStr,而不是重新生成。

2、sign 需要重新针对5个字段进行签名:partnerIdprepayId package nonceStr timeStamp  不需要传入appid或者openid

需要传入appid

3、package = @"Sign=WXPay" 注意服务器传来的"="会不会被转义成 %3D

4、sign的确需要大写。

 

33、如果你app同时使用了友盟分享(含微信分享)和微信支付。如果你没有处理好这个两个SDK register的顺序,那就很不幸,也会出现这种情况。

(如何出现这种情况,请看我的测试步骤:1、杀掉微信进程、2、删除自己开发的app、3、重新同步自己的app到设备,点击微信支付)

两者register的顺序:如果是先调用微信registerApp、然后调用友盟的 [UMSocialWechatHandler setWXAppId:WXAppID appSecret:[NSStringstringWithBundleNameForKey:@"WXAppSecret"] url:url] ,然后按照我测试的步骤,应该就会出现。

解决办法:改变两者的register步骤。先调用友盟,然后调用微信。

 

34、支付宝支付:Redefinition of 'RSA' as differentkind of symbol 多为sdk集成时产生的坑,因为我们公司在集成支付宝之前,有用过RSA加密,导致重名问题

由于支付宝中的openssl中的rsa.h文件与RSA加密有重名冲突。改掉公司自己之前导入RSA的命名。

 

35、支付宝支付:RSA密钥生成命令步骤如下:

(1)生成RSA私钥
(2)openssl>genrsa -out rsa_private_key.pem 1024
生成RSA公钥
(3)openssl>rsa -in rsa_private_key.pem -pubout -out rsa_public_key.pem
将RSA私钥转换成PKCS8格式
(4)openssl>pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM-nocrypt
注意:“>”符号后面的才是需要输入的命令。

(5)把公钥上传到支付宝,然后把pkcs8-topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt 这条命令产生的私钥用在下面设置中就好

 

36、iOS集成支付宝,IOS9.0及以上版本的报错:error: "This app is not allowed to query for scheme alipay”?

近期苹果公司iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。

 

37、在调试移动支付接口,客户端的时候报错,提示为:failurecalling remote service,请问是什么原因?

主要原因是私钥没有转pkcs8导致的;

其次是http不要放在UI里面,放在UI里面http报错,导致支付包sendorder的时候出现异常,导致failure calling remote service 这个错误的发生。最简单的解决办法:<uses-sdkandroid:minSdkVersion="5"></uses-sdk>。


38、在调试移动支付接口的时候报ALI69错误?

报错含义就是没权限,请检查:

1、检查收款账号是否是签约账号;

2、检查是否签约了移动支付产品。

40、SVN,’.’ is not a working copy.Can’t open file‘.svn/entries’: 系统找不到指定的路径。

原因是输入的访问路径不正确,如svn://192.168.6.200/如果最后少写了“/”,就会出现这种错误提示。

 

41、“Commit failed。……You have toupdate yourworking copyfirst” 提交失败,需要首先执行更新操作。

多人同时修改同一文件,在提交前其他人已经抢先提交到SVN服务器中,导致该错误;解决方法:对工作复本中的文件进行更新即可。

 

42、更新时提示文件发生冲突:“One ormore files are not a conflicted state。”

多人同时修改同一文件的同一部分,SVN无法自动进行合并,会导致该错误;对工作复本中的文件和服务器的文件进行比较,手工合并即可。

 

43、“Commit failed;File alreadyexists”提交失败,文件**已存在。


版本管理系统在改变你的计算机上的工作副本时,是非常的小心的。在做任何事情之前,它都尽可能把您的意图写到你的计算机上的日志文件中去。但如果偶然地操作中断了(例如:突然停电了,您的计算机死机了),那么日志文件记录就可能同您最后的工作状态不一致。一种建议解决途径:先把要提交的东西拷出来放到其它目录,再更新本地文件,然后把拷出来的文件重新放回去提交。

 

44、Working copy’**’locked.Pleaseexecute the ’Clean up’command.
 version客户端在提交内容之前会在本地的工作拷贝写日志,防止其他客户端再次作操作,如果这个提交过程中发生错误,就会存在未清理的日志,解决这个问题之需要执行“清理”操作,整理你的计算机上的工作副本,清理错误的日志记录,使您可以继续操作。

 

45、执行cleanup时,出现错误“version reported an error while doing a cleanup!” '**'is not a working copy directory ”



遇到这种情况,先删除隐藏文件夹.svn中的tmp下面的临时文件,再执行cleanup。

46、使用友盟,点击微信分享,弹框说微信未安装(实际已经安装了)

 A、在info.plist中加入安全域名白名单(右键info.plist用sourcecode打开)

 B、在info.plist的NSAppTransportSecurity下新增NSAllowsArbitraryLoads并设置为YES,指定所有HTTP连接都可正常请求

 

47、应用跳转(SSO等)

 如果你的应用使用了如SSO授权登录或跳转分享功能,在iOS9下就需要增加一个可跳转的白名单,指定对应跳转App的URL Scheme,

否则将在第三方平台判断是否跳转时用到的canOpenURL时返回NO,进而只进行webview授权或授权/分享失败。

同样在info.plist增加

<key>LSApplicationQueriesSchemes</key>
<array>
<!-- 微信 URL Scheme 白名单-->
<string>wechat</string>
<string>weixin</string>
</array>

 

48、百度地图,如果您只在Xib文件中使用了BMKMapView,没有在代码中使用BMKMapView,编译器在链接时不会链接对应符号。

需要在工程属性中显式设定:在Xcode的Project -> Edit Active Target ->Build Setting -> Other Linker Flags中添加-ObjC

 

49、百度地图,由于iOS9改用更安全的https,为了能够在iOS9中正常使用地图SDK,请在"Info.plist"中进行如下配置,否则影响SDK的使用。

  

<key>NSAppTransportSecurity</key>
    <dict>
       <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>

 

50、如果在iOS9中使用了调起百度地图客户端功能,必须在"Info.plist"中进行如下配置,否则不能调起百度地图客户端。

    <

key>LSApplicationQueriesSchemes</key>
    <array>
       <string>baidumap</string>
    </array>

51、自iOS SDKv2.5.0起,为了对iOS8的定位能力做兼容,做了相应的修改,开发者在使用过程中注意事项如下:

需要在info.plist里添加(以下二选一,两个都添加默认使用NSLocationWhenInUseUsageDescription):

NSLocationWhenInUseUsageDescription  ,允许在前台使用时获取GPS的描述
NSLocationAlwaysUsageDescription  ,允许永久使用GPS的描述

 

52、在使用Xcode6进行SDK开发过程中,需要在info.plist中添加:Bundle display name ,且其值不能为空(Xcode6新建的项目没有此配置,若没有会造成manager start failed)

 

53、确认项目中添加mapapi.bundle文件以及添加方法正确,不能删除或随意更改其中files文件夹下的内容.

注:mapapi.bundle中存储了定位、默认大头针标注View及路线关键点的资源图片,还存储了矢量地图绘制必需的资源文件。如果您不需要使用内置的图片显示功能,则可以删除bundle文件中的image文件夹。您也可以根据具体需求任意替换或删除该bundle中image文件夹的图片文件。添加方式:将mapapi.bundle拷贝到您的工程目录,直接将该bundle文件托拽至Xcode工程左侧的Groups&Files中即可。若您需要替换定位、指南针的图标,请保留原文件名称,否则不显示替换的新图片,默认大头针标注与路线关键点的新图片名称可自定义名称。

 

54、app在前后台切换时,需要使用下面的代码停止地图的渲染和openGL的绘制(V2.10.0后不需要再调用):

- (void)applicationWillResignActive:(UIApplication *)application{
    [BMKMapViewwillBackGround];//当应用即将后台时调用,停止一切调用opengl相关的操作
}
- (void)applicationDidBecomeActive:(UIApplication *)application{
    [BMKMapViewdidForeGround];//当应用恢复前台状态时调用,回复地图的渲染和opengl相关的操作
}