`
zg049zg
  • 浏览: 13948 次
最近访客 更多访客>>
社区版块
存档分类
最新评论

第五章: 基本I/O

 
阅读更多

第五章: 基本I/O
2011年04月21日
  5.1  基本输入输出
  
一般来说,Unix信奉简单设计的哲理。"一切都是文件"是个很强大的特征--这就意味着你所编辑的文本文件具有和调制解调器、打印机网卡相同的编程接口,就像编辑文本文件一样,你应该能够对它们(被编辑文件)执行基本的读、写操作等等。尽管这个想法现行的实现不完美,BSD Unix实际上做到非常接近了,这也正是BSD又一个强大的地方--简洁而优雅。有些不是真实的文件而是设备,它们的入口在/dev目录下,有些设备只能用于特殊的操作,如块的读、写,一个极端的例子是以太网设备,甚至它(以太网设备)在FreeBSD 5之前在/dev下面没有入口。
  操作系统看待每件事都像文件,一个好的示范是Plan 9,Plan 9用文件实现一切,甚至以太网和网络协议;更详细的信息可以参考Plan 9的主页http://www.cs.bell-labs.com/plan9dist/
  一般来说,文件是计算机上数据最基本、最初级的表现形式,本质上是数据一位一位的线性序列。当用exec命令执行编译过的程序时,系统将把二进制文件读入内存,代码将在分配到内存地址空间后被执行,程序被定位在什么位置跟exec命令有关,它可以在软磁盘,硬盘,光驱,甚至是加载的另一半还分布在世界其他角落的网络文件系统上;跟基于网络链路发送数据一样,内容被顺序地一位一位地读入。当一个程序发送数据的时候,数据本身是一位一位的线性序列,有些时候叫做“流”,程序不关心它是否基于网络链路发送数据,它仅仅写数据;这两种最基本的操作,读跟写,是计算鸡用到的最多的。
  本章将涉及最基本的I/O子系统跟进程资源。
  5.2  基本输入输出
  UNIX进程打开文件的时候,会保存文件描述符的参考值,该值是一个整数,不论何时在UNIX系统上创建一个进程,都会给它3个文件描述符:
  0   标准输入
  1   标准输出
  2   标准错误
  这些值能够用于描述终端、文件的读写,甚至设置其他进程的描述。使shell重定向, cat /etc/hosts >> hosts.out, shell将打开文件hosts.out并且将cat /etc/hosts做为自己的参数执行。不管怎样,当cat进程写到标准输出后(1),结果不会被tty得到,而是输出到hosts.out文件。(cat程序根本不知道写入了文件系统的文件,还是写入到标准输出的文件描述符,我们将在这章的后面一点看到究竟是怎么实现的)
  最基本的两个操作描述符是Open和Close函数
  Open函数
  int     open(const char *path, int flags, /*  mode */ );,
  成功地调用这个函数后,Open函数将返回文件及参数的描述符,这个整型描述符在进程文件描述表内生成索引。该描述符的结构能够让内核知道如何操作这个文件。在BSD上,这个结构叫做filedesc,并且能够在/usr/include/sys/filedesc.h这个头文件中找到。当进程要在这个描述符上执行一些操作的时候,它将要求文件描述符为读、写、可执行操作指定一个整数值。
  内核保存了所有文件描述符的基准值,这些基准值将在时进程打开、复制它或者已经处于打开状态的文件描述符执行exec调用、跨越fork的过程中增加。当这个参考值为0的时候,文件关闭。意思是,如果你有一个程序执行fork或者exec调用,并且close-on-exec位没有指定,基准值将增加;并且当一个新的程序执行了fork或者exec调用,基准值将继续增加。所以文件一直处于打开状态,直到基准值被设置为0,或者直到所有的进程关闭它,或者退出。
  Close函数
  int        close(int fd);
  当进程想移除或者关闭一个打开的文件描述符的时候,它将调用close函数。这将关闭指定的文件描述符,并且减少文件描述符的参考值。这个过程很像 exit――――当一个进程执行exit,所有打开的文件描述符跟进程一起被自动地减少,自从文件参考值设为0,内核将释放所有的文件入口的副本.
  getdtablesize函数
  int        getdtablesize();
  getdtablesize函数返回文件描述表的大小,它能用作检查系统限制,你也能够用下面的命令做相同的事情。
  bash$ sysctl kern.maxfilesperproc
  kern.maxfilesperproc: 3722
  依赖于你的系统,你能够在系统运行的时候调整它,或者从新编译你的内核,这个函数不能检查当前进程打开了多少文件,(跟getdtablesize一样)仅仅返回你的进程能够打开文件的最大个数。
  fcntl函数
  int        fcntl(int fd, int cmd, ...);
  fcntl 函数允许进程操作文件描述符,fcntl函数至少需要指定两个参数,一个有效的文件描述符,一个命令。根据使用的命令,决定fnctl是否需要第三个参数,下面为命令定参数义了一些值。在FreeBSD上,你能在/usr/include/fcntl.h头文件中找到它们。
  #define F_DUPFD        0
  F_DUPFD用作创建一个新的很像原型的文件描述符,(你能够用dup调用做到相同的事情,将在晚些时候涉及到),当成功执行带F_DUPFD标记的fcntl函数,fcntl将返回下面属性之一的新的文件描述符:
  假如指定了第三个参数,描述符返回的值比最小可用的描述符,该值等于或者比给定的第三个参数的值大一点,返回的描述符将参照指定给fcntl第一个参数的文件描述符
  假如fcntl指定的文件描述符是一个文件,新文件描述符将有相同的文件偏移量,并且新文件描述符将有相同的访问方式(如:O_RDONLY,O_RDWR,o_WRONLY)
  新文件描述符将共享文件状态标记
  新文件的“close-on-exec”标志将被关闭,即新的文件描述符在exec调用之后仍将保持打开。
  F_GETFD命令
  #define  F_GETFD     1
  F_GETFD 命令用作获取"close-on-exec"标记的状态,跟FD_CLOSEXEC相与后返回值要么为0,要么为1。如果返回0,close-on- exec标记没有被设置过,那么文件描述符将保持调用交叉执行调用(so the file descriptor will remain open across exec calls.),假如是1,close-on-exec标志被设置过,文件描述符将在成功调用一个exec函数后被关闭。
  F_SETFD命令
  #define  F_SETFD     2
  F_SETFD命令用作设置文件描述符的close-on-exec标志位。第三个参数要么是FD_CLOEXEC,设置close-on-exec标记,要么是0,取消close-on-exec标记的设置。
  F_GETFL和F_SETFL命令
  #define  F_GETFL    3
  #define  F_SETFL    4
  F_GETFL命令将使fcntl返回当前文件描述符状态标记,当返回值加上O_ACCMODE(#define O_ACCMODE 0x0003)能够获取到打开的方式,F_SETFL命令将根据第三个参数设置文件状态标记。
  公共的标记
  下面这些标记也用作调用open,并且只能被跟上期望的标记调用open函数设置,这是最常见的,检查你系统的头文件能够查到那些值
  #define  O_RDONLY 0x0000
  如果O_RDONLY标记被设置,那么文件只能以只读方式打开。注意这个O_RDONLY标记只能在打开的时候被设置,它不能被fnctl加F_SETFL命令设置。
  #define  O_WRONLY 0x0001
  如果O_WRONLY标记被设置,那么文件只能以只写方式打开。这个标记只能被open设置,不能被fcntl加F_SETFL命令设置。
  #define  O_RDWR      0x0002
  如果O_RDWR标记被设置,那么文件以可读可写方式打开。这个标记也只能被open调用设置。
  #define  O_NONBLOCK  0x0004
  如果O_NONBLOCK标记被设置,文件描述符将不被阻塞而被直接返回替代。一个例子是打开tty。如果用户不在终端调用里输入任何东西,read将被阻塞,直到用户有输入,当O_NONBLOCK标记被设置,read调用将直接返回设置到EAGAIN的值
  #define  O_APPEND 0x0008
  如果O_APPEND标记被设置,文件将以追加方式打开,并且将从文件末尾开始写入。
  #define  O_SHLOCK 0x0010
  如果O_SHLOCK标记被设置,文件描述符将在文件上生成一个共享锁,在文件上设置了共享锁,多个进程能在同一个文件够执行操作,文件共享锁的详细信息,可用看fnctl函数的F_GETLK跟F_SETL命令。
  #define  O_EXLOCK 0x0020
  如果O_EXLOCK标记被设置,文件描述符将在文件上生成一个可执行锁,一样,更详细的描述可以参照fcntl函数的F_SETLK跟F_GETLK命令。
  #define  O_ASYNC     0x0040
  如果O_ASYNC标记被设置,进程集将被发送的SIGIO信号通知,在文件描述符号的IO是可用的。详细的描述请参照信号那一章。
  #define  O_FSYNC     0x0080
  如果O_FSYNC标记被设置,所有写到文件描述符的写操作将不被内核缓存,取而代之的是将被写到介质,并且所有的写调用都将被阻塞,直到内核完成(写操作)。
  #define  O_NOFOLLOW  0x0100
  如果O_NOFOLLOW标记被设置,假如文件是一个符号连接,open调用将会失败。如果在一个有效的文件描述符上设置了这个标志,那么当前文件就不是一个符号连接。
  #define  O_CREAT     0x0200
  如果O_CREAT标记被设置,假如执行open调用的时候文件不存在,那么文件可用被创建。(这个错误的拼写很有趣;when one of the original creators of C was asked "What one thing would you change about C?" he replied, "I would change O_CREAT to O_CREATE!", or at least how the rumor goes)
  #define  O_TRUNC     0x0400
  如果O_TRUNC标记被设置,成功地调用open后文件将被截除。
  #define  O_EXCL      0x0800
  当O_EXCL标记被设置,假如文件已经存在,open调用将产生一个错误。
  #define F_GETOWN          5
  F_GETOWN命令用于描述符获取当前进程或者进程集收到的SIGIO信号。如果这个值是一个正数,它表示一个进程,负数表示一个进程集。
  #define F_SETOWN  6
  当IO就绪的时候,F_SETOWN命令用作设置进程或者进程集使其接收SIGIO信号,指定一个进程,用一个正数(一个进程ID)作为fcntl的第三个参数,否则,用一个负数作为fcntl的第三个参数指定进程集。
  5.3文件上锁
  当多个进程试图写同一个文件,将发生什么?它们相互冲突,已知的事情像文件上锁。结果就是每个文件描都有自己的描述符跟偏移量,当每个进程写自己的文件时,偏移量预先独立导致没有进程知道其他的进程也正在执行写操作。最后的文件将因为多个独立写文件的操作使混合后的文件变得相当于垃圾,直接给文件上锁是解决这个问题的一种方式。在任意时刻只能让一个进程能够写到文件,另一种办法是允许在一个叫做高级文件锁的scheme里的文件内部进行区域锁定。 fcntl函数能够提供这个功能,通常来说,锁有两种,一种是写,另一种是写,不同之处在于读锁不会干扰其它进程读取文件,但是特定的区域只能一个写锁存在。
  当使用顾问锁的时候,下面的结构用作fcntl的第三个参数。
  struct flock {
  off_t   l_start;    /* starting offset */
  off_t   l_len;      /* len = 0 means until end of file */
  pid_t   l_pid;      /* lock owner */
  short   l_type;     /* lock type:   */
  short   l_whence;   /* type of l_start */
  };
  让我们继续讨论每个元素的细节。
  l_start
  这是一个相对于l_whence,单位为字节的偏移量,换句话说,要求的位置实际上是l_whence + l_start
  l_len
  需设置为期望位置的长度,单位为字节,锁将从l_whence + l_start开始锁定l_len字节,如果你想整个文件用一把锁,那么设定l_len的值为0,如果l_len的值是一个负数,结果是不可预测的。
  l_pid
  需要设置为工作在锁上的进程的ID
  l_type
  需要设置为期望的锁的类型,下面是能够使用的值
  * F_RDLCK - 读锁定
  * F_WRLCK - 写锁定
  * F_UNLCK - 用作清除锁定
  l_whence
  这是这个系统调用里面最混乱的部分,这个字段将决定l_start位置的偏移量,需要设为:
  * SEEK_CUR - 在当前位置
  * SEEK_SET - 在文件开始
  * SEEK_END - 在文件末尾
  fcntl的命令
  下面的可用作fcntl的命令
  #define  F_GETLK      7
  F_GETLK 命令尝试检查否能上锁,当使用这个命令,fnctl将检查是否有相冲突的锁,如果存在相冲突的锁,fnctl将改写flock结构,用冲突锁消息通过检查,如果没有相冲突的锁,那么在flock结构最初的信息将被保留,除非l_type字段被设成F_UNLCK
  #define  F_SETLK      8
  F_SETLK命令试图获得flock结构描述的锁,如果锁不被承认,本次调用将不被阻塞。不管怎样,fcntl将直接返回EAGAIN,同时将设置相应的errno,当flock结构的l_type被设置为F_UNLCK时,你能够使用这个命令清除一个锁。
  #define  F_SETLKW     9
  F_GETLK命令试图获得flock结构描述的锁,它将命令fnctl阻塞,直到赋予一个锁
  5.4为什么用FLOCK 
  对大部分情况来说,高级文件锁定机制是有好处的。然而,POSIX.1接口有几个缺点。第一,当一个文件的任何一个文件描述符被关闭时,与该文件关联的所有锁定必须被删除。换句话说,如果你有一个进程打开一个文件,接着它调用一个函数打开同一个文件,读取然后关闭它,这样先前你对这个文件的所有锁定都会被删除。如果你并不确定一个库例程会做什么,这将会引起严重问题。第二,锁定是不会传递给子进程的,所以一个子进程必须独立地创建属于它自己的锁定。第三,所有在一个exec调用之前获得的锁定在由exec启动的进程释放,关闭这个文件或结束之前不会被释放。所以,如果你需要锁定文件的某一部分,那么调用exec不需要释放锁定或者关闭文件描述符,那部分区域将被锁定直到进程结束,你想要的或许不是预期的结果,不论如何,BSD的设计者用许多flock创建了非常简单的优先级文件上锁的接口.
  flock用于锁定整个文件,是BSD优先选择的方法,跟fcntl高级锁定相反,flock机制允许锁定进入子进程,使用flock调用的其他好处是可以在文件级并且不在文件描述符级别完成锁定,在某些情况下可用优先选择,意味着多个参照同一个文件的文件描述符,例如DUP()调用,或者多个OPEN()调用,希望每一个参照相同的文件锁,带flock的文件锁跟一个写多个读的fcntl锁很类似,不论如何,当下面的操作被定义,调用flock时,锁的优先级能够被提升:
  #define   LOCK_SH        0x01      /* shared file lock */
  LOCK_SH操作用于在文件上(类似fcntl的读锁)创建共享锁,在一个文件上,多个进程能够共享一把锁。
  #define   LOCK_EX        0x02      /* exclusive file lock */
  LOCK_EX操作用于在文件上创建互斥锁,当互斥锁生效时,文件上不能存在其他的共享锁,包括已共享的锁。
  #define   LOCK_NB        0x04      /* don't block when locking */
  使用这个,flock的调用将阻塞,直到锁定生效,不论如何,假如期望的操作LOCK_NB是ORed,flock的调用将向EWOULDBLOCK返回错误号成功(0)或者失败(1).
  #define   LOCK_UN        0x08      /* unlock file */
  LOCK_UN用于移除文件上的锁
  通过调用期望的flock,flock锁的优先级能够被提升或者降低。新的成功的调用将使最近生效的锁替换先前的锁。
  DUP函数
  int dup(int old);
  像fcntl调用能够用作为现有的文件描述符复制描述符一样,dup函数也能复制文件描述符,dup调用能够返回一个跟old参数无法区别的新的文件描述符,这就意味着所有的read(),write()跟lseek()调用都会操作两个描述符(复制出来的新的跟原来的描述符),同时,所有fcntl的选项将保留,close on exec位出外, close on exec位会被关闭,所以你可以复制一个文件描述符,然后允许子进程去调用一个exec函数,这是dup函数非常普遍的一个用法。old参数用作复制,并且必须是一个有效的参数,描述目标描述符,新文件符至少应该是没使用过的文件描述符,它由成功调用dup函数后返回。它意味着如果你关闭STDIN_FILENO(该值为0)那么dup直接调用的新文件描述符的值将是STDIN_FILENO,假如dup函数调用因一些原因失败,将返回-1并且相应地设置errno.
  DUP2函数
  int dup2(int old, int new);
  除了new参数是希望的目标值,dup2函数跟dup函数很相似。假如新参数已经参照了一个有效打开的描述符,并且它的值跟老参数的值不一样,那么新文件描述符将先被关闭。假如新参数等于老参数,那么函数不会做任何操作。成功调用DUP2的返回值将等于新参数。假如DUP2调用失败,将返回-1并且相应地设置errno.
  5.5  进程间通信
  来自于System V的主要的功能是基本的进程间通信,或者说IPC,这些一直在BSD里面被非常广泛地使用。IPC机制允许程序之间相互共享数据。这个很像我们已经介绍过的重定向,但是重定向是单向处理而不是双向处理。在示范程序中,重定向可以跟设置过STDIN_FILENO参数的CAT命令共享数据,但是有一个问题:cat命令不能跟重定向的程序共享数据,假设一个算法是从其他文件描述符读但是用open不灵活的时候,我们可以修改他们使其可以双向地相互共享数据。BSD提供了很多更好的用于进程间通信的方法。
  PIPE函数
  int pipe(int *array);
  通过给定一个有效的二维数组调用pipe函数(如:int array[2]),pipe函数将分配两个文件描述符,假如成功,数组将包含两个有区别的并且允许单向通信的文件描述符, 打开的第一个文件描述符(array[0])用于读,打开的另一(array[1])个用于写,所以,自从成功调用pipe函数后,你能在这两个描述符之间得到一个单向通信通道,当写入其中一个时,你也将能够从另一个读取输出,管道函数比重定向好的地方是你不必使用文件,
  这些文件描述符的行为与普通的文件描述符完全一样,然而它们没有任何文件与之关联,管道功能使unix shell加到其他命令的管道变得很有用,例如
  bash$ find /  -user frankie  | grep -i jpg  | more
  这个例子里面,find命令将其输出通过管道传送给grep命令,grep再将其输出通过管道传送给more命令。当建立这个顺序的时候,shell将处理管道实际的设置,这些程序本身没有写到其他程序的想法,因为他们真的不需要知道。从这个例子你能看见自从调用了管道,正常来说进程就会fork, 之后进程就能通信,假如要达到双向通信的目标,你需要创建两个管道,一个用于父进程到子进程的通信,另一个用作子进程到父进程的通信。
  管道有下面两条通信规则:
  1.如果管道读的这边关闭了,试图写到这个管道将会导致一个SIGPIPE信号发送给试图写的进程。
  2.如果管道写的这边关闭了,试图从这个管道读将导致读返回0或文件结束。关闭写端是发送文件结束到该管道读端的唯一方法。
  成功地调用pipe函数后将返回0,假如调用失败,将返回-1并且errno将被相应地设置,
  备注:在更多的现代的BSD上,单个描述符上pipe函数支持双向通信,不论如何,这个特性不是很轻便,也因为如此,这个方式不建议使用。
  Mkfifo函数
  int mkfifo(const char *path, mode_t mode);
  在相关的进程间通信时,管道是有用的,然而在没有关联关系的进程间通信时,使用mkfifo函数。Mkfifo函数实际上在文件系统创建一个文件。这个文件只是其他文件在通信时使用的一个标志。这些文件就叫做FIFO管道(先进先出管道)。当一个进程创建一个FIFO管道,写到这个FIFO管道并不会写到这个文件,而是被另一个进程读取。这种行为与管道非常相似,所以FIFO也被叫做命名管道。Mkfifo函数有两个参数。第一个参数是一个以null结尾的字符串,声明路径和文件名。第二个参数是该文件的存取模式。该存取模式是标准的unix文件所有者读写权限(参考/usr/include/sys/stat.h中的S_IRUSR, S_IRGRP等)。
  一旦mkfifo函数成功调用,需要用open函数打开创建的fifo管道进行读写。如果调用失败,会返回-1而且错误代码会被相应地设置。
  创建fifo管道与创建文件相类似,进程也必须有足够的权限来创建fifo管道,因为该fifo的用户ID会被设置为该进程的有效用户ID,而组ID会被设置为该进程的有效组ID。
  关于FIFO重要的一点是,在缺省情况下,它们是阻塞的。因此,读取一个fifo管道会被阻塞,直到另一端把数据写进来,反之亦然。为了避免这种情况,可以使用O_NOBLOCK参数来打开。在这种情况下,你会获得以下行为:对读的调用会立即返回,返回值为0;或者对写的调用会导致一个SIGPIPE信号。
  5.6消息队列
  另一种进程间通信机制,消息队列,为进程间通信提供另一种方式。然而和我提到的其他通信机制不同,你应该尽量避免使用这种方式。如果你的程序使用消息队列,试着用fifo或者甚至Unix Domain Socket重新实现它。在我讨论原因之前,以下是一个快速概述。
  消息队列与FIFO相似,但它们使用一个键而不是一个文件作为引用。这个键是一个无符号整数。一旦一个消息队列被创建,发送到这个消息队列的数据会被内核缓存。内核分配给消息队列的内存是有限的。一旦一个消息队列被填满,那么在一个进程从这个消息队列把数据读走之前不能再往这个队列发送数据。在这种情况下,如果两个进程以不同的速度读写,队列是可靠的而且在大多数情况下是非堵塞的。这与FIFO不同。在FIFO的机制中,一个慢的读进程事实上是会拖慢一个比较快的写进程的(除非设置了O_NONBLOCK参数)。另一个好处是即使写进程退出了,写到消息队列中的数据也会被保存起来直到另一个进程读取它。而在FIFO的机制下,如果写进程退出了,这个FIFO会被关闭,而读进程会收到一个文件结束的标志。
  以上这些所有的消息队列的好处看起来不错,但让我们再仔细看看。假定一个进程打开一个消息队列,往里面写了一大块数据,填满了内核的缓冲区然后退出,内核将不得不保存这些数据直到另一个进程来读取它,而其他任何想创建和写消息队列的进程将会被拒绝。这种情况将会持续直到一个进程读走这些数据或者系统重启。在这种情况下,创建一个简单的针对消息队列的拒绝服务是可能的。
  另一个问题是键并不确保是唯一的。换句话说,一个进程无法确立一种方式来确定它是否是使用一个特定消息队列的唯一进程。而在FIFO机制中,当一个进程创建一个FIFO时,它有比较好的机会知道这个FIFO是否唯一因为可以声明一个针对文件路径的预先约定(比如:/usr/local/myapp/fifo_dir)。你的应用程序可以在安装时创建一个唯一的目录,这样几乎可以确保一个唯一的FIFO路径。有效的消息队列键值可以通过调用一个函数ftok来生成以帮助减少相同的键值,但并不能确保唯一。这个问题的副作用难于确定―你的程序可能读到它并不想读的数据,或者你的程序写入的数据正被其他并不想读取的进程读取。简短来说,当你使用消息队列时,可能导致难于调试的奇怪行为和错误。
  如果你仍然坚持使用消息队列,参考以下的指南页:ftok(3), msgget(3), msgctl(3), msgrcv(3), 和msgsnd(3)。
  5.7 结论
  这一章介绍了几个操作打开文件描述符的系统调用,包含在我们fork和exec之前必须关闭文件描述符的场景。我们也讨论了文件锁定,设置和移除文件锁定,以及一些特殊的文件描述符如FIFO和Queue等,在那种情况下根本不在文件系统上存储数据。这些系统调用为BSD增加了很大的可编程性和灵活性。但当一个进程有多个打开的文件描述符时会怎么样?下一章将会讨论高效地处理多个文件描述符。
分享到:
评论

相关推荐

    珍藏近二十年的Linux后端编程资料,迟点删,有需要的赶紧下载

    珍藏近二十年的Linux后端编程资料,迟点删,有...第五章: 基本I/O ;第六章: 高级I/O;第七章: 进程资源和系统限制;第八章: FreeBSD 5.x 。Linux系统大同小异,看了这些,受益良多,感兴趣的,欢迎关注我,一起探讨。

    微机接口技术第五章 I / O 数据交换方式

    1.微机与外设的数据交换方式:包括查询方式、中断方式、DMA 方式和通道控制方式。 2.可编程中断控制器:介绍 8259 的结构与工作原理,编程方法与实际应用。...4.多功能 I / O 接口芯片:讲述 82380 的基本构造。

    UNIX网络编程第1卷(1-19章)

    第五章 TCP客户-服务器程序例子 第六章 I/O复用:select和poll函数 第七章 套接口选项 第八章 基本UDP套接口编程 第九章 基本名字与地址转换 第十章 IPv4和Ipv6的互操作性 第十一章 高级名字与地址转换 第十二章 ...

    UNIX网络编程 第2卷 进程间通信.pdf(带书签)

    第5章 TCP客户/服务器程序例子? 第6章 I/O复用:select和poll函数 第7章 套接口选项 第8章 基本UDP套接口编程 第9章 基本SCTP套接口编程 第10章 SCTP客户/服务器程序例子 第11章 名字与地址转换 第3部分 高级套接口...

    电子设计:单片机入门教程

    第5章:AT89S51程序设计与调试 第6章:AT89S51单片机并行I/O口 第7章:AT89S51单片机中断系统 第8章:AT89S51定时/计数器 第9章:AT89S51单片机串行通信 欢迎大家积极点赞和评论,博主会定期回复!

    编程实践:Java进阶100例

    第五章:面向对象的Java编辑; 第六章:接口与内部类; 第七章:集合的应用; 第八章:异常和反射; 第九章:初识AWT和Swing; 第十章:Swing中的常用组件; 第十一章:线程; 第十二章:I/O流; 第十三章:Swing中...

    UNIX网络编程 第2卷 进程间通信 带完整书签

    第5章 TCP客户/服务器程序例子? 第6章 I/O复用:select和poll函数 第7章 套接口选项 第8章 基本UDP套接口编程 第9章 基本SCTP套接口编程 第10章 SCTP客户/服务器程序例子 第11章 名字与地址转换 第3部分 ...

    UNIX网络编程 卷1:套接字联网API

    第5章 TCP客户/服务器程序示例 第6章 I/O复用:select和poll函数 第7章 套接字选项 第8章 基本UDP套接字编程 第9章 基本SCTP套接字编程 第10章 SCTP客户/服务器程序例子 第11章 名字与地址转换 第三...

    计算机组成原理:硬件软件接口 原书第5版课后答案

     与前几版一样,本书采用MIPS处理器讲解计算机硬件技术、汇编语言、计算机算术、流水线、存储器层次结构以及I/O等基本功能。  《计算机组成与设计:硬件/软件接口(原书第5版)》特点  更新例题、练习题和参考...

    UNIX网络编程卷2进程间通信(第2版)

    第5章 TCP客户/服务器程序例子? 第6章 I/O复用:select和poll函数 第7章 套接口选项 第8章 基本UDP套接口编程 第9章 基本SCTP套接口编程 第10章 SCTP客户/服务器程序例子 第11章 名字与地址转换 第3部分 高级套接口...

    嵌入式系统-硬件与软件架构(正版)

     第5章 板级存储器   5.1 只读存储器   5.2 随机访问存储器   5.3 辅助存储器   5.4 外部存储器的存储管理   5.5 板级存储器及其性能   小结   习题   附注   第6章 板级I/O   6.1 管理数据:...

    计算机组成与设计:硬件软件接口教材+习题答案 中文第5版

    《计算机组成与设计:硬件/软件接口(原书第5版)》是计算机组成与设计的经典畅销教材,第5...与前几版一样,本书采用MIPS处理器讲解计算机硬件技术、汇编语言、计算机算术、流水线、存储器层次结构以及I/O等基本功能。

    OMRON CS/CJ 系列可编程序控制器 PLC 编程手册

    断和调试,编程装置,以及CJ 系列基本I/O 单元的输入响应时间设定。 第7 章描述用于将程序传送到CPU 单元的过程及测试和调试程序的功能。 附录 给出了CS/CJ 系列可编程序控制器的比较,使用C200H 特殊I/O 单元的限制...

    UNIX网络编程卷1:套接字联网API(第3版)part1 共2部分

    第5章 TCP客户/服务器程序示例 第6章 IO复用:select和poll函数 第7章 套接字选项 第8章 基本UDP套接字编程 第9章 基本SCTP套接字编程 第10章 SCTP客户/服务器程序例子 第11章 名字与地址转换 第三部分 第12...

    ARM开发--S3C4510B

    第五章:本章是全书的重点,详细介绍基于S3C4510B的系统的设计全过程,包括存储器及外围芯片的选型,各单元电路的设计、调试等。通过对本章的阅读,具有一定系统设计知识的读者应该可以掌握基于S3C4510B的系统设计,...

    精通MATLAB—综合辅导与指南

    第5章 关系和逻辑运算 第6章 文本 6.3 循环串函数 第7章 决策: 控制流 第8章 M-文件函数 第9章 数据分析 第10章 多项式 第11章 曲线拟合与插值 第12章 三次条样 第13章 数值分析 第14章 富里哀分析 第15章 低级文件...

    OMRON CJ1系列PLC操作手册

    第8 章 介绍对基本 I/O 单元、特殊 I/O 单元和CPU 总线单元的I/O 分配,以及与CPU 总线单元的 数据交换。 第9 章 介绍 I/O 存储器区和参数区的结构和功能。 第10 章 介绍 CPU 单元的内部操作和内部处理用的循环时间...

    清华版labview教程

    第五章 字符串和文件I/O 5.1 字符串 5.2 文件的输入/输出(I/O) 5.2.1 文件 I/O 功能函数 5.2.2 将数据写入电子表格文件 5.3 数据记录文件(datalog file) 第六章 数据采集 6.1 概述 ...

    ARM技术开发全集之5

    第五章:本章是全书的重点,详细介绍基于S3C4510B的系统的设计全过程,包括存储器及外围芯片的选型,各单元电路的设计、调试等。通过对本章的阅读,具有一定系统设计知识的读者应该可以掌握基于S3C4510B的系统设计,...

    aybook.cn_c++jiaocheng0105.rar

    第5章 数组和字符串 5.1 一维数组 5.2 字符串 5.3 字符串库函数 5.4 二维数组 5.5 多维数组 5.6 数组初始化 5.7 字符串数组 第6章 指针 6.1 什么是指针 6.2 指针运算符 6.3 指针表达式 6.4 指针和数组 6.5 指针与...

Global site tag (gtag.js) - Google Analytics