Lecture notes for CSC 252, Thurs. Apr. 14, 2011 A7 trivia due today main due Friday 29 Apr. ======================================== I/O to/from files; also pipes, network connections keyboards, mice, joysticks, credit card readers, robot arms, ... all hidden behind a common interface sequence of bytes stateful; file/device must be _opened_ prior to read/write does name lookup -- finds file/device on disk/bus checks permissions initializes kernel-level buffers, file pointer (current position) etc. random-access (seek-able) v. sequential (no seek) ---------------------------------------- "system-level" int open(const char *fname, int flags, mode_t mode) flags indicate combinations of read, write, create, truncate, append mode is permissions if creating: read/write/execute for user/group/others umask value (part of process state, settable via umask() function) is set of permission bits to always leave off, regardless of what's specified. That is, the actual permissions will be (mode & ~umask). umask is inherited on fork. I set it to 2 in my shell. That way files I create are never world-writable, unless the creating process explicitly changes its umask prior to creation, or I explicitly change the file after creation. return value is _file descriptor_: small integer; used by kernel to index into hidden per-process table three initially-open files: STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO int close(int fd) ssize_t read(int fd, void *buf, size_t n) n indicates # of bytes desired; returns # of bytes read, which may be less if EOF is reached (or EOLN on a terminal, or network limitations on a socket or pipe). -1 means error. 0 means already at EOF. (NB: arg is unsigned; return is signed) ssize_t write(int fd, void *buf, size_t n) n indicates max # of bytes to be written; returns # actually written. which may be less due to network limitations if on a socket or pipe. -1 means error. (NB: arg is unsigned; return is signed) off_t lseek(int fd, off_t offset, int whence) whence indicates whether offset is relative to the beginning, end, or current position. other stuff (metadata access, directory access, ioctl, ...) Metadata via stat and fstat. Retrieves a whole bunch of stuff, including kind of file/device access, update, and status modification times size user and group ids block size ---------------------------------------- Unix "standard I/O" FILE object ("stream"): lots of user-level state, including buffers for read-ahead and write-behind minimize # of kernel calls three initially-open streams (FILE* objects): stdin, stdout, stderr fgetc(stream) function getc(stream) macro (faster, but may eval arg more than once) getchar() from stdin fputc(stream) function putc(stream) macro (faster, but may eval arg more than once) putchar() to stdout fputs(char*, stream) puts(char*) to stdout fgets(char*, size, stream) scanf, fscanf printf, fprintf and several others (see man pages) ======================================== (Internet) Networking Messier than (local) file I/O due to different administrative domains packet reordering (packet-switched routing) packet size restrictions packet loss (unreliable connections) packet duplication timing variation Take 257 to learn (much) more. 210 also touches on this stuff. IP, (UDP), TCP data on the wire is big-endian ("network byte order") IP and UDP are connectionless and unreliable TCP is connection-based and "reliable" (hard failures only) IPv4 addresses are 32 bits. Still the most common. IPv6 are 128 bits. Most big networks and recent OSes support IPv6, but most small networks do not, and most traffic and most endpoints are still IPv4 ---------------------------------------- TCP based on reliable _connections_ bidirectional socket address at each end socket manifests in Unix as a file descriptor Typically distinguish between a "well known" endpoint, on which a server waits for connection requests, and an "ephemeral" endpoint on which a client communicates with a server or a server communicates with a particular client. Important to distinguish between "listening" socket fd, bound to the well-known server endpoint, and a connected socket fd, used for ordinary messages. C interface is messy. Book introduces wrapper functions to simplify it somewhat, but these are non-standard. Java has standard wrappers, which are a good bit nicer. I'll use these to illustrate the concepts. Server "listens" on a well-known port: ServerSocket myServerSocket = new ServerSocket(portID); // Cf. the open_clientfd wrapper in the text Socket clientConnection = myServerSocket.accept(); // Blocks until server receives a connection request from a // client. Typically server will fork a thread to talk to the // client, and then go back to listening for other clients. Client sends request for connection via Socket constructor: Socket serverConnection = new Socket(hostName, portID); // hostName is a string; portID is an integer // Cf. the open_listenfd wrapper in the text Once server and client are connected, they typically create streams to talk through: BufferedReader in = new BufferedReader( new InputStreamReader(clientConnection.getInputStream())); PrintStream out = new PrintStream(clientConnection.getOutputStream()); // client would make similar calls using serverConnection ... String s = in.readLine(); ... out.println("Hi, Mom\n");