分类: LINUX
2005-03-12 13:37:57
原来奇怪socket在connect失败时为什么不释放(见commer一书7.7的例子),现在终于明白了。
另外,即使不close file,进程结束产生的结果和close file几乎没有区别(读linux源代码的印象)
fclose似乎必须使用,因为还有用户态缓冲。
查了一下
国外的课程质量高啊
(1). fopen() uses a string for Mode, where "r" stands for READ, "w" for
WRITE. It returns a pointer to a FILE structure. The FILE structure
contains a buffer, whose size usually matches that of BLKSIZE. In
addition, it also has pointers, counters and status variables for
manipulating the buffer.
fopen() first allocates and initialize a FILE structure in (heap area
of) the UserImage. It then issues an open() syscall for the file. If
the open() syscall succeeds, it records the returned fd in the FILE
structure, and returns a pointer to the FILE structure. Otherwise, it
frees the FILE structure and returns a NULL pointer.
It is important to note that the FILE structure, which is allocated/
freed dynamically, is in the process' UserImage. This means that calls
to Library I/O functions are ordinary function calls, not syscalls.
3. Algorithms of fread(), fwrite() and fclose()
3-1. The algorithm of fread() is as follows:
(1). On the first call to fread(), the FILE structure's buffer is empty.
fread() uses the saved file descriptor fd to issue a
n = read(fd, fbuffer, BLKSIZE);
syscall to fill the local fbuffer. Then, it initializes fbuffer's
pointers, counters and status variables to indicate that there is a
block full of data in the local buffer.
It then tries to satisfy the fread() call from the local buffer by
copying data to the program's buffer area. If the local buffer does
not have enough data, it issues additional read() syscalls to fill
the local buffer, until the needed number of bytes is satisfied (or
end of file is reached). After copying data to the program's buffer
area, it updates the local buffer's pointers, counters, etc. getting
ready for next fread() request. It then returns the acutal number of
objects read to the calling place.
(2). On each subsequent call to fread(), it tries to satisfy the call from
the FILE structure's local buffer. It issues a read() syscall to
refill the local buffer whenever the buffer becomes empty.
Thus, fopen() accepts calls from user program on one side and issues
read() syscalls to the Kenrel on the other. Except for the read()
syscalls, all processing of fread() are performed in the User Mode.
It enters the Kernel mode only when needed and it does so in a way
that matches the Kernel's behavior for best efficiency. It provides
automatic buffering mechanism so that user programs do not have to
worry about such detailed operations.
3-2 fwrite():
The algorithm of fwrite() is similar to that of fread() except for the
data movement direction. Initially the FILE structure's local buffer is
empty. On each call to fwrite(), it writes data to the local buffer, and
adjust the buffer's pointers, counters and status variable to keep track
of the number of bytes in the buffer. If the buffer becomes full, it
issues a write() syscall to write the entire buffer to Kernel
3-3. USE syscalls OR Library Functions?
Based on the above discussion, we can now answer the question of whether
to use syscalls or Libray functions to do file I/O?
fread() relies on read() to copy data from Kernel to the local buffer,
from which it copies data to the program's buf area. In contrast, read()
copies data from Kernel directly to the program's buf area. Thus, for
read/write data in units of BLKSIZEs, read() is inherently more efficient
than fread() because it only needs one copying operation instead of two.
Therefore, in the above C programs, the one that uses syscalls is actually
more efficient than the other that uses Library I/O functions. However,
if the read/write is not in units of BLKSIZE, fread() and fwrite() may be
far more efficient. For example, if we insists on R/W one byte at a time,
fread() and fwrite() would be far better because they enter Kernel Mode
only to fill or flush the local buffer, not on every byte. Here, we have
implicitly assumed that entering Kernel mode is more expensive than
staying in User mode. This is indeed true.
3-4. Algorithm of fclose():
fclose() first flushes the local buffer if the file was opened for WRITE.
Then it issues a close() syscall to close the file descriptor. Finally
it frees the FILE structure and resets the FILE pointer to NULL.
3-5. Other Modes for fopen(): 重要
The Mode parameter in fopen() may be specified as
"r", "w", "a" : for READ, WRITE, APPEND, or with a +, which means to
create the file if it does not exist.
"r+" : for R/W, without truncating the file.
"w+" : for R/W, but truncate the file first.
"a+" : for R/W by appending.
However, when a file is fopened for both R/W, there may be restrictions on
the use of mixed fread() and fwrite() calls. The specification requires
that at least one fseek() or ftell() be used between every pair of fread()
and fwrite().
Example: This program yields different results when run under HP Unix and
Linux.
#include
FILE fp; char buf[1024];
main()
{
fp = fopen("t.c", "r+"); /* for both R/W */
fread(buf, 1, 20, fp); /* read 20 bytes */
fwrite(buf,1, 20, fp); /* write to the same file */
}
Linux gives the right result, which modifies the bytes from 20 to 39. But
HP Unix appends 40 bytes to the end of the original file.
The difference stems from the non-uniform treatment of R/W pointers in the
two systems. Recall that fread()/fwrite() issue read()/write() syscalls
to fill/flush the local buffer. While read()/write() use the R/W pointer
in the file's OFTE, fread()/fwrite() use the local buffer's R/W pointer in
the FILE structure. Without a fseek() to synchronize these two pointers,
the results depend on how are they used in the implementations. In order
avoid any inconsistencies, follow the man pages. For the example program,
the results become idnetical (and correct) if you insert a line
fseek(fp, (long)20, 0);
between the fread() and fwrite().