When I began my computing career in 1984, most programmers didn't care about network protocols. However, sometime in the 1990s networking became ubiquitous, and now it's hard to imagine using a computer without some form of connectivity. Today the average programmer is more interested in building scalable, distributed applications than implementing floating, semi-transparent, nonrectangular, owner-drawn Coolbars in MFC.Programmers prefer to think in terms of programming models, not network
protocols. Though that's generally a good thing, in this article I'll discuss the Simple Object Access Protocol (SOAP), a network protocol that happens to have no explicit programming model. This doesn't mean that the architects of SOAP (including the author) are out to fundamentally change the way you program. Rather, one of the primary goals of SOAP is to make your existing programs more accessible to a broader range of users. To this end, there is no SOAP API or SOAP Object Request Broker (ORB). Instead, SOAP assumes that you will use as much existing technology as possible. Several major CORBA vendors have committed to support the SOAP protocol in their ORB products. Microsoft has committed to support SOAP in future versions of COM. DevelopMentor has developed reference implementations that make SOAP accessible to any Java-language or Perl programmer on any platform.The guiding principle behind SOAP is to "first invent no new technology." SOAP uses two existing and widely deployed protocols: HTTP and XML. HTTP is SOAP's RPC-style transport, and XML is its encoding scheme. With a few lines of code and an XML parser, HTTP servers such as Microsoft® Internet Information Server (IIS) and Apache instantly become SOAP ORBs. Given the fact that over half of the planet's Web traffic is directed at IIS or Apache, SOAP benefits from the proven engineering and wide availability of these two products. This does not mean, however, that all SOAP requests must be routed through a Web server. Traditional Web servers are just one way to dispatch SOAP requests. Web services like IIS or Apache are sufficient, but by no means necessary for building SOAP-enabled applications.As this article will describe, SOAP simply codifies the use of XML as an HTTP payload. The most common application of SOAP is as a Remote Procedure Call (RPC) protocol. To understand how SOAP works, it is useful to take a brief look into the history of RPC protocols.RPCs Throughout History The two dominant communication models for building distributed applications are message passing (often combined with queuing) and request/response. Message passing systems typically allow any party to send messages at any time. Request/response protocols restrict the communication pattern to request/response pairs. Messaging-based applications are acutely aware that they are communicating with external concurrent processes and require an explicit design style. Request/response-based applications more closely resemble a single-process application, since the application that sends the request is more or less blocked until it receives the response from the second process. This makes request/response communications a natural fit for RPC applications.While both messaging and request/response have their advantages, either one can be implemented in terms of the other. Messaging systems can be built using lower-level request/response protocols. For example, Microsoft Message Queue Server (MSMQ) uses DCE RPC internally for most of its control logic. RPC systems can be built using lower-level messaging systems. MSMQ provides a correlation ID for exactly this purpose. For better or worse, most applications tend to use RPC protocols due to their wider availability, simpler design, and natural mapping to traditional programming techniques.During the 1980s, the two dominant RPC protocols were Sun RPC and DCE RPC. The most popular Sun RPC application is the Network File System (NFS) used by most Unix systems. The most popular DCE RPC application is Windows NT®, which uses the DCE RPC protocol for a number of system services. Both of these protocols proved to be quite functional and adaptable to a wide range of applications. However, as the decade neared an end, the industry's obsession with object-orientation went into full swing, motivating programmers across the globe to forge a marriage between object-oriented languages and RPC-based communications.The 1990s brought Object RPC (ORPC) protocols that attempted to marry object orientation and network protocols. The primary difference between ORPC and the RPC protocols that preceded them was that ORPC codified the mapping of a communication endpoint to a language-level object. Somewhere in the header of each ORPC request was a cookie that the server-side plumbing could use to locate the target object in the server process. Often this cookie was just an index into an array, but other techniques were (and are) often used, such as using symbolic names as keys into a hash table.
Figure 1 ORPC Request and Response Figure 1 shows a typical ORPC request and response message. There are several request header components that are used by the server-side plumbing to dispatch the call. The object endpoint ID is used to locate the target object inside the server process. The interface ID and method ID are used to determine which method to call on the target object. The payload is used to transport the values of any [in] and [in, out] parameters as part of the request (or [out] and [in,out] parameters in the case of a response). Note that optional protocol extensions can appear between the header fields and the payload. This is standard practice in protocol design, as it allows new services to be piggybacked on an ORPC request or response. Most ORPC systems use this area for transmitting additional context information (such as transaction information and causality identifiers). At this time, the two dominant ORPC protocols are DCOM and CORBA's Internet Inter-ORB Protocol (IIOP) flavor of the General Inter-ORB Protocol (GIOP). The request formats from DCOM and IIOP/GIOP are extremely similar, as shown in Figure 2. Both protocols use an object endpoint ID to identify the target object, as well as a method identifier to determine which method to invoke.There are two differences between the protocols worth noting. The primary difference between the two protocols is that with IIOP/GIOP, the interface ID is implicit, since a given CORBA object only implements one interface (although the Object Management Group (OMG) is currently standardizing support for multiple interfaces per object). Another subtle difference between DCOM and IIOP/GIOP requests is the format of parameter values in the payload. In DCOM, the payload is written in a format known as Network Data Representation (NDR). In IIOP/GIOP, the payload is written using Common Data Representation (CDR) format. Both NDR and CDR deal with the differing data representations used on various platforms. However, there are some minor differences between these two formats that make them incompatible with one another.Another key distinction between ORPC and RPC protocols is how communication endpoints are named. In ORPC protocols, some transmissible representation of an ORPC endpoint is needed to communicate object references across the network. In CORBA/IIOP, this representation is called an Interoperable Object Reference (IOR). IORs contain addressing information in a portable format that any CORBA product can resolve to an object endpoint. In DCOM, this representation is called an OBJREF, which combines distributed reference counting with endpoint/object identification. Both CORBA and DCOM provide higher-level mechanisms for finding object endpoints on the network, but at the end of the day these mechanisms all map down to IORs or OBJREFs.Figure 3 shows how an IOR/OBJREF relates to the addressing information found in IIOP/DCOM request messages.
What's Wrong with this Picture?
While DCOM and IIOP are both solid protocols, the industry has not shifted completely to either one. The lack of convergence is partly due to cultural issues. Additionally, the technical applicability of both protocols has been called into question as organizations have tried to standardize on one protocol or the other. The conventional wisdom is that DCOM and CORBA are both reasonable protocols for server-to-server communications. However, both DCOM and IIOP have severe weaknesses for client-to-server communications, especially when the client machines are scattered across the Internet.
DCOM and CORBA/IIOP both rely on single-vendor solutions to use the protocol to maximum advantage. Though both protocols have been implemented on a variety of platforms and products, the reality is that a given deployment needs to use a single-vendor's implementation. In the case of DCOM, this means every machine runs Windows NT. (Although DCOM has been ported to other platforms, it has only achieved broad reach on Windows®.) In the case of CORBA, this means that every machine runs the same ORB product. Yes, it is possible to get two CORBA products to call one another using IIOP. However, many of the higher-level services (such as security and transactions) are not generally interoperable at this time. Additionally, any vendor-specific optimizations for same-machine communications are very unlikely to work unless all applications are built against the same ORB product.
DCOM and CORBA/IIOP both rely on a closely administered environment. The odds of two random computers being able to successfully make DCOM or IIOP calls out of the box are fairly low. This is especially true when security is involved. While it is possible to write a shrink-wrap application that can use DCOM or IIOP successfully, doing so requires much more attention to detail than the typical sockets-based application. This is especially applicable to the unglamorous but necessary task of configuration/installation management.
DCOM and CORBA/IIOP both rely on fairly high-tech runtime environments. While in-process COM is deceptively simple, building the COM/DCOM remoting plumbing is definitely not a weekend project. IIOP is a simpler protocol to implement than DCOM, but both protocols have their fair share of arcane rules dealing with data alignment, type information, and bit twiddling. This makes it difficult for the average programmer to simply cruft up a CORBA or DCOM call without the benefit of an ORB product or OLE32.DLL.
Perhaps the most damning limitation of DCOM and CORBA/IIOP is their inability to work in Internet scenarios. In the case of DCOM, it is unlikely that the average user's Bondi-blue iMac or cheap PC clone running Windows 95 will be able to perform domain-based authentication with your servers. Worse, if a firewall or proxy server separates the client and server machines, the likelihood of either IIOP or DCOM packets getting through is extremely low due to the HTTP bias of most Internet connectivity technology. While vendors like Microsoft, Iona, and Visigenic have all built tunneling technology, these products tend to be very sensitive to configuration mistakes and are not interoperable.
None of these issues impact the use of DCOM or IIOP within a server farm. The number of host machines in a server farm is relatively small (hundreds, not tens of thousands), which marginalizes the cost of DCOM's ping-based lifecycle management. Chances are that all of the host machines in the server farm are under a common administrative domain, which makes consistent configuration quite likely. The relatively small number of machines also helps to keep the costs of using commercial ORB products under control, as a smaller number of ORB licenses are needed. If IIOP is only spoken within the server farm, a smaller number of ORB licenses are needed. Finally, it is likely that all of the host machines in a server farm will have direct IP connectivity, removing the firewall-related problems of DCOM and IIOP.
HTTP as a Better RPC
It is common practice to use DCOM or CORBA within a server farm, but to use HTTP to enter the server farm from a client machine. HTTP is a very RPC-like protocol that is simple, widely deployed, and more likely to function in the face of firewalls than any other protocol known to man. HTTP requests are typically handled by Web server software (such as IIS and Apache), but an increasing number of application server products are supporting HTTP as a native protocol in addition to DCOM and IIOP.
Like DCOM and IIOP, HTTP layers request/response communications over TCP/IP. An HTTP client connects to an HTTP server using TCP. The standard port number used in HTTP is port 80, but any port can be used. After establishing the TCP connection, the client can send an HTTP request message to the server. The server then sends an HTTP response message back to the client after processing the request. Both the request and response messages can contain arbitrary payload information, typically tagged with the Content-Length and Content-Type HTTP headers. The following is a legal HTTP request message: POST /foobar HTTP/1.1
Host: 209.110.197.12
Content-Type: text/plain
Content-Length: 12
Hello, World
You may have noticed that the HTTP headers are just plain text. This makes it easy to diagnose HTTP problems using a packet sniffer or text-based Internet tools like telnet. The text-based nature of HTTP also makes it easily adaptable to low-tech programming environments popular in Web development.
The first line of an HTTP request contains three components: the HTTP method, the Request-URI, and the protocol version. In the previous example, these correspond to POST, /foobar, and HTTP/1.1, respectively. The Internet Engineering Task Force (IETF) has standardized a fixed number of HTTP methods. GET is the HTTP method used to surf the Web. POST is the most commonly used HTTP method for building applications. Unlike GET, POST allows arbitrary data to be sent from the client to the server. The Request-URI (Uniform Resource Identifier) is simply a token used by the HTTP server software to identify the target of the request (much like an IIOP/GIOP object_key or a DCOM IPID). For more information on URIs see the sidebar, "URIs, URLs, and URNs." The protocol version in this example is HTTP/1.1, which indicates that the rules of RFC 2616 are to be observed. HTTP/1.1 added several features to its predecessor (HTTP/1.0), including support for chunked data transfer and explicit support for keeping TCP connections alive across HTTP requests.
The third and fourth lines of the request specify the size and type of the request payload. The Content-Length header specifies the number of bytes of payload information. The Content-Type identifier specifies the syntax of the payload information as a MIME type. HTTP (like DCE) allows the client and server to negotiate the transfer syntax used to encode information. Most DCE applications use NDR. Most Web applications use text/html or other text-based syntaxes.
Pay attention to the blank line between the Content-Length header and the request payload in the code sample. Individual HTTP headers are delimited by a carriage-return/line-feed sequence, and the headers are delimited from the payload using an extra carriage-return/line-feed sequence. The request then contains raw bytes whose syntax and length are identified by the Content-Length and Content-Type HTTP headers. In this example, the content is the 12-byte plain text string "Hello, World".
After processing the request, the HTTP server is expected to send an HTTP response back to the client. The response must contain a status code indicating the outcome of the request. The response can also contain arbitrary payload information much like the request message. The following is an HTTP response message: 200 OK
Content-Type: text/plain
Content-Length: 12
dlroW ,olleH
In this case, the server returned a status code of 200, which is the standard success code for HTTP. Had the server been unable to decode the request, it would have returned the following response instead of the one shown previously: 400 Bad Request
Content-Length: 0
Had the HTTP server decided that requests for the target URI should be temporarily redirected to a different URI, the following response would have been returned: 307 Temporarily Moved
Location: http://209.110.197.44/foobar
Content-Length: 0
This response informs the client that the request could be satisfied by retransmitting it to the endpoint identified in the Location HTTP header.
All of the standardized status codes and headers are documented in RFC 2616. Very few of them relate directly to SOAP users, with one notable exception. In HTTP/1.1, the underlying TCP connection is reused across multiple request/response pairs. The HTTP Connection header allows either the client or the server to close the underlying connection. By adding the following HTTP header to a request or response, both sides are required to shut down their TCP connections after processing the request. Connection: close
To keep the TCP connection alive when interoperating with HTTP/1.0 software, it is recommended that the sender add the following HTTP header to each request or response: Connection: Keep-Alive
This header disabled the default HTTP/1.0 behavior of resetting the TCP connection after each response.
One of the advantages of HTTP is its wide deployment and acceptance. Figure 4 shows a simple Java-language program that sends the request shown previously and parses out the resultant string from the response. The following is a simple C program that uses CGI to read the string from the HTTP request and write the reversed version back out through the HTTP response.
#include
int main(int argc, char **argv) {
char buf[4096];
int cb = read(0, buf, sizeof(buf));
buf[cb] = 0;
strrev(buf);
printf("200 OK\r\n");
printf("Content-Type: text/plain\r\n");
printf("Content-Length: %d\r\n", cb);
printf("\r\n");
printf(buf);
return 0;
}
Figure 5 shows a more modern version of the server implemented as a Java-language servlet to avoid the overhead of CGI's process-per-request model.In general, CGI is the way to write HTTP server code for the lowest common denominator. Virtually every HTTP server product provides a much more efficient mechanism to get your code to process an HTTP request. IIS provides ASP and ISAPI as the native mechanisms for writing HTTP code. Apache allows you to write modules in C or Perl that run inside the Apache daemon. Most application server products allow you to write Java-language servlets, COM components, EJB session beans, or CORBA servants based on the Portable Object Adapter (POA) interface.XML as a Better NDR HTTP is a fairly functional RPC protocol that provides most—if not all—of the functionality of IIOP or DCOM in terms of framing, connection management, and support for serialized object references. (URLs are surprisingly close to IORs and OBJREFs in functionality.) What HTTP lacks is a single standard format for representing the parameters of an RPC call. This is where XML comes in.Like NDR and CDR, XML is a platform-neutral data representation protocol. XML allows data to be serialized into a transmissible form that is easily decoded on any platform. XML has the following characteristics that differentiate it from NDR and CDR:
There is a plethora of XML encoding and decoding software that is available for virtually every programming environment and platform.
XML is text-based and fairly easy to handle from low-tech programming environments.
It's an extremely flexible format that can easily be extended in unambiguous ways.To support extensibility, every element and attribute in XML has a namespace URI associated with it. This URI is specified using the xmlns attribute. Consider the following XML document:
This is a comment!!
The namespace URI for the
This is a comment!!
The latter form is considerably easier to author, especially if many namespace URIs are in use. XML also supports typed data representation. The emerging XML Schema specification standardizes a vocabulary for describing XML data types. The following is an XML Schema description of the
This XML Schema definition states that the XML namespace urn:schemas-develop-com:StringProcs contains an element named
Additional mechanisms for linking XML document instances to XML Schema descriptions are being standardized at the time of this writing.HTTP + XML = SOAP SOAP codifies the use of XML as an encoding scheme for request and response parameters using HTTP as a transport. SOAP deals in a small number of abstractions. In particular, a SOAP method is simply an HTTP request and response that complies with the SOAP encoding rules. A SOAP endpoint is simply an HTTP-based URL that identifies a target for method invocation. Like CORBA/IIOP, SOAP does not require that a specific object be tied to a given endpoint. Rather, it is up to the implementor to decide how to map the object endpoint identifier onto a server-side object.A SOAP request is an HTTP POST request. SOAP requests must use the text/xml content-type. Additionally, they must contain a Request-URI as per the HTTP specification. How the server interprets this Request-URI is implementation-specific, but many implementations are likely to use it to map to either a class or an object. A SOAP request must also indicate the method to be invoked using the SOAPMethodName HTTP header. The SOAPMethodName header is simply the application-specific method name scoped by a URI using a # character as a delimeter:
SOAPMethodName: urn:strings-com:IString#reverse
This header indicates that the method name is reverse and that the scoping URI is urn:strings-com:IString. The namespace URI that scopes the method name in SOAP is functionally equivalent to the interface ID that scopes a method name in DCOM or IIOP.The HTTP payload of a SOAP request is simply an XML document that contains the values of the [in] and [in,out] parameters of the method. These values are encoded as child elements of a distinguished call element that shares the method name and namespace URI of the SOAPMethodName HTTP header. The call element must appear inside the standard SOAP
POST /string_server/Object17 HTTP/1.1
Host: 209.110.197.2
Content-Type: text/xml
Content-Length: 152
SOAPMethodName: urn:strings-com:IString#reverse
<-body>
<-/body>
The SOAPMethodName header must match the first child element under the <-body> element, otherwise the call must be rejected. This allows firewall administrators to reliably filter calls to a particular method without parsing the XML.The SOAP response format is similar to that of the request. The response payload will contain the [out] and [in,out] parameters of the method encoded as child elements of a distinguished response element. This element's name is the same as the request's call element catenated with the Response suffix. The following is a minimal SOAP response to the request shown earlier:
200 OK
Content-Type: text/xml
Content-Length: 162
<-body>
<-/body>
In this case, the response element is named reverseResponse, which is simply the method name followed by the Response suffix. Also, note that the SOAPMethodName HTTP header is absent. This header is only required in the request message, not in the response.<-/div><-/div>
0 komentar:
Post a Comment