San Diego State University -- This page last updated March 8, 1995
Async I/O using select()
Basic rules:
Both input and output should be buffered.
Input needs to be split up into lines or records.
Output needs to be converted into a byte stream.
Return values for read() and write()
read():
write():
Error codes that need special handling:
For input:
For output:
setup; for ever { clear readfds and writefds; for each client { set bits in readfds and writefds; } set readfds bit for passive socket; result = select(...) for each client { if bits set in readfds or writefs deal with it; } if bit for passive socket is set, accept new connection; }
Two interfaces to the buffer:
Select interface caused the buffer to call read() and fill its internal holding area.
Once a complete record is available, it needs to let the protocol engine know.
The protocol engine will then request records.
void DataAvailable(int fd)Tells the buffer that it needs to call read() on the given filedescriptor.
int HasRecord()Is TRUE if at least one complete record is available.
Record GetRecord()Returns one record.
FlushBuffer(int fd)Tells the buffer that it is allowed to write data to the file descriptor.
WriteToClient(Record someRecord)Writes a complete record into the buffer.
int IsEmpty()Returns TRUE if the output buffer is empty.
Use a state machine to process your protocol
You are NOT required to be fluent in Finite Automata theory to use state machines!
Sample protocol: SPOP (Simple POP)
Commands allowed:
Two general methods:
Table:
1 2 3 4 5 USER 2 5 5 4 5 PASS 5 3 5 4 5 LIST 5 5 3 4 5 QUIT 4 4 4 4 4
switch (state) case 1: switch (input) case USER: state = 2; case QUIT: state = 4; default: state = 5; case 2: switch (input) case PASS: state = 3; case QUIT: state = 4; default: state = 5; case 3: switch (input) case LIST: state = 3; case QUIT: state = 4; default: state = 5; case 4: state = 4; case 5: switch (input) case QUIT: state = 4; default: state = 5;
A state machine would do not good without some actions.
The default action for any given state and input is to go to the state specified by the machine.
Actions can determine which state to pick next:
In POP the username and password need to be verified:
typedef struct { char *command; int (*function)(); int valid_in; int win; int lose; } vector; vector switchtable[] = { {"user", user, AUTH1, AUTH2, AUTH1}, {"pass", pass, AUTH2, TRANS, AUTH}, . . . {NULL, NULL, 0, 0, 0} };