1. Chapter 2 Review Of Underlying Network Technologies. Introduction Internetworking With TCP/IP Volume Client-Server Programming. technology underlying the TCP/IP Internet protocol suite and the architecture of an internet. Internetworking With TCP/IP vol 1 -- Part 1. 2. [PDF] Free Download Internetworking with TCP/IP, Vol 1 (5th Edition) by Douglas E. Comer E-book^ Online^ shows how all protocols in the TCP/IP suite fit into the five- layer model. With a new focus on CIDR addressing, this revision addresses MPLS and IP switching technology.
|Language:||English, Spanish, Hindi|
|Genre:||Fiction & Literature|
|Distribution:||Free* [*Register to download]|
Note: If you're looking for a free download links of Internetworking with TCP/IP Volume One (2-download). (6th Edition): 1 Pdf, epub, docx and torrent then this. free download links of Internetworking with TCP/IP Volume One (2-download) ( 6th Edition): 1 Pdf, epub, docx and torrent then this site is not for you. Vol III: Client-Server Programming And Applications. Internetworking with TCP/IP Volume One (2-download) (6th Edition): 1 Pdf medical-site.info, medical-site.info
Additional information can be found at: Du kanske gillar. The Elder Scrolls: SAFe 4. Deep Medicine Eric Topol Inbunden. Inbunden Engelska, Spara som favorit. It means "apparently simultaneous execution. The important concept is: Application programmers build programs for a concurrent environment without knowing whether the underlying hardware consists of a uniprocessor or a multiprocessor. Processes In a concurrent processing system, a conventional application program is merely a special case: The notion of process differs from the conventional notion of program in other ways.
For example, most application programmers think of the set of variables defined in the program as being associated with the code. However, if more than one process executes the code concurrently, it is essential that each process has its own copy of the variables. To understand why, consider the following segment of C code that prints the integers from 1 to In a conventional program, the programmer thinks of storage for variable i as being allocated with the code.
However, if two or more processes execute the code segment concurrently, one of them may be on the sixth iteration when the other starts the first iteration. Each must have a different value for i. Thus, each process must have its own copy of variable i or confusion will result, To summarize: When multiple processes execute a piece of code concurrently, each process has its own, independent copy of the variables associated with the code. Subprograms accept arguments, compute a result, and then return just after the point of the call.
If multiple processes execute code concurrently, they can each be at a different point in the sequence of procedure calls. One process, A, can begin execution, call a procedure, and then call a second-level procedure before another process, B, begins.
Process B may return from a first-level procedure call just as process A returns from a second-level call. The run-time system for procedure-oriented programming languages uses a stack mechanism to handle procedure calls. The run-time system pushes a procedure activation record on the stack whenever it makes a procedure call.
Among other things, the activation record stores information about the location in the code at which the procedure call occurs. When the procedure finishes execution, the run-time system pops the activation record from the top of the stack and returns to the procedure from which the call occurred.
Analogous to the rule for variables, concurrent programming systems provide separation between procedure calls in executing processes: As with most computational concepts, the programming language syntax is trivial; it occupies only a few lines of code. For example, the following code is a conventional C program that prints the integers from I to 5 along with their sum: In essence, fork divides the running program into two almost identical processes, both executing at the same place in the same code.
The two processes continue just as if two users had simultaneously started two copies of the application.
For example, the following modified version of the above example calls fork to create a new process. Note that although the introduction of concurrency changes the meaning of the program completely, the call to fork occupies only a single line of code.
However, when the process reaches the call to fork, the system duplicates the process and allows both the original process and the newly created process to execute. Of course, each process has its own copy of the variables that the program uses. In fact, the easiest way to envision what happens is to imagine that the system makes a second copy of the entire running program. Then imagine that both copies run Oust as if two users had both simultaneously executed the program.
To understand the fork function, imagine that fork causes the operating system to make a copy of the executing program and allows both copies to run at the same time. On one particular uniprocessor system, the execution of our example concurrent program produces twelve lines of output: The value of i is 1 The value of i is 2 The value of i is 3 The value of i is 4 The value of i is 5 2 To a programmer, the call to fork looks and acts like an ordinary function call in C.
It is written fork. At run-time, however, control passes to the operating system, which creates a new process. Once the first process completed, the operating system switched the processor to the second process, which also ran to completion. The entire run took less than a second.
Therefore, once a process gained control of the CPU, it quickly ran to completion. If we examine concurrent processes that perform substantially more computation, an interesting phenomenon occurs: We use the term timeslicing to describe systems that share the available CPU among several processes concurrently. For example, if a timeslicing system has only one CPU to allocate and a program divides into two processes, one of the processes will execute for a while, then the second will execute for a while, then the first will execute again, and so on.
If the timeslicing system has many processes, it runs each for a short time before it runs the first one again. A timeslicing mechanism attempts to allocate the available processing equally among all available processes.
Thus, all processes appear to proceed at an equal rate, no matter how many processes execute. With many processes executing, the rate is low; with few, the rate is high. To see the effect of timeslicing, we need an example program in which each process executes longer than the allotted timeslice. Extending the concurrent program above to iterate 10, times instead of 5 times produces: However, instead of all output from the first process followed by all output from the second process, output from both processes is mixed together.
In one run, the first process iterated 74 times before the second process executed at all. Then the second process iterated 63 times before the system switched back to the first process. On subsequent timeslices, the processes each received enough CPU service to iterate between 60 and 90 times.
Of course, the two processes compete with all other processes executing on the computer, so the apparent rate of execution varies slightly depending on the mix of programs running. Creating a truly identical copy of a running program is neither interesting nor useful because it means that both copies perform exactly the same computation. In practice, the process created by fork is not absolutely identical to the original process: Fork is a function that returns a value to its caller.
When the function call returns, the value returned to the original process differs from the value returned to the newly created process. In the newly created process, the fork returns zero; in the original process, fork returns a small positive integer that identifies the newly created process.
Technically, the value returned is called a process identifier or process id3. Concurrent programs use the value returned by fork to decide how to proceed. In the most common case, the code contains a conditional statement that tests to see if the value returned is nonzero: Remember that each process has its own copy of all variables, and that fork will either return zero in the newly created process or nonzero in the original process.
Following the call to fork, the if statement checks variable pid to see whether the original or the newly created process is 3 Many programmers abbreviate process id as pid. The two processes each print an identifying message and exit.
When the program runs, two messages appear: The value returned by fork differs in the original and newly created processes; concurrent programs use the difference to allow the new process to execute different code than the original process. The mechanism that UNIX uses is a system call, execve4, that takes three arguments: Execve replaces the code that the currently executing process runs with the code from the new program.
The call does not affect any other processes. Thus, to create a new process that executes the object code from a file, a process must call fork and execve. For example, whenever the user types a command to one of the UNIX command interpreters, the command interpreter uses fork to create a new process for the command and execve to execute the code.
Execve is especially important for servers that handle diverse services. To keep the code for each service separate from the code for other services, a programmer can build, write, and compile each service as a separate program. When the server needs to handle a particular service, it can use fork and execve to create a process that runs one of the programs.
Later chapters discuss the idea in more detail, and show examples of how servers use execve. To make sure that all processes proceed concurrently, the operating system uses timeslicing, switching the CPU or CPUs among processes so fast that it appears to a human that the processes execute simultaneously. When the operating system temporarily stops executing one process and switches to another, a context switch has occurred.
Switching process context requires use of the CPU, and while the CPU is busy switching, none of the application processes receives any service. Thus, we view context switching as overhead needed to support concurrent processing. To avoid unnecessary overhead, protocol software should be designed to minimize context switching. In particular, programmers must always be careful to ensure that the benefits of introducing concurrency into a server outweigh the cost of switching context among the concurrent processes.
Later chapters discuss the use of concurrency in server software, present nonconcurrent designs as well as concurrent ones, and describe circumstances that justify the use of each. In principle, select is easy to understand: As an example, imagine an application program that reads characters from a TCP connection and writes them to the display screen. The program might also allow the user to type commands on the keyboard to control how the data is displayed. Because a user seldom or never types commands, the program cannot wait for input from the keyboard - it must continue to read and display text from the TCP connection.
The user may type a command while the program is blocked waiting for input on the TCP connection.
The problem is that the application cannot know whether input will arrive from the keyboard or the TCP connection first. To solve the dilemma, a UNIX program calls select. In doing so, it asks the operating system to let it know which source of input becomes available first. The call returns as soon as a source is ready, and the program reads from that source.
For now, it is only important to understand the idea behind select; later chapters present the details and illustrate its use. Concurrency in clients arises easily because multiple users can execute client application software at the same time.
Concurrency in servers is much more difficult to achieve because server software must be programmed explicitly to handle requests concurrently. In UNIX, a program creates an additional process using the fork system call.
We imagine that the call to fork causes the operating system to duplicate the program, causing two copies to execute instead of one. Technically, fork is a function call because it returns a value. The only difference between the original process and a process created by fork lies in the value that the call returns.
In the newly created process, the call returns zero; in the original process, it returns the small, positive integer process id of the newly created process.
Concurrent programs use the returned value to make new processes execute a different part of the program than the original process. A process can call execve at any time to have the process execute code from a separately-compiled program. Concurrency is not free. When an operating system switches context from one process to another, the system uses the CPU. Programmers who introduce concurrency into server designs must be sure that the benefits of a concurrent design outweigh the additional overhead introduced by context switching.
Peterson and Silberschatz  covers the general topic. Comer [ discusses the implementation of processes, message passing, and process coordination mechanisms.
Leffler et. Approximately how many iterations of the output loop can a process make in a single timeslice? Arrange for each process to print a few lines of output and then halt. What information does the newly created process share with the original process? Which version is easier to understand? This chapter considers general properties of the interface an application program uses to communicate in the client-server model.
The following chapter illustrates these properties by giving details of a specific interface. From a programmer's point of view, the routines the operating system supplies define the interface between the application and the protocol software, the application interface. In other words: On the positive side, it provides flexibility and tolerance.
More important, it means designers can use either a procedural or message-passing interface style whichever style the operating system supports. On the negative side, a loose specification means that designers can make the interface details different for each operating system. As vendors add new interfaces that differ from existing interfaces, application programming becomes more difficult and applications become less portable across machines.
Thus, while system designers favor a loose specification, application programmers, desire a restricted specification because it means applications can be compiled for new machines without change. The University of California at Berkeley defined an interface for the Berkeley UNIX operating system that has become known as the socket interface, or sockets. A few other interfaces have been defined, but none has gained wide acceptance yet. An interface must support the following conceptual operations: Because most operating systems use a procedural mechanism to transfer control from an application program into the system, the standard defines the conceptual interface as a set of procedures and functions.
The standard suggests the parameters that each procedure or function requires as well as the semantics of the operation it performs. The point of defining conceptual operations is simple: Because it does not prescribe exact details, operating system designers are free to choose alternative procedure names or parameters as long as they offer equivalent functionality.
To a programmer, system calls look and act like function calls. As the figure shows, when an application invokes a system call, control passes from the application to the system call interface. The interface then transfers control to the operating system.
The operating system directs the incoming call to an internal procedure that performs the requested operation. Once the internal procedure completes, control returns through the system call interface to the application, which then continues to execute.
As it passes through the system call interface, the process acquires privileges that allow it to read or modify data structures in the operating system. The operating system remains protected, however, because each system call branches to a procedure that the operating system designers have written.
Implementations follow one of two approaches: In the first approach, the designer makes a list of all conceptual operations, invents names and parameters for each, and implements each as a system call. Because many designers consider it unwise to create new system calls unless absolutely necessary, this approach is seldom used. The table in Figure 4. The call to open takes three arguments: For example, the code segment: For example, the statement: Finally, when an application finishes using a file, it calls close to deallocate the descriptor and release associated resources e.
First, they extended the set of file descriptors and made it possible for applications to create descriptors used for network communication. Second, they extended the read and write system calls so they worked with the new network descriptors as well as with conventional file descriptors. Thus, when an application needs to send data across a TCP connection, it creates the appropriate descriptor, and then uses write to transfer data.
However, not all network communication fits easily into UNIX's open- read-writeclose paradigm. An application must specify the local and remote protocol ports and the remote IP address it will use, whether it will use TCP or UDP, and whether it will initiate transfer or wait for an incoming connection i. If it is a server, it must specify how many incoming connection requests the operating system should enqueue before rejecting them. The next chapter shows the details of the design.
The standards do discuss a conceptual interface, but it is intended only as an illustrative example. Although the standards present the conceptual interface as a set of procedures, designers are free to choose different procedures or to use an entirely different style of interaction e. Operating systems often supply services through a mechanism known as the system call interface. How would you extend the application program interface to accommodate network communication?
What are the major differences? How are the two similar? What reasons could designers have for choosing one design over the other? How many system calls have already been assigned in your local operating system? How can a system designer add additional system calls without changing the hardware? Write an example script. It covers concepts in general, and gives the intended use of each call.
Later chapters show how clients and servers use these calls, and provide examples that illustrate many of the details. As part of the project, the designers created an interface that applications use to communicate.
TCP first appeared in release 4. Because many computer vendors, especially workstation manufacturers like Sun Microsystems Incorporated, Tektronix Incorporated, and Digital Equipment Corporation, adopted Berkeley UNIX, the socket interface has become available on many machines. Consequently, the socket interface has become so widely accepted that it ranks as a de facto standard. In so doing, they decide the scope of services that the functions supply and the style in which applications use them.
Thus, the designers must choose one of two broad approaches: Differences between the two approaches are easiest to understand by their impact on the names of system functions and the parameters that the functions require. For example, in the first approach, a designer might choose to have a system function named maketcpconnection, while in the second, a designer might choose to create a general function makeconnection and use a parameter to specify the TCP protocol.
Because the designers at Berkeley wanted to accommodate multiple sets of com- munication protocols, they used the second approach. They also decided to have applications specify operations using a type of service required instead of specifying the protocol name. Thus, instead of specifying that it wants a TCP connection, an application requests the stream transfer type of service using the Internet family of protocols.
The calls allow the programmer to specify the type of service required rather than the name of a specific protocol. The overall design of sockets and the generality they provide have been debated since their inception.
Some computer scientists argue that generality is unnecessary and merely makes application programs difficult to read. Others argue that having programmers specify the type of service instead of the specific protocol makes it easier to program because it frees the programmer from understanding the details of each protocol family. As Figure 5.
The system maintains a separate file descriptor table for each process. When a process opens a file, the system places a pointer to the internal data structures for that file in the process' file descriptor table and returns the table index to the caller. The application program only needs to remember the descriptor and to use it in subsequent calls that request operations on the file. The operating system uses the descriptor as an index into the process' descriptor table, and follows the pointer to the data structures that hold all information about the file.
The socket interface adds a new abstraction for network communication, the socket. Like files, each active socket is identified by a small integer called its socket descriptor. UNIX allocates socket descriptors in the same descriptor table as file descriptors.
Thus, an application cannot have both a file descriptor and a socket descriptor with the same value. BSD UNIX contains a separate system function, socket, that applications call to create a socket; an application only uses open to create file descriptors. The general idea underlying sockets is that a single system call is sufficient to create any socket. Once the socket has been created, an application must make additional system calls to specify the details of its exact use.
The paradigm will become clear after we examine the data structures the system maintains. When an application calls socket, the operating system allocates a new data structure to hold the information needed for communication, and fills in a new descriptor table entry to contain a pointer to the data structure.
For example, Figure 5. Although the internal data structure for a socket contains many fields, the system leaves most of them unfilled when it creates the socket. As we will see, the application that created the socket must make additional system calls to fill in information in the socket data structure before the socket can be used.
A socket used by a server to wait for an incoming connection is called a passive socket, while a socket used by a client to initiate a connection is called an active socket. The only difference between active and passive sockets lies in how applications use them; the sockets are created the same way initially.
In particular, the socket does not contain information about the protocol port numbers or IP addresses of either the local machine or the remote machine. Before an application uses a socket, it must specify one or both of these addresses. Other protocol families define their endpoint addresses in other ways. Because the socket abstraction accommodates multiple families of protocols, it does not specify how to define endpoint addresses nor does it define a particular protocol address format.
Instead, it allows each protocol family to specify endpoints however it likes. To allow protocol families the freedom to choose representations for their addresses the socket abstraction defines an address family for each type of address. A protocol family can use one or more address families to define address representations. The chief problem is that both symbolic constants have the same numeric value 2 , so programs that inadvertent ly use one in place of the other operate correctly.
Programmers should observe the distinction, however, because it helps clarify the meaning of variables and makes programs more portable. For example, it may be necessary to write a procedure that accepts an arbitrary protocol endpoint specification as an argument and chooses one of several possible actions depending on the address type.
To accommodate such programs, the socket system defines a generalized format that all endpoint addresses use. The generalized format consists of a pair: In practice, the socket software provides declarations of predefined C structures for address endpoints.
Application programs use the predefined structures when they need to declare variables that store endpoint addresses or when they need to use an overlay to locate fields in a structure. The most general structure is known as a sockaddr structure. It contains a 2-byte address family identifier and a byte array to hold an address3: Each protocol family that uses sockets defines the exact representation of its endpoint addresses, and the socket software provides corresponding structure declarations.
This section describes the calls that provide the primary functionality that clients and servers need. The details of socket system calls, their parameters, and their semantics can seem overwhelming.
Much of the complexity arises because sockets have parameters that allow programs to use them in many ways. A socket can be used by a client or by a server, for stream transfer TCP or datagram UDP communication, with a specific remote endpoint address usually needed by a client or with an unspecified remote endpoint address usually needed by a server.
To help understand sockets, we will begin by examining the primary socket calls and describing how a straightforward client and server use them to communicate with TCP. Later chapters each discuss one way to use sockets, and illustrate many of the details and subtleties not covered here. The call returns a descriptor for the newly created socket. Arguments to the call specify the protocol family that the application will use e.
For a socket that uses the Internet protocol family, the protocol or type of service argument determines whether the socket will use TCP or UDP. An argument to connect allows the client to specify the remote endpoint, which includes the remote machine's IP address and protocol port number. Once a connection has been made, a client can transfer data across it.
Clients usually use write to send requests, while servers use it to send replies. A call to write requires three arguments. The application passes the descriptor of a socket to which the data should be sent, the address of the data to be sent, and the length of the data. Usually, write copies outgoing data into buffers in the operating system kernel, and allows the application to continue execution while it transmits the data across the 4 Structure sockaddr is used to cast i.
If the system buffers become full, the call to write may block temporarily until TCP can send data across the network and make space in the buffer for new data.
Usually, after a connection has been established, the server uses read to receive a request that the client sends by calling write. After sending its request, the client uses read to receive a reply. To read from a connection, an application calls read with three arguments. The first specifies the socket descriptor to use, the second specifies the address of a buffer, and the third specifies the length of the buffer.
Read extracts data bytes that have ar rived at that socket, and copies them to the user's buffer area. If no data has arrived, the call to read blocks until it does. If more data has arrived than fits into the buffer, read only extracts enough to fill the buffer. If less data has arrived than fits into the buffer, read extracts all the data and returns the number of bytes it found.
Clients and servers can also use read to receive messages from sockets that use UDP. As with the connection-oriented case, the caller supplies three arguments that identify a socket descriptor, the address of a buffer into which the data should be placed, and the size of the buffer. Each call to read extracts one incoming UDP message i.
If the buffer cannot hold the entire message, read fills the buffer and discards the remainder.
If only one process is using the socket, close immediately terminates the connection and deallocates the socket. If several processes share a socket, close decrements a reference count and deallocates the socket when the reference count reaches zero. An application calls bind to specify the local endpoint address for a socket. The call takes arguments that specify a socket descriptor and an endpoint address. Primarily, servers use bind to specify the well-known port at which they will await connections.
Connection-oriented servers call listen to place a socket in passive mode and make it ready to accept incoming connections. Most servers consist of an infinite loop that accepts the next incoming connection, handles it, and then returns to accept the next connection.
Even if handling a given connection takes only a few milliseconds, it may happen that a new connection request arrives during the time the server is busy handling an existing request. To ensure that no connection request is lost, a server must pass listen an argument that tells the operating system to enqueue connection requests for a socket.
Thus, one argument to the listen call specifies a socket to be placed in passive mode, while the other specifies the size of the queue to be used for that socket. An argument to accept specifies the socket from which a connection should be accepted. Accept creates a new socket for each new connection request, and returns the descriptor of the new socket to its caller. The server uses the new socket only for the new connection; it uses the original socket to accept additional connection requests.
After it finishes using the new socket, the server closes it. The representation, known as network byte order, represents integers with the most significant byte first. Although the protocol software hides most values used in headers from application programs, a programmer must be aware of the standard because some socket routines require arguments to be stored in network byte order. The socket routines include several functions that convert between network byte order and the local host's byte order.
Programs should always call the conversion routines even if the local machine's byte order is the same as the network byte order because doing so makes the source code portable to an arbitrary architecture.
The conversion routines are divided into short and long sets to operate on bit integers and bit integers. Functions htons host to network short and ntohs network to host short convert a short integer from the host's native byte order to the network by to order, and vice versa.
Similarly, htonl and ntohl convert long integers from the host's native byte order to network byte order and vice versa. Doing so makes the source code portable to any machine, regardless of its native byte order. The client creates a socket, calls connect to connect to the server, and then interacts using write to send requests and read to receive replies.
When it finishes using the connection, it calls close. A server uses bind to specify the local well-known protocol port it will use, calls listen to set the length of the connection queue, and then enters a loop. Inside the loop, the server calls accept to wait until the next connection request arrives, uses read and write to interact with the client, and finally uses close to terminate the connection.
The server then returns to the accept call, where it waits for the next connection. To do so, the program must incorporate the appropriate definitions into each program with the C preprocessor include statement. Usually, include statements appear at the beginning of a source file; they must appear before any use of the constants they define.
The include statements needed for sockets usually have the form: Programs that reference these constants must begin with C preprocessor include statements that reference the files in which the definitions appear.
Because so many other vendors have adopted sockets, they have become a de facto standard. A program calls socket to create a socket and obtain a descriptor for it. Arguments to the socket call specify the protocol family to be used and the type of service required.
The system creates an internal data structure for the socket, fills in the protocol family, and uses the type of service argument to select a specific protocol usually either UDP or TCP.
Additional system calls allow the application to specify a local endpoint address bind , to force the socket into passive mode for use by a server listen , or to force the socket into active mode for use by a client connect.
Servers can make further calls to obtain incoming connection requests accept , and both clients and servers can send or receive information read and write. Finally, both clients and servers can deallocate a socket once they have finished using it close. The socket structure allows each protocol family to define one or more address representations. Before an application program written in C can use the predefined structures and symbolic constants associated with sockets, it must include several files that define them.
The UNIX Programmer's Manual contains specifications for the socket functions, including an exact description of arguments and return codes. Much of the information on socket calls can also be found in Appendix A. What socket types are allowed? Why do some calls require orders of magnitude more time than others? How many packets do you see? This chapter discusses the basic algorithms underlying client software. It shows how applications become clients by initiating communication, how they use TCP or UDP protocols to contact a server, and how they use socket calls to interact with those protocols.
The next chapter continues the discussion, and shows complete client programs that imple- ment the ideas discussed here. For example, the application must specify whether it wishes to act as a client or a server, the endpoint address or addresses it will use, whether it will communicate with a connectionless or connection-oriented protocol, how it will enforce authorization and protection rules, and details such as the size of the buffers it will need.
So far, we have examined the set of operations available to an application without discussing how applications should use them. Unfortunately, knowing the low-level details of all possible system calls and their exact parameters does not provide programmers with an understanding of how to build well-designed, distributed programs.
In fact, while a general understanding of the system calls used for network communication is important, few programmers remember all the details. Instead, they learn and remember the possible ways in which programs can interact across a network, and they understand the trade-offs of each possible design. In essence, programmers know enough about the algorithms underlying distributed computing to make design decisions and to choose among alternative algorithms quickly.
WordPress Shortcode. Published in: Full Name Comment goes here. Are you sure you want to Yes No. Be the first to like this.
No Downloads. Views Total views. Actions Shares. Embeds 0 No embeds. No notes for slide. Leading author Doug Comer covers layering and 3.