Question

I have an assignment in which I have to implement a few network protocols. The assignment includes communication over ideal connections (that do not lose or corrupt data) and connections that do corrupt the data. I would like to make this as modular as possible, but I can't figure out how to do it (everything seems so intertwined). Here's a list of things I have to do:

  • Sliding window. This task assumes a perfect connection. However, I would like to abstract away this detail (implement the sliding window code such that handling the quality of the connection is some other module's responsibility).
  • Go-Back-N protocol for an imperfect connection. Here I would like to reuse code from the previous task that involved sliding windows.
  • Selective repeat. This sounds like it should replace the Go-Back-N module, while still working on top of the sliding window module.
  • Error detection. This one looks like it should be independent of whether I use sliding windows, Go-Back-N or selective repeat. Yet, I can't figure out how to separate error checking from message receiving.

Maybe I can implement a layered architecture (inspired by the OSI model), but I'm not sure how to do it. I need a nudge in the right direction.

How should these different modules interact with each other? Such that Go-Back-N or Selective Repeat function independently of whether I want to fill the data link (sliding window) or not, and such that error checking is done on top of all of this, transparently.

Edit: One other difficulty is that some protocols (Go-Back-N, Selective Repeat, Sliding Window) require state particular to that protocol and there's no nice way to implement stateful functions in C.

Était-ce utile?

La solution

Maybe you could work with chained functions?

Initially, you could have a struct connection with fields like void (*write)(struct connection *con, char *buf, size_t len, void *data);, void *write_data;, int (*get_write_queue_size)(struct connection *con, void *data) and void *get_write_queue_size_data. First, you would fill it with the functions for dealing with an ideal connection.

Then, for adding a sliding window, you would make a struct sliding_window_connection with all the fields from struct connection that you want to intercept. Then, you would move the old functions and data-pointers from the struct connection into the struct sliding_window_connection, replace the functions in the struct connection with the sliding window implementations and replace the data pointers in the struct connection with pointers to the struct sliding_window_connection. The new write could e.g. look somewhat like this:

void sliding_window_connection_write
      (struct connection *con, char *buf, size_t len, void *data) {
  struct sliding_window_connection *swcon = data;
  /* ... do magic for the sliding window ... */
  /* if we want the buffer to be sent now, call the lower layer like this: */
  swcon->write(con, buf, len, swcon->write_data);
}

For stacking go-back-n or selective repeat on top, you would then add the go-back-n or selective repeat functions the same way.

For reading, you would basically do the same – let the data bubble up through the layers and maybe manipulate or interpret it on the way.

To make this work better, you might want to add a function similar to write that can be used by a layer (e.g. go-back-n) to signal a lower layer (e.g. the sliding window) for purposes like "hey, please resend bytes m->n, thanks".

As error detection would have to happen on a higher level than these things, you would have to add it after the other things – the later you add something, the higher its layer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top