📄 streams.wvsgml
字号:
WVEXAMPLE(wvstreamex7.cc) ) ) WVCHAPTER(somesimplestreams, Some Simple Streams, Let's look at a few streams that are only slightly more complicated than WvStream itself: WvFile, WvFileWatcher, and WvPipe. WVSECT1(wvfile, WvFile - accessing Unix files, WvFile is the simplest WvStream-derivative around. All it does is open a Unix file for you given a filename, so you don't have to supply the fd yourself. WVEXAMPLE(wvfileex.cc) Need we say more? Oh, since Unix devices are just files, you can use them with WvFile just as easily. For example, if your modem is /dev/ttyS2, you can connect to it by creating a WvFile that refers to /dev/ttyS2. Of course, the <link linkend="wvmodem">WvModem</link> class is probably more useful for that particular job. ) WVSECT1(wvwatcher, WvFileWatcher - waiting for a file to change, WvFileWatcher is a bit more interesting than WvFile: it reads to the end of a file, and then if the file grows, select() returns true and you can read more data; if the file shrinks (which presumably means it was rewritten from scratch), it starts again at the top of the file. To think of it another way: WvFileWatcher makes select() make sense on regular files. Normally, select() is always true for a file, since all the data is always immediately available. (Note that this isn't true if your WvFile is connected to a Unix device; then select() makes sense already, and WvFileWatcher will just mess you up.) WvFileWatcher is very seldom used except as a WvStreams test, so we won't bother to give an example here. ) WVSECT1(wvpipe, WvPipe - talking to subtasks, WvPipe will certainly be very interesting to anyone who writes programs that need to spawn off sub-programs, and read and possibly write to that programs input and output. WvPipe makes this rediculously easy, by making the application call look exactly like any other stream. No more messy exec() calls, and best yet, no more blocking - if you just need to send a program off to do something, then you don't need to fork at all, you can just create a WvPipe stream which ignores any input, output, or error messages, and add it to your WvStreamList. If you do need to access input or output, you can easily just select() on this pipe, which will return true when the program has something interesting for you. Insert Example Here... ) WVSECT1(wvmodem, WvModem - baud rates and terminal modes, Not written yet. ) ) WVCHAPTER(logs, Dealing with Log Messages, WVSECT1(wvlog, WvLog - printing log messages, x) WVSECT1(wvlogrcv, WvLogRcv - receiving and disposing of log messages, x) WVSECT1(wvlogbuffer, WvLogBuffer - saving log messages to a buffer, x) WVSECT1(wvsyslog, WvSyslog - sending log messages to syslog, x) ) WVCHAPTER(wvstreamlist, WvStreamList - dealing with multiple streams, WvStreamList is one of the most important parts of the WvStreams library. Almost every real WvStreams program (in contrast with all the preceding examples) involves at least one WvStreamList. We would have mentioned it much sooner, but we thought it would be nice to have a few different kinds of streams to play with before we started creating lots of them at a time. Fundamentally, what WvStreamList does is allow you to select() on more than one stream at a time. That way you can, for example, wait for multiple TCP connections to send you data, and wake up immediately as soon as any one of them is available. Without the magic of WvStreamList, there is no good way to wait for multiple streams simultaneously. There are, however, a couple of bad ways, which we will mention shortly just so you don't try them. WVSECT1(wvstreamlistbadidea, Don't do this, Don't try this: WVEXAMPLE(wvstreamlistex.cc) It will fail in three different ways depending on the value of X. If X==-1, each select() statement waits forever for data. That means in order to print a snorkle (which should appear once per second), you must first print a foo (which only happens once every three seconds). That's bad enough, but some streams might be almost completely idle, so you certainly can't get away with doing that. If X==0, we never wait at all. This will appear to work properly -- if you run the program, the snorkles and foos will show up at the right time. But unfortunately, your program will spin in the main loop, and take 100% of the CPU unnecessarily. We can compromise by making X==1000 instead. That way, each select() statement will give up after 1 second. Since the snorkles only happen once per second, that should be okay. However, it's not perfect -- the snorkles should appear _exactly_ one second apart, but you can't guarantee that using this technique. It'll be somewhere between zero and one seconds, depending on random luck. Besides, the whole point of this chapter is there's a better way, so don't write programs like the one above. ) WVSECT1(wvstreamlistgood, Do this instead, Here's a better way to choose between two lists, using WvStreamList. As you might have guessed, WvStreamList is a type of WvLinkList that contains WvStreams. It's also a stream itself, so (among other things) you can select() on a WvStreamList and include one WvStreamList inside another. But let's keep it simple for now: WVEXAMPLE(wvstreamlistex2.cc) A streamlist is always okay (isok() == true) because you can always add and remove streams from it. That's why our main loop is checking for "okayness" of the two main streams, rather of the list. But also notice the contents of the main loop. We select() on the list, and if it returns true, we then callback() the list. What's happening there? What happens is this. WvStreamList::select() will return true if the select() of any of its member streams would return true. (It doesn't actually _call_ the select() function of each of its member streams, but the idea is the same. That's why WvStreamList is magic.) When you run WvStreamList::callback(), it calls back all the member streams that would have returned true to a select() call. If you give select() a delay (in this case, infinity), it will wait until any one of the member streams is ready. This mechanism increases fairness between streams, in case you have a lot of high-bandwidth streams and you're having trouble keeping up. If more than one stream is ready, callback() will call each one sequentially before it returns. That way, no one stream will get priority over the others. ) WVSECT1(wvstreamlistfun, An Interesting Example, Now that we've introduced all the pieces, we can have our first interesting WvStream example by throwing several pieces together. Here's a program that prints messages every once in a while through a WvPipe and using timeouts, while you talk to your modem device via the console. WVEXAMPLE(wvstreamfunex.cc) ) ) WVCHAPTER(magicstreams, Some Magical Streams, WVSECT1(wvstreamclone, WvStreamClone - a stream within a stream, WvStreamclone is probably one of the coolest, and most confusing parts within the WvStream library. Almost everyone who has ever encountered this stream the first time has had to stop and go over it a few times before they can wrap their head around what is going on. Ok.. now that I've scared you... I'm going to tell you that it is really quite easy. Most of the time, when you are using a WvStreamClone, you will be doing something like the following: 1. Start a Stream on a TCP Connection 2. Change this Stream into something else (like an SSL Stream) 3. And then talk some sort of high level protocol (like HTTP) So you have one stream (a TCP Connection), that morphs into another stream TYPE (an SSL Stream), that then becomes another stream (talking HTTP). All the while, not changing the stream that was started and added to the original WvStreamList. Insert Example here...) WVSECT1(wvsplitstream, WvSplitStream - separating read and write streams, x) WVSECT1(wvloopback, WvLoopback - talking to yourself across fork(), x) ) WVCHAPTER(unusualstreams, Some Unusual Streams, WVSECT1(wvtimestream, WvTimeStream - timed events, x) WVSECT1(wvprotostream, WvProtoStream - a protocol state machine, x) ) )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -