0

I am making an iPhone app that connects to a server (whose protocol I have no control over) and gets a stream of textual data, where each line ends with a CRLF, and the amount of lines, as well as their exact length, is undetermined. I'm calling GCDAsyncSocket's readDataToData:withTimeout:tag: recursively to get the data, line by line.

I was previously reading from an NSStream synchronously, so I would know when a read was complete by calling hasBytesAvailable. I recently switched to GCDAsyncSocket, and now I'd also like to know when the stream has read all available data, so I can save/process data, refresh a table, remove an overlay, etc.

I tried using the a similar technique as before, calling the following in my socket:didReadData:withTag: delegate method, before the next read was requested:

[asyncSocket performBlock:^{
    if (CFReadStreamHasBytesAvailable([sock readStream]))
        NSLog(@"CFReadStreamHasBytesAvailable: yes");
    else
        NSLog(@"CFReadStreamHasBytesAvailable: no");
}];

But the result was always YES.

I also tried calling the method progressOfReadReturningTag:bytesDone:total: after the read request was sent, and it seems to always return 1 when the reads are finished and nil otherwise, but I'm not sure if it's reliable to use the method in that way.

Perhaps someone can tell me if progressOfReadReturningTag:... is actually reliable in this case, or, if not, point me in another direction to solve this.

newenglander
  • 2,019
  • 24
  • 55
  • You need to define "End of Stream" on the protocol layer. For example, you may to define a `EOS` character (possibly the `EOS` equals 0x00). If the sender detects an "end of data" it will send the `EOS` character and the receiver detects this. Notice, that an `EOS` does not work in a binary stream. In a binary stream, the sender may close the stream in order to indicate EOS, or - again - it is defined on the "protocol" layer, which requires to send "structured" data, where an "end of message" can be signaled. – CouchDeveloper Nov 11 '13 at 13:26
  • @CouchDeveloper: thanks for the tip, unfortunately it's not my server, so I can't change the protocol. Hopefully there's another way to solve this. – newenglander Nov 11 '13 at 13:55
  • If your data stream has a structure, you might possibly detect an "End of Message". For example, if you transfer JSON, it can be detected by the parser when the JSON is finished: `["one" "two", false]` – CouchDeveloper Nov 11 '13 at 14:02
  • @CouchDeveloper: Thanks again, but unfortunately no such structure, each line is separate, and has no indication of what's next or what came before. It's very basic in this respect. – newenglander Nov 11 '13 at 14:11
  • 1
    Well, then your data is "infinite" and you never get an EOS :) You can alleviate this "issue" by starting actions when you got enough information, for example after receiving a whole "string" which is terminated by a CRLF. (Think of a "chat system") – CouchDeveloper Nov 11 '13 at 14:14
  • @CouchDeveloper: Yeah, exactly, and that's just what I'm doing now, but the UI is suffering. Before I was processing at the end of data, and it was much smoother. You think there's no reliable way to know I'm at the end? `hasBytesAvailable` was in this regard very reliable before my switch to `GCDAsyncSocket`. – newenglander Nov 11 '13 at 14:19
  • You can process the reading in a background process. For example, the "reader" reads complete lines, and then *on the main thread* adds this line to an NSArray which is the data source of a table view. The table view displays these line and requires access to the NSArray on the main thread. If your problem is something of that sort, please rephrase your question, and possibly create a new one. – CouchDeveloper Nov 11 '13 at 14:23
  • @CouchDeveloper Tried this already too, didn't help much. Hopefully there's a good alternative. Otherwise I'll take a risk and try using `progressOfReadReturningTag...` as mentioned in my question. – newenglander Nov 11 '13 at 14:29

0 Answers0