0

I'm writing a toy MUD client which uses a TCP/IP socket to make a connection to a telnet server.

As a common feature in MUD clients, I should be able to run a bunch of regular expressions on the responses from the server and do stuff when they are triggered.

Now the problem arises when the response is long and received in 2 or more TCP/IP packets, and therefore the regular expressions wont match when I run them on the responses, as they are not complete yet (the first or second part wont match alone).

So the question is how do I know the server is done sending a packet of data before running my regular expressions on them.

Farzad Bekran
  • 489
  • 1
  • 6
  • 13

3 Answers3

3

The short answer is: you don't

TCP/IP is a serial protocol, that has no notion of packets.

If your application layer protocol uses packets (most do), then you have two options:

  • use a transport layer that supports packets natively (UDP, SCTP,...)

  • add packetizing information to your data stream

The simplest way to add packetizing info, is by adding delimiter characters (usually \n); obviously you cannot use the delimiter in the payload then, as it is already reserved for other purposes.

If you need to be able to transmit any character in the payload (so you cannot reserve a delimiter), use something like SLIP on top of TCP/IP

umläute
  • 28,885
  • 9
  • 68
  • 122
  • I know it "has no notion of packets". but i need to somehow determine if there is no more data coming until i send the next command. sometimes the data ends with a '\n' and sometimes it ends with some other character so the server clearly does not care about a delimiter. – Farzad Bekran Mar 30 '15 at 11:02
  • I now take it you didn't write the server and may not change it. In that case you'll have to figure it out on a case by case basis. – gia Mar 30 '15 at 11:04
  • yes, so whats the best way to do it? since the server could be different in any case. i was thinking about waiting for like 200ms before acting on the data... – Farzad Bekran Mar 30 '15 at 11:08
2

you can keep a stack, add the packets to it, keep testing until you get a full response

If the MUD is to be played (almost) exclusively by the client (not telnet itself), you can add delimiters, again have the stack, but don't test blindly, test when you get a delimiter.

If there is a command you can send that has no gameplay effect but has a constant reply from the server (eg a ping) you could use it as a delimiter of sorts.

gia
  • 757
  • 5
  • 19
  • the question is "what is the delimiter?" and what do you mean by "played (almost) exclusively by the client (not telnet itself)"? – Farzad Bekran Mar 30 '15 at 10:51
  • delimiter is whatever you want it to be, right now im delimiting my sentences with commas, and my words with any non-letter, you just have to find or define a delimiter that consistently separates your messages from each other. If the player will connect through telnet itself and not your client and for example your delimiter is %%%, they will see those %%% and you may not want that. – gia Mar 30 '15 at 11:02
  • little misunderstanding here: the server side is not under my control, im just writing a general mud client. so i cant make the server add delimiters to the end of the data. – Farzad Bekran Mar 30 '15 at 11:06
  • use the first paragraph of my response then, mix it with the second when possible. Keep the stack, and whenever you feel the string is complete process it (eg, you detected a full command word, or 30 seconds have passed with no more packets > I'd logout in that case though). If certain commands are delimited, take advantage in those cases. – gia Mar 30 '15 at 11:11
  • thats pretty much what i was thinking, but the problem is that it puts unnecessary delay between receiving data and showing it to user. – Farzad Bekran Mar 30 '15 at 11:19
  • If you know the game by heart you can know at what state of the game you are at, then you can predict the nature of the response from the first bytes received, maybe even from your own command :) That's a bit hardcore of a solution though. – gia Mar 30 '15 at 11:26
  • wait x time then, play with numbers until happy, have failure cases when you receive packets you weren't expecting – gia Mar 30 '15 at 11:34
2

You may be over thinking it. Nearly all muds delimit lines with LF, i.e. \n (some oddball servers will use CRLF, \r\n, or even \n\r). So buffer your input and scan for the delimiter \n. When you find one, move the line out of the input buffer and then run your regexps.

A special case is the telnet command IAC GA, which some muds use to denote prompts. Read the Telnet RFC for more details, https://www.rfc-editor.org/rfc/rfc854 , and do some research on mud-specific issues, for example http://cryosphere.net/mud-protocol.html .

Practically speaking, with muds you will never have a problem with waiting for a long line. If there's a lot of lag between mud and client there's not a whole lot you can do about that.

Community
  • 1
  • 1
georgek
  • 877
  • 6
  • 11
  • the problem with this solution would be that every line ends with line feed, for example you send 'map' and receive a ASCII map of your surroundings. And I have seen prompts that just end with a '>' and nothing more. – Farzad Bekran Mar 30 '15 at 15:54
  • Unstructured data (e.g. 'map', a 'help' command) is a problem for muds in general, and you're not going to solve it at the level of the problem you're asking about unless you have control of the server and client. Prompts that end with '>' may have a `LF` or an `IAC GA` after them. You are scanning for IAC aren't you? – georgek Mar 30 '15 at 23:55
  • I do scan for IAC, unfortunately muds play by their own rules. I'm using aardwolf as a sample mud right now, and it ends the prompt with a '> ' nothing more. I can change the prompt format with some commands in the mud, but as a general rule, its not a good idea for a generic mud client to rely on a predefined format. and the well established clients that I use have no problem with detecting any kind of prompt without a fuss. – Farzad Bekran Mar 31 '15 at 13:07