📄 24.htm
字号:
And an addition note from Andrew (andrew@erlenstar.demon.co.uk): <br>
Not quite to do with EPROTO from read(), but I found out once that on <br>
some STREAMS-based implementations, EPROTO could be returned by <br>
accept() if the incoming connection was reset before the accept <br>
completes. <br>
On some other implementations, accept seemed to be capable of blocking <br>
if this occured. This is important, since if select() said the <br>
listening socket was readable, then you would normally expect not to <br>
block in the accept() call. The fix is, of course, to set nonblocking <br>
mode on the listening socket if you are going to use select() on it. <br>
<br>
2.11. How can I force a socket to send the data in its buffer? <br>
From Richard Stevens (rstevens@noao.edu): <br>
You can't force it. Period. TCP makes up its own mind as to when it <br>
can send data. Now, normally when you call write() on a TCP socket, <br>
TCP will indeed send a segment, but there's no guarantee and no way to <br>
force this. There are lots of reasons why TCP will not send a <br>
segment: a closed window and the Nagle algorithm are two things to <br>
come immediately to mind. <br>
(Snipped suggestion from Andrew Gierth to use TCP_NODELAY) <br>
Setting this only disables one of the many tests, the Nagle algorithm. <br>
But if the original poster's problem is this, then setting this socket <br>
option will help. <br>
A quick glance at tcp_output() shows around 11 tests TCP has to make <br>
as to whether to send a segment or not. <br>
Now from Dr. Charles E. Campbell Jr. (cec@gryphon.gsfc.nasa.gov): <br>
As you've surmised, I've never had any problem with disabling Nagle's <br>
algorithm. Its basically a buffering method; there's a fixed overhead <br>
for all packets, no matter how small. Hence, Nagle's algorithm <br>
collects small packets together (no more than .2sec delay) and thereby <br>
reduces the amount of overhead bytes being transferred. This approach <br>
works well for rcp, for example: the .2 second delay isn't humanly <br>
noticeable, and multiple users have their small packets more <br>
efficiently transferred. Helps in university settings where most <br>
folks using the network are using standard tools such as rcp and ftp, <br>
and programs such as telnet may use it, too. <br>
However, Nagle's algorithm is pure havoc for real-time control and not <br>
much better for keystroke interactive applications (control-C, <br>
anyone?). It has seemed to me that the types of new programs using <br>
sockets that people write usually do have problems with small packet <br>
delays. One way to bypass Nagle's algorithm selectively is to use <br>
"out-of-band" messaging, but that is limited in its content and has <br>
other effects (such as a loss of sequentiality) (by the way, out-of- <br>
band is often used for that ctrl-C, too). <br>
More from Vic: <br>
So to sum it all up, if you are having trouble and need to flush the <br>
socket, setting the TCP_NODELAY option will usually solve the problem. <br>
If it doesn't, you will have to use out-of-band messaging, but <br>
according to Andrew, "out-of-band data has its own problems, and I <br>
don't think it works well as a solution to buffering delays (haven't <br>
tried it though). It is not 'expedited data' in the sense that exists <br>
in some other protocols; it is transmitted in-stream, but with a <br>
pointer to indicate where it is." <br>
I asked Andrew something to the effect of "What promises does TCP make <br>
about when it will get around to writing data to the network?" I <br>
thought his reply should be put under this question: <br>
Not many promises, but some. <br>
I'll try and quote chapter and verse on this: <br>
References: <br>
RFC 1122, "Requirements for Internet Hosts" (also STD 3) <br>
RFC 793, "Transmission Control Protocol" (also STD 7) <br>
1. The socket interface does not provide access to the TCP PUSH flag. <br>
2. RFC1122 says (4.2.2.2): <br>
A TCP MAY implement PUSH flags on SEND calls. If PUSH flags are <br>
not implemented, then the sending TCP: (1) must not buffer data <br>
indefinitely, and (2) MUST set the PSH bit in the last buffered <br>
segment (i.e., when there is no more queued data to be sent). <br>
3. RFC793 says (2.8): <br>
When a receiving TCP sees the PUSH flag, it must not wait for more <br>
data from the sending TCP before passing the data to the receiving <br>
process. <br>
[RFC1122 supports this statement.] <br>
4. Therefore, data passed to a write() call must be delivered to the <br>
peer within a finite time, unless prevented by protocol <br>
considerations. <br>
5. There are (according to a post from Stevens quoted in the FAQ <br>
[earlier in this answer - Vic]) about 11 tests made which could <br>
delay sending the data. But as I see it, there are only 2 that are <br>
significant, since things like retransmit backoff are a) not under <br>
the programmers control and b) must either resolve within a finite <br>
time or drop the connection. <br>
The first of the interesting cases is "window closed" (ie. there is <br>
no buffer space at the receiver; this can delay data indefinitely, but <br>
only if the receiving process is not actually reading the data that is <br>
available) <br>
Vic asks: <br>
OK, it makes sense that if the client isn't reading, the data isn't <br>
going to make it across the connection. I take it this causes the <br>
sender to block after the recieve queue is filled? <br>
The sender blocks when the socket send buffer is full, so buffers will <br>
be full at both ends. <br>
While the window is closed, the sending TCP sends window probe <br>
packets. This ensures that when the window finally does open again, <br>
the sending TCP detects the fact. [RFC1122, ss 4.2.2.17] <br>
The second interesting case is "Nagle algorithm" (small segments, e.g. <br>
keystrokes, are delayed to form larger segments if ACKs are expected <br>
from the peer; this is what is disabled with TCP_NODELAY) <br>
Vic Asks: <br>
Does this mean that my tcpclient sample should set TCP_NODELAY to <br>
ensure that the end-of-line code is indeed put out onto the network <br>
when sent? <br>
No. tcpclient.c is doing the right thing as it stands; trying to write <br>
as much data as possible in as few calls to write() as is feasible. <br>
Since the amount of data is likely to be small relative to the socket <br>
send buffer, then it is likely (since the connection is idle at that <br>
point) that the entire request will require only one call to write(), <br>
and that the TCP layer will immediately dispatch the request as a <br>
single segment (with the PSH flag, see point 2.2 above). <br>
The Nagle algorithm only has an effect when a second write() call is <br>
made while data is still unacknowledged. In the normal case, this data <br>
will be left buffered until either: a) there is no unacknowledged <br>
data; or b) enough data is available to dispatch a full-sized segment. <br>
The delay cannot be indefinite, since condition (a) must become true <br>
within the retransmit timeout or the connection dies. <br>
Since this delay has negative consequences for certain applications, <br>
generally those where a stream of small requests are being sent <br>
without response, e.g. mouse movements, the standards specify that an <br>
option must exist to disable it. [RFC1122, ss 4.2.3.4] <br>
Additional note: RFC1122 also says: <br>
[DISCUSSION]: <br>
When the PUSH flag is not implemented on SEND calls, i.e., when <br>
the application/TCP interface uses a pure streaming model, <br>
responsibility for aggregating any tiny data fragments to form <br>
reasonable sized segments is partially borne by the application <br>
layer. <br>
So programs should avoid calls to write() with small data lengths <br>
(small relative to the MSS, that is); it's better to build up a <br>
request in a buffer and then do one call to sock_write() or <br>
equivalent. <br>
The other possible sources of delay in the TCP are not really <br>
controllable by the program, but they can only delay the data <br>
temporarily. <br>
Vic asks: <br>
By temporarily, you mean that the data will go as soon as it can, and <br>
I won't get stuck in a position where one side is waiting on a <br>
response, and the other side hasn't recieved the request? (Or at <br>
least I won't get stuck forever) <br>
You can only deadlock if you somehow manage to fill up all the buffers <br>
in both directions... not easy. <br>
If it is possible to do this, (can't think of a good example though), <br>
the solution is to use nonblocking mode, especially for writes. Then <br>
you can buffer excess data in the program as necessary. <br>
<br>
2.12. Where can a get a library for programming sockets? <br>
There is the Simple Sockets Library by Charles E. Campbell, Jr. PhD. <br>
and Terry McRoberts. The file is called ssl.tar.gz, and you can <br>
download it from this faq's home page. For c++ there is the Socket++ <br>
library which is on ftp://ftp.virginia.edu/pub/socket++-1.10.tar.gz. <br>
There is also C++ Wrappers. The file is called <br>
ftp://ftp.huji.ac.il/pub/languages/C++/C++_wrappers.tar.gz. Thanks to <br>
Bill McKinnon for tracking it down for me! From <br>
http://www.cs.wustl.edu/~schmidt you should be able to find the ACE <br>
toolkit. PING Software Group has some libraries that include a <br>
sockets interface among other things. You can find them at <br>
http://love.geology.yale.edu/~markl/ping. <br>
I don't have any experience with any of these libraries, so I can't <br>
recomend one over the other. <br>
<br>
2.13. How come select says there is data, but read returns zero? <br>
The data that causes select to return is the EOF because the other <br>
side has closed the connection. This causes read to return zero. For <br>
more information see ``2.1 How can I tell when a socket is closed on <br>
the other end?'' <br>
<br>
2.14. Whats the difference between select() and poll()? <br>
From Richard Stevens (rstevens@noao.edu): <br>
The basic difference is that select()'s fd_set is a bit mask and <br>
therefore has some fixed size. It would be possible for the kernel to <br>
not limit this size when the kernel is compiled, allowing the <br>
application to define FD_SETSIZE to whatever it wants (as the comments <br>
in the system header imply today) but it takes more work. 4.4BSD's <br>
kernel and the Solaris library function both have this limit. But I <br>
see that BSD/OS 2.1 has now been coded to avoid this limit, so it's <br>
doable, just a small matter of programming. :-) Someone should file a <br>
Solaris bug report on this, and see if it ever gets fixed. <br>
With poll(), however, the user must allocate an array of pollfd <br>
structures, and pass the number of entries in this array, so there's <br>
no fundamental limit. As Casper notes, fewer systems have poll() than <br>
select, so the latter is more portable. Also, with original <br>
implementations (SVR3) you could not set the descriptor to -1 to tell <br>
the kernel to ignore an entry in the pollfd structure, which made it <br>
hard to remove entries from the array; SVR4 gets around this. <br>
Personally, I always use select() and rarely poll(), because I port my <br>
code to BSD environments too. Someone could write an implementation <br>
of poll() that uses select(), for these environments, but I've never <br>
seen one. Both select() and poll() are being standardized by POSIX <br>
1003.1g. <br>
<br>
2.15. How do I send [this] over a socket? <br>
Anything other than single bytes of data will probably get mangled <br>
unless you take care. For integer values you can use htons() and <br>
friends, and strings are really just a bunch of single bytes, so those <br>
should be OK. Be careful not to send a pointer to a string though, <br>
since the pointer will be meaningless on another machine. If you need <br>
to send a struct, you should write sendthisstruct() and <br>
readthisstruct() functions for it that do all the work of taking the <br>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -