使用GCDAsyncSocket同时会接收到多个包的问题

问题

在与服务端 TCP 通讯的时候, 由于业务需要, 在正常类似一问一答的情况外, 还有一种服务端主动发送数据到客户端的额情况, 这样就会遇到当客户端发送一个请求以后,本来应该接收到服务端的回复报文, 但有可能会接收到另外服务端主动发送的报文, 而这时本来期望收到的回复报文就会接收不到.

解决

socket 的报文发送与 unix 的读写文件差不多, 服务端写数据到缓冲中, 客户端就已经收到了,上面的情况是只是取了一次,没有取到期望的报文,如果要解决这个问题, 只要接着取,直到取到需要的报文,应该就可以了

回到 GCDAsyncSocket ,几个重要的方法:

  1. readDataWithTimeout 获取缓冲中的数据,即接收数据
  2. readDataToData 以报文分隔符为界,读取数据
  3. func socket(socket : GCDAsyncSocket, didReadData data:NSData, withTag tag:Int) 这个方法是在readDataWithTimeout之后触发

我们要做的, 就是再次触发func socket(socket : GCDAsyncSocket, didReadData data:NSData, withTag tag:Int) 直到取到需要的报文,于是

class GCDAsynTcpSocketDelegate: NSObject, GCDAsyncSocketDelegate {
...
    // 发送数据
    func send(message: String) {
        let messageData = message.dataUsingEncoding(NSUTF8StringEncoding)
        if let socket = tcpSocket as GCDAsyncSocket! {
            socket.writeData(messageData, withTimeout: socketTimeOut, tag: 0)
            // 接收数据
            socket.readDataWithTimeout(socketTimeOut, tag: 0)
        }
    }

    // - (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag;
    func socket(socket : GCDAsyncSocket, didReadData data:NSData, withTag tag:Int) {
        if let data = NSString(data: data, encoding: NSUTF8StringEncoding) as NSString! {
            logger.debug("didReadData:\(data)")
            if data.length > 0 { 
                // 当取到不是期望的报文时再次读取
                while (!data.containsString("ReqSerialNo")) {
                    socket.readDataToData(GCDAsyncSocket.CRLFData(), withTimeout: -1, tag: 0)
                    socket.readDataWithTimeout(socketTimeOut, tag: 0)
                    // 退出该方法,会再次进入                    
                    return
                }
                ......
            }
        }
    }
    ...
}
2015-07-17 10:3155