📄 xdr.nts.ms
字号:
sendsize, recvsize, iohandle, readproc, writeproc) XDR *xdrs; u_int sendsize, recvsize; char *iohandle; int (*readproc)(), (*writeproc)();.DEThe routine.I xdrrec_create() provides an XDR stream interface that allows for a bidirectional,arbitrarily long sequence of records.The contents of the records are meant to be data in XDR form.The stream's primary use is for interfacing RPC to TCP connections.However, it can be used to stream data into or out of normalUNIX files..LPThe parameter.I xdrsis similar to the corresponding parameter described above.The stream does its own data buffering similar to that of standard I/O.The parameters.I sendsizeand.I recvsizedetermine the size in bytes of the output and input buffers, respectively;if their values are zero (0), then predetermined defaults are used.When a buffer needs to be filled or flushed, the routine.I readproc() or.I writeproc() is called, respectively.The usage and behavior of theseroutines are similar to the UNIX system calls.I read() and.I write ().However,the first parameter to each of these routines is the opaque parameter.I iohandle .The other two parameters.I buf ""and.I nbytes )and the results(byte count) are identical to the system routines.If.I xxx is.I readproc() or.I writeproc (),then it has the following form:.DS.ft CW.ft I/* * returns the actual number of bytes transferred. * -1 is an error */.ft CWintxxx(iohandle, buf, len) char *iohandle; char *buf; int nbytes;.DEThe XDR stream provides means for delimiting records in the byte stream.The implementation details of delimiting records in a stream arediscussed in the.I "Advanced Topics"topic below.The primitives that are specific to record streams are as follows:.DS.ft CWbool_txdrrec_endofrecord(xdrs, flushnow) XDR *xdrs; bool_t flushnow;.sp.5bool_txdrrec_skiprecord(xdrs) XDR *xdrs;.sp.5bool_txdrrec_eof(xdrs) XDR *xdrs;.DEThe routine.I xdrrec_endofrecord() .IX xdrrec_endofrecord() "" \fIxdrrec_endofrecord()\fPcauses the current outgoing data to be marked as a record.If the parameter.I flushnowis.I TRUE ,then the stream's.I writeproc will be called; otherwise,.I writeproc will be called when the output buffer has been filled..LPThe routine.I xdrrec_skiprecord() .IX xdrrec_skiprecord() "" \fIxdrrec_skiprecord()\fPcauses an input stream's position to be moved pastthe current record boundary and onto thebeginning of the next record in the stream..LPIf there is no more data in the stream's input buffer,then the routine.I xdrrec_eof() .IX xdrrec_eof() "" \fIxdrrec_eof()\fPreturns.I TRUE .That is not to say that there is no more datain the underlying file descriptor..NH 2\&XDR Stream Implementation.IX "XDR" "stream implementation".IX "stream implementation in XDR".LPThis section provides the abstract data types neededto implement new instances of XDR streams..NH 3\&The XDR Object.IX "XDR" "object".LPThe following structure defines the interface to an XDR stream:.ie t .DS.el .DS L.ft CWenum xdr_op { XDR_ENCODE=0, XDR_DECODE=1, XDR_FREE=2 };.sp.5typedef struct { enum xdr_op x_op; /* \fIoperation; fast added param\fP */ struct xdr_ops { bool_t (*x_getlong)(); /* \fIget long from stream\fP */ bool_t (*x_putlong)(); /* \fIput long to stream\fP */ bool_t (*x_getbytes)(); /* \fIget bytes from stream\fP */ bool_t (*x_putbytes)(); /* \fIput bytes to stream\fP */ u_int (*x_getpostn)(); /* \fIreturn stream offset\fP */ bool_t (*x_setpostn)(); /* \fIreposition offset\fP */ caddr_t (*x_inline)(); /* \fIptr to buffered data\fP */ VOID (*x_destroy)(); /* \fIfree private area\fP */ } *x_ops; caddr_t x_public; /* \fIusers' data\fP */ caddr_t x_private; /* \fIpointer to private data\fP */ caddr_t x_base; /* \fIprivate for position info\fP */ int x_handy; /* \fIextra private word\fP */} XDR;.DEThe.I x_opfield is the current operation being performed on the stream.This field is important to the XDR primitives,but should not affect a stream's implementation.That is, a stream's implementation should not dependon this value.The fields.I x_private ,.I x_base ,and.I x_handyare private to the particularstream's implementation.The field.I x_publicis for the XDR client and should never be used bythe XDR stream implementations or the XDR primitives..I x_getpostn() ,.I x_setpostn()and.I x_destroy()are macros for accessing operations. The operation.I x_inline()takes two parameters:an XDR *, and an unsigned integer, which is a byte count.The routine returns a pointer to a piece ofthe stream's internal buffer.The caller can then use the buffer segment for any purpose.From the stream's point of view, the bytes in thebuffer segment have been consumed or put.The routine may return.I NULL if it cannot return a buffer segment of the requested size.(The.I x_inline() routine is for cycle squeezers.Use of the resulting buffer is not data-portable.Users are encouraged not to use this feature.) .LPThe operations.I x_getbytes()and.I x_putbytes()blindly get and put sequences of bytesfrom or to the underlying stream;they return.I TRUE if they are successful, and.I FALSE otherwise. The routines have identical parameters (replace.I xxx ):.DS.ft CWbool_txxxbytes(xdrs, buf, bytecount) XDR *xdrs; char *buf; u_int bytecount;.DEThe operations.I x_getlong()and.I x_putlong()receive and putlong numbers from and to the data stream.It is the responsibility of these routinesto translate the numbers between the machine representationand the (standard) external representation.The UNIX primitives.I htonl()and.I ntohl()can be helpful in accomplishing this.The higher-level XDR implementation assumes thatsigned and unsigned long integers contain the same number of bits,and that nonnegative integershave the same bit representations as unsigned integers.The routines return.I TRUEif they succeed, and.I FALSE otherwise. They have identical parameters:.DS.ft CWbool_txxxlong(xdrs, lp) XDR *xdrs; long *lp;.DEImplementors of new XDR streams must make an XDR structure(with new operation routines) available to clients,using some kind of create routine..NH 1\&Advanced Topics.IX XDR "advanced topics".LPThis section describes techniques for passing data structures thatare not covered in the preceding sections. Such structures includelinked lists (of arbitrary lengths). Unlike the simpler examplescovered in the earlier sections, the following examples are writtenusing both the XDR C library routines and the XDR data description language. The.I "External Data Representation Standard: Protocol Specification"describes this language in complete detail..NH 2\&Linked Lists.IX XDR "linked lists".LPThe last example in the.I Pointerstopic earlier in this chapter presented a C data structure and its associated XDRroutines for a individual's gross assets and liabilities. The example is duplicated below:.ie t .DS.el .DS L.ft CWstruct gnumbers { long g_assets; long g_liabilities;};.sp.5bool_txdr_gnumbers(xdrs, gp) XDR *xdrs; struct gnumbers *gp;{ if (xdr_long(xdrs, &(gp->g_assets))) return(xdr_long(xdrs, &(gp->g_liabilities))); return(FALSE);}.DE.LPNow assume that we wish to implement a linked list of such information. A data structure could be constructed as follows:.ie t .DS.el .DS L.ft CWstruct gnumbers_node { struct gnumbers gn_numbers; struct gnumbers_node *gn_next;};.sp .5typedef struct gnumbers_node *gnumbers_list;.DE.LPThe head of the linked list can be thought of as the data object;that is, the head is not merely a convenient shorthand for astructure. Similarly the .I gn_next field is used to indicate whether or not the object has terminated. Unfortunately, if the object continues, the .I gn_next field is also the address of where it continues. The link addresses carry no useful information when the object is serialized..LPThe XDR data description of this linked list is described by the recursive declaration of .I gnumbers_list :.ie t .DS.el .DS L.ft CWstruct gnumbers { int g_assets; int g_liabilities;};.sp .5struct gnumbers_node { gnumbers gn_numbers; gnumbers_node *gn_next;};.DE.LPIn this description, the boolean indicates whether there is more datafollowing it. If the boolean is .I FALSE ,then it is the last data field of the structure. If it is .I TRUE ,then it is followed by a gnumbers structure and (recursively) by a .I gnumbers_list .Note that the C declaration has no boolean explicitly declared in it (though the .I gn_next field implicitly carries the information), while the XDR data description has no pointer explicitly declared in it..LPHints for writing the XDR routines for a .I gnumbers_list follow easily from the XDR description above. Note how the primitive .I xdr_pointer() is used to implement the XDR union above..ie t .DS.el .DS L.ft CWbool_txdr_gnumbers_node(xdrs, gn) XDR *xdrs; gnumbers_node *gn;{ return(xdr_gnumbers(xdrs, &gn->gn_numbers) && xdr_gnumbers_list(xdrs, &gp->gn_next));}.sp .5bool_txdr_gnumbers_list(xdrs, gnp) XDR *xdrs; gnumbers_list *gnp;{ return(xdr_pointer(xdrs, gnp, sizeof(struct gnumbers_node), xdr_gnumbers_node));}.DE.LPThe unfortunate side effect of XDR'ing a list with these routinesis that the C stack grows linearly with respect to the number ofnode in the list. This is due to the recursion. The followingroutine collapses the above two mutually recursive into a single,non-recursive one..ie t .DS.el .DS L.ft CWbool_txdr_gnumbers_list(xdrs, gnp) XDR *xdrs; gnumbers_list *gnp;{ bool_t more_data; gnumbers_list *nextp;.sp .5 for (;;) { more_data = (*gnp != NULL); if (!xdr_bool(xdrs, &more_data)) { return(FALSE); } if (! more_data) { break; } if (xdrs->x_op == XDR_FREE) { nextp = &(*gnp)->gn_next; } if (!xdr_reference(xdrs, gnp, sizeof(struct gnumbers_node), xdr_gnumbers)) { return(FALSE); } gnp = (xdrs->x_op == XDR_FREE) ? nextp : &(*gnp)->gn_next; } *gnp = NULL; return(TRUE);}.DE.LPThe first task is to find out whether there is more data or not,so that this boolean information can be serialized. Notice thatthis statement is unnecessary in the .I XDR_DECODE case, since the value of more_data is not known until we deserialize it in the next statement..LPThe next statement XDR's the more_data field of the XDR union. Then if there is truly no more data, we set this last pointer to .I NULL to indicate the end of the list, and return .I TRUE because we are done. Note that setting the pointer to .I NULL is only important in the .I XDR_DECODE case, since it is already .I NULL in the .I XDR_ENCODE and XDR_FREE cases..LPNext, if the direction is .I XDR_FREE ,the value of .I nextp is set to indicate the location of the next pointer in the list. We do this now because we need to dereference gnp to find the location of the next item in the list, and after the next statement the storage pointed to by.I gnp will be freed up and no be longer valid. We can't do this for alldirections though, because in the .I XDR_DECODE direction the value of .I gnp won't be set until the next statement..LPNext, we XDR the data in the node using the primitive .I xdr_reference ()..I xdr_reference() is like .I xdr_pointer() which we used before, but it does notsend over the boolean indicating whether there is more data. We use it instead of .I xdr_pointer() because we have already XDR'd this information ourselves. Notice that the xdr routine passed is not the same type as an element in the list. The routine passed is .I xdr_gnumbers (),for XDR'ing gnumbers, but each element in the list is actually of type .I gnumbers_node .We don't pass .I xdr_gnumbers_node() because it is recursive, and instead use .I xdr_gnumbers() which XDR's all of the non-recursive part. Note that this trick will work only if the .I gn_numbers field is the first item in each element, so that their addresses are identical when passed to .I xdr_reference ()..LPFinally, we update .I gnp to point to the next item in the list. If the direction is .I XDR_FREE ,we set it to the previously saved value, otherwise we can dereference .I gnp to get the proper value. Though harder to understand than the recursive version, this non-recursive routine is far less likelyto blow the C stack. It will also run more efficiently sincea lot of procedure call overhead has been removed. Most lists are small though (in the hundreds of items or less) and the recursive version should be sufficient for them..EQdelim off.EN
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -