0

I am writing a bulletin board system (BBS) reader on ios. I use GCDAsyncSocket library to handle packets sending and receiving. The issue that I have is the server always splits the data to send into multiple packets. I can see that happens by printing out the receiving string in didReceiveData() function.

From the GCDAsyncSocket readme, I understand TCP is a stream. I also know there are some end of stream mechanisms, such as double CR LFs at the end. I have used WireShark to parse the packets, but there is no sign of some sort of pattern in the last data packet. The site is not owned by me, so I couldn't make it to send certain bytes. There must be some way to detect the last packet, otherwise how BBS clients handle displaying data?

user3739779
  • 183
  • 2
  • 6
  • What is the "server" your "reader" is reading from? – Geremy Jun 18 '14 at 23:32
  • It's an old BBS system to which clients use telnet to connect. It sends back information with ASCII escape code so you'll have colorful text and background on the console. – user3739779 Jun 19 '14 at 04:44
  • "*.... how BBS clients handle displaying data?*" They just display all they get. – alk Jun 19 '14 at 07:26
  • "*There must be some way to detect the last packet ...*" No, not on TCP stream level, as a stream is endless be definition, as long as the conection lasts. On application level there might be. In this special case of a BBS receiving the input prompt might be an indicator that all data had been sent. – alk Jun 19 '14 at 07:30
  • @user3739779 what language is it written in? – Geremy Jun 19 '14 at 17:17
  • @Geremy I believe the server was written in C, but I am not entirely sure. – user3739779 Jun 19 '14 at 17:56
  • If you had access to the source code, I could suggest some easier ways to exchange data with it, rather than a raw socket client implementation. – Geremy Jun 19 '14 at 18:23

1 Answers1

0

Double CR LFs are not end of stream. That is just part of the details of HTTP protocol, for example, but has nothing to do with closing the stream. HTTP 1.1 allows me to send multiple responses on a single stream, with double CR LF after HTTP header, without end of stream.

The TCP socket stream will return 0 on a read when it is closed from the other end, blocking or non-blocking.

So assuming the server will close the socket when it is done sending to you, you can loop and perform a blocking read and if returns > 0, process the data, then read again. if < 0, process the error code (could be fatal or not), and if == 0, socket is closed from the other side, don't read again.

For non-blocking sockets, you can use select() or some other API to detect when the stream becomes ready to read. I'm not familiar with the specific lib you are using but if it is a POSIX / Berkeley sockets API, it will work that way.

In either case, you should build a buffer of input, concatenating the results of each read until you are ready to process. As you've found, you can't assume that a single read will return a complete application level packet. But as to your question, unless the server wants you to close the socket, you should wait for read to return 0.

codenheim
  • 20,467
  • 1
  • 59
  • 80
  • Thanks! I checked GCDAsyncSocket source code. It does what you described, using the return value of read() to determine whether there's any more data. Unfortunately all the related variables are private. I am hacking the class and trying to find something that is useful to me. – user3739779 Jun 19 '14 at 18:01