The program that created the file random.dat
read by the program in the previous recipe was not written in Java,
but in C. Since the earliest days of the TCP/IP protocol in the
1980s, and particularly on the 4.2 BSD version of Unix, there was an
awareness that not all brands of computers store the bytes within a
word in the same order, and there was a means for dealing with it.
For this early heterogeneous network to function at all, it was
necessary that a 32-bit word be interpreted correctly as a
computer’s network address, regardless of whether it originated
on a PDP-11, a VAX, a Sun workstation, or any other kind of machine
then prevalent (there were no “IBM PC” machines powerful
enough to run TCP/IP at that time). So network byte
order was established, a standard for which bytes go in
which order on the network. And the network byte order macros were
written: ntohl
for network-to-host order for a
long (32 bits), htons
for
host-to-network order for a short (16 bits), and so on. In most Unix
implementations, these C macros live in one of the
Internet header files, although
in some newer systems they have been segregated out into a file like
<machine/endian.h>, as on our OpenBSD
system.
The designers of Java, working at Sun, were well aware of these
issues, and chose to use network byte order in the Java
Virtual Machine. Thus a Java program can
read an IP address from a socket using a
DataInputStream
, or write an integer to disk that
will be read from C using read( )
and the network
byte order macros.
This
C program writes the file
random.dat
read in Section 9.15.
It uses the network byte order macros to make sure that the long
integer (32 bits on most C compilers on the IBM PC) is in the correct
order to be read as an int
in Java.
/* Create the random-access file for the RandomAccessFile example */ #include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <machine/endian.h> const off_t OFFSET = 1234; const char* FILENAME = "random.dat"; const int MODE = 0644; const char* MESSAGE = "Ye have sought, and ye have found! "; int main(int argc, char **argv) { int fd; int java_offset; if ((fd = creat(FILENAME, MODE)) < 0) { perror(FILENAME); return 1; } /* Java's DataStreams etc. are defined to be in network byte order, * so convert OFFSET to network byte order. */ java_offset = htonl(OFFSET); if (write(fd, &java_offset, sizeof java_offset) < 0) { perror("write"); return 1; } if (lseek(fd, OFFSET, SEEK_SET) < 0) { perror("seek"); return 1; } if (write(fd, MESSAGE, strlen(MESSAGE)) != strlen(MESSAGE)) { perror("write2"); return 1; } if (close(fd) < 0) { perror("close!?"); return 1; } return 0; }
The same technique can be used in the other direction, of course, and when exchanging data over a network socket, and anyplace else you need to exchange binary data between Java and C.
18.117.138.104