Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 84 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
84
Dung lượng
6,76 MB
Nội dung
sin.sin_addr.s_addr = INADDR_ANY; sin.sin_port = htons(port); if (bind(sock_descriptor, (struct sockaddr *)&sin, sizeof(sin)) == -1) { perror(“call to bind”); exit(1); } if (listen(sock_descriptor, 20) == -1) { perror(“call to listen”); exit(1); } while(1) { temp_sock_descriptor = accept(sock_descriptor, (struct sockaddr *)&pin, &address_size); if (temp_sock_descriptor == -1) { perror(“call to accept”); exit(1); } if (recv(temp_sock_descriptor, buf, 4000, 0) == -1) { perror(“call to recv”); exit(1); } // this calls the work function passed // to the class constructor: work_func(buf, temp_buf, 16384); // the virtual function doWork has filled in the // data to be returned to the client in ‘temp_buf’: len = strlen(temp_buf); if (send(temp_sock_descriptor, temp_buf, len, 0) == -1) { perror(“call to send”); exit(1); } close(temp_sock_descriptor); } } The Server class constructor uses calls to socket, bind, listen, accept, and recv to set up socket connections to remote client objects. The main processing loop in the construc- tor calls the my_work function with each new service request, waits for my_work to place Interprocess Communication and Network Programming P ART III 338 2772316072 CH23 7/26/99 2:21 PM Page 338 return data in the temp_buf buffer, then returns data to the client object. The following section contains an example of writing a work function, creating a server object, and handling client requests. Testing the C++ Client/Server Classes The Server class contains as private data a pointer to a work function that is called to process each client request. The following simple test program defines a simple work function that returns a message to the client, and then creates a server object to handle remote client requests. #include <iostream.h> #include “Server.hxx” void my_work_func(char *command, char *return_buffer, int return_buffer_size) { cout << “entering my_work_func(“ << command << “, )\n”; sprintf(return_buffer,”overriden my_work_func. %s”, command); } void main() { Server * server = new Server(my_work_func); // default to port=8080 } In this example, you could also have created a server object directly instead of using the new operator: Server server(my_work_func); The following short program can be used to test the Client class: #include <iostream.h> #include “Client.hxx” void main() { // default to host=”127.0.0.1”, port=8080 // in the CLient constructor call: Client * client = new Client();char * s; char buf[100]; sprintf(buf,”This is a test”); s = client->getResponseFromServer(buf); cout << “Server response: “ << s << “\n”; sprintf(buf,”This is a another test”); s = client->getResponseFromServer(buf); cout << “Server response: “ << s << “\n”; delete client; // closes the socket connection } A C++ Class Library for TCP Sockets C HAPTER 23 339 23 A C++ CLASS LIBRARY FOR TCP SOCKETS 2772316072 CH23 7/26/99 2:21 PM Page 339 The following output is seen when running the test_client.cpp sample program: markw@colossus:/home/markw/MyDocs/LinuxBook/src/IPC/C++ > make g++ -c Client.cpp g++ -o test_client test_client.cpp Client.o g++ -c Server.cpp g++ -o test_server test_server.cpp Server.o markw@colossus:/home/markw/MyDocs/LinuxBook/src/IPC/C++ > test_client Sending message ‘This is a test’ to server sent message wait for response Response from server: overriden my_work_func. This is a test Server response: overriden my_work_func. This is a test Sending message ‘This is a another test’ to server sent message wait for response Response from server: overriden my_work_func. This is a another test Server response: overriden my_work_func. This is a another test markw@colossus:/home/markw/MyDocs/LinuxBook/src/IPC/C++ > The following output is seen when running the test_server.cpp sample program: markw@colossus:/home/markw/MyDocs/LinuxBook/src/IPC/C++ > test_server entering my_work_func(This is a test, ) entering my_work_func(This is a another test, ) Summary This chapter hopefully serves two purposes: introducing some readers to C++ and pro- viding an example of wrapping socket programs in C++ classes to make using sockets easier. This chapter was not a tutorial on C++; interested readers should search the Internet for “C++ programming tutorial” and invest some time in learning the language. C is a great language for writing small programs with a small number of programmers, but C++ is a much better language for large projects. Interprocess Communication and Network Programming P ART III 340 2772316072 CH23 7/26/99 2:21 PM Page 340 IN THIS CHAPTER • Comparing libc5 and libc6 342 • Library Tools 343 • Writing and Using Static Libraries 346 • Writing and Using Shared Libraries 352 • Using Dynamically Loaded Shared Objects 354 24 CHAPTER Using Libraries by Kurt Wall 2872316072 CH24 7/26/99 2:20 PM Page 341 This chapter looks at creating and using programming libraries, collections of code that can be used (and reused) across multiple software projects. First, though, we’ll examine some of the issues surrounding the two versions of the Linux C library (yes, there are two fundamentally incompatible versions out there). Libraries are a classic example of software development’s Holy Grail, code reuse. They collect commonly used programming routines into a single location. The system C library is an example. It contains hundreds of frequently used routines, such as the output function printf() and the input function getchar() that would be tedious to rewrite each time you create a new program. Beyond code reuse and programmer convenience, however, libraries provide a great deal of utility code, such as functions for network pro- gramming, graphics handling, data manipulation, and, most importantly, system calls. Comparing libc5 and libc6 Before delving into library usage proper, you need to know about the two competing C libraries, libc5 and libc6, also known as glibc2. libc5 and libc6 do not actually compete, but the Linux world is moving from the old, very Linux-specific libc5 (some systems use glibc1 as a synonym) to the more general, faster, and much more standards- compliant and extensible libc6. libc5 evolved in parallel with Linux—as Linux matured, the original GNU C library was modified to coincide with kernel changes. While this made for the C library tightly integrated with Linux, it also made the basic library difficult to maintain for other operat- ing systems using GNU’s C library. In addition, libc5’s heavy reliance on Linux’s kernel headers created an unwise set of dependencies. As Linus made changes to kernel head- ers, these changes had to be regressed into the C library, creating maintenance problems for Linus, the kernel development team, and the C library maintainer. It also slowed ker- nel development. Conversely, as the C library changed, these changes had to be incorpo- rated into the kernel. In fact, some parts of the kernel relied on undocumented, and thus subject to change, features of the C library and, in some cases, outright bugs. This situation changed dramatically in 1997 with the first release of libc6/glibc2. Almost all of its dependencies on the Linux kernel headers were eliminated, in addition to the following changes: • The new library was made thread-safe. • An easily extensible scheme for handling name databases was added. Interprocess Communication and Network Programming P ART III 342 2872316072 CH24 7/26/99 2:20 PM Page 342 • The math library was corrected and in many cases speeded up. • Standards compliance, such as with POSIX.1, POSIX.2, ISO/ANSI C, and XPG4.2 became a reality, or much closer to it. The price for these enhancements and improvements, however, was introducing funda- mental incompatibilities between libc5 and libc6. Until all Linux distributions move to libc6, Linux users have to be aware of and deal with this incompatibility. Distribution builders, such as Caldera and Red Hat, have to provide compatibility libraries to enable users to run programs that depend on one or the other of the library versions while simul- taneously basing their distributions on the other library. Worse still, because the C library is so pervasive and fundamental on any Linux (or UNIX) system, upgrading from libc5 to libc6 is a difficult undertaking and, if done incorrectly or carelessly, can render a sys- tem unusable. “What’s your point?” I hear you asking. There are several. First, if you are in the market for a new Linux distribution, you can finesse the whole upgrade issue by using a libc6- based distribution. Secondly, if you are a developer, you have to decide whether you will support libc5, libc6, or both. Finally, the entire discussion provides an excellent object lesson in software development, highlighting in international orange the importance of good design and the far-reaching impact of interface changes in core software compo- nents. The lesson is simply that thoughtful software design will at least attempt to pro- vide a general, extensible public interface and minimize the necessity for changes that will introduce core incompatibilities. Library Tools Before jumping into library creation and usage, this section takes a quick tour of the tools you will need to create, maintain, and manage programming libraries. More detailed information can be found in the manual pages and info documents for each of the commands and programs discussed in the following sections. Understanding the nm Command The nm command lists all of the symbols encoded in an object or binary file. One use would be to see what function calls a program makes. Another might be to see if a library or object files provides a needed function. nm uses the following syntax: nm [options] file nm lists the symbols stored in file. Table 24.1 describes useful options for nm. Using Libraries C HAPTER 24 343 24 USING LIBRARIES 2872316072 CH24 7/26/99 2:20 PM Page 343 Table 24.1 nm OPTIONS Option Description -C|-demangle Convert symbol names into user-level names, especially useful for making C++ function names readable. -s|-print-armap When used on archive (.a) files, also print the index that maps symbol names to the modules or member names in which the symbol is defined. -u|-undefined-only Only display undefined symbols, symbols defined external- ly to the file being examined. -l|-line-numbers Use debugging information to print the line number where each symbol is defined, or the relocation entry if the symbol is undefined. Understanding the ar Command The ar command uses the following syntax: ar {dmpqrtx} [member] archive files ar creates, modifies, or extracts archives. It is most commonly used to create static libraries—files that contain one or more object files, called members, of subroutines in precompiled format. ar also creates and maintains a table that cross-references symbol names to the members in which they are defined. Table 24.2 describes the most common- ly used ar options. Table 24.2 ar OPTIONS Option Description -c Create archive if it doesn’t exist from files, suppressing the warning ar would emit if archive doesn’t exist. -s Create or update the map linking symbols to the member in which they are defined. -r Insert files into the archive, replacing any existing members whose name matches that being added. New members are added at the end of the archive. -q Add files to the end of archive without checking for replacements. Interprocess Communication and Network Programming P ART III 344 2872316072 CH24 7/26/99 2:20 PM Page 344 Understanding the ldd Command The nm command lists the symbols defined in an object file, but unless you know what library defines which functions, ldd is much more useful. ldd lists the shared libraries that a program requires in order to run. Its syntax is: ldd [options] file ldd prints the names of the shared libraries required by file. For example, on my sys- tem, the mail client mutt requires five shared libraries, as illustrated below: $ ldd /usr/bin/mutt libnsl.so.1 => /lib/libnsl.so.1 (0x40019000) libslang.so.1 => /usr/lib/libslang.so.1 (0x4002e000) libm.so.6 => /lib/libm.so.6 (0x40072000) libc.so.6 => /lib/libc.so.6 (0x4008f000) /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) Table 24.3 describes some of ldd’s useful options. Table 24.3 ldd OPTIONS Option Description -d Perform relocations and report any missing functions -r Perform relocations for both function and data objects and report any missing functions or data objects Using Libraries C HAPTER 24 345 24 USING LIBRARIES TIP Given an archive created with the ar command, you can speed up access to the archive by creating an index to the archive. Ranlib does precisely this, storing the index in the archive file itself. ranlib’s syntax is: ranlib [-v|-V] file This generates a symbol map in file. It is equivalent to ar -s file. 2872316072 CH24 7/26/99 2:20 PM Page 345 Understanding ldconfig The ldconfig command uses the following syntax: ldconfig [options] [libs] ldconfig determines the runtime links required by shared libraries that are located in /usr/lib and /lib, specified in libs on the command-line, and stored in /etc/ld.so.conf. ldconfig works in conjunction with ld.so, the dynamic linker/loader, to create and maintain links to the most current versions of shared libraries. Table 24.4 describes typically used options; a bare ldconfig updates the cache file. Table 24.4 ldconfig OPTIONS Option Description -p Merely print the contents of /etc/ld.so.cache, the current list of shared libraries about which ld.so knows. -v Verbosely update /etc/ld.so.cache, listing each library’s version number, the directory scanned, and any links that are created or updated. Environment Variables and Configuration Files The dynamic linker/loader ld.so uses two environment variables. The first is $LD_LIBRARY_PATH, a colon-separated list of directories in which to search for shared libraries at runtime. It is similar to the $PATH environment variable. The second variable is $LD_PRELOAD, a whitespace-separated list of additional, user-specified, shared libraries to be loaded before all others. This can be used to selectively override functions in other shared libraries. ld.so also uses two configuration files whose purposes parallel the environment vari- ables mentioned in the preceding paragraph. /etc/ld.so.conf is a list of directories that the linker/loader should search for shared libraries in addition to the standard directories, /usr/lib and /lib. /etc/ld.so.preload is a disk-based version of the $LD_PRELOAD environment variable: it contains a whitespace-separated list of shared libraries to be loaded prior to executing a program. Writing and Using Static Libraries Static libraries (and shared libraries, for that matter) are files that contain object files, called modules or members, of reusable, precompiled code. They are stored in a special Interprocess Communication and Network Programming P ART III 346 2872316072 CH24 7/26/99 2:20 PM Page 346 format along with a table or map linking symbol names to the members in which the symbols are defined. The map speeds up compilation and linking. Static libraries are typ- ically named with a .a (for archive) extension. To use library code, include its header file in your source code and link against the library. For example, consider Listing 24.1, a header file for a simple error-handling library, and Listing 24.2, the corresponding source code. Listing 24.1 liberr.h 1 /* 2 * liberr.h 3 * Declarations for simple error-handling library 4 * Listing 24.1 5 */ 6 #ifndef _LIBERR_H 7 #define _LIBERR_H 8 9 #include <stdarg.h> 10 11 #define MAXLINELEN 4096 12 13 /* 14 * Print an error message to stderr and return to caller 15 */ 16 void err_ret(const char *fmt, ); 17 18 /* 19 * Print an error message to stderr and exit 20 */ 21 void err_quit(const char *fmt, ); 22 23 /* 24 * Print an error message to logfile and return to caller 25 */ 26 void log_ret(char *logfile, const char *fmt, ); 27 28 /* 29 * Print a error message to logfile and exit 30 */ 31 void log_quit(char *logfile, const char *fmt, ); 32 33 /* 34 * Print an error message and return to caller 35 */ 36 void err_prn(const char *fmt, va_list ap, char *logfile); 37 38 #endif _LIBERR_H Using Libraries C HAPTER 24 347 24 USING LIBRARIES 2872316072 CH24 7/26/99 2:20 PM Page 347 [...]... *logfile, const char *fmt, ) { va_list ap; va_start(ap, fmt); err_prn(fmt, ap, logfile); va_end(ap); exit(1); 2872316072 CH24 7/26/99 2:20 PM Page 349 Using Libraries CHAPTER 24 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 349 } extern void err_prn(const char *fmt, va_list ap, char *logfile) { int save_err; char buf[MAXLINELEN]; FILE *plf; save_err = errno; /* value caller... addresses Table 25. 2 shows the names given to the individual bits in these three registers Table 25. 3 shows the functions of each bit Table 25. 2 PARALLEL PORT PROGRAMMING INTERFACE Register Address D7 D6 D5 D4 D3 D2 D1 D0 Read Write Data base+0 D7 D6 D5 D4 D3 D2 D1 D0 Yes Yes Status base+1 S7 S6 S5 S4 S3 S2 S1 S0 Yes No Control base+2 C7 C6 C5 C4 C3 C2 C1 C0 Yes Yes 25 DEVICE DRIVERS 2972316072 CH 25 7/26/99... the test program using this command line: $ gcc -g errtest.c -o errtest -L -lerr 24 USING LIBRARIES 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 351 2872316072 CH24 7/26/99 2:20 PM Page 352 352 Interprocess Communication and Network Programming PART III As discussed in Chapter 3, “GNU cc,” -L tells the linker to look in the current directory... Communication and Network Programming PART III Table 25. 3 PARALLEL PORT HARDWARE INTERFACE Bit Signal Pin D0 Data bit 0 2 D1 Data bit 1 3 D2 Data bit 2 4 D3 Data bit 3 5 D4 Data bit 4 6 D5 Data bit 5 7 D6 Data bit 6 8 D7 Data bit 7 9 S3+ -Error 15 S4+ +Select 13 S5+ +PaperOut 12 S6+ -Ack 10 S7- +Busy 11 C0- -Strobe 1 C1- -AutoFeed 14 C2+ -Init 16 C3- +SelectIn 17 C4 IRQ Enable none C5 Output Enable none... the desired position, keeping the winding(s) energized 2972316072 CH 25 7/26/99 2:19 PM Page 3 65 Device Drivers CHAPTER 25 FIGURE 25. 1 A stepper motor driver circuit PC Parallel Port Pins 1K TIP120 Motor 0 Phase A 2 1K TIP120 3 V+ V+ Motor 0 Phase A* V+ N N S S 1K N S TIP120 Motor 0 Phase B 4 V+ 1K 3 65 V+ TIP120 V+ Motor 0 Phase B* 5 Half Step 0 1K 1K TIP120 Half Step 1 TIP120 Motor 1 Phase A 6 7 V+...2872316072 CH24 7/26/99 2:20 PM Page 348 348 Interprocess Communication and Network Programming PART III Listing 24.2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 liberr.c /* * liberr.c * Implementation of error-handling library * Listing 24.2 */ #include /* for... command line used to compile Listing 24.4 was: $ gcc -g -Wall dltest.c -o dltest -ldl 24 USING LIBRARIES 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 dltest.c 2872316072 CH24 7/26/99 2:20 PM Page 358 358 Interprocess Communication and Network Programming PART III As you can see, we neither link against liberr nor include liberr.h in the source code All... Page 350 350 Interprocess Communication and Network Programming PART III To create a static library, the first step is compiling your code to object form: $ gcc -H -c liberr.c -o liberr.o Next, use the ar utility to create an archive: $ ar rcs liberr.a liberr.o If all went well, the static library liberr.a was created The output of nm should prove instructive: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16... 18,19,20,21,22,23,24, 25 S0 S1 S2 C6 C7 None A negative sign in the first column indicates that there is an inverter between the computer and the port A negative sign in the second column means that this line is considered active low when interfacing to a printer Table 25. 4 shows the stepper motor connections to parallel port signals 2972316072 CH 25 7/26/99 2:19 PM Page 369 Device Drivers CHAPTER 25 Table 25. 4 369... Motor 0, Phase B* D3 D3 5 Motor 1, Phase A D4 D4 6 Motor 1, Phase A* D5 D5 7 Motor 1, Phase B D6 D6 8 Motor 1, Phase B* D7 D7 9 Motor 2, Phase A Strobe C0* 1 Motor 2, Phase A* AutoLF C1* 14 Motor 2, Phase B Init C2 16 Motor 2, Phase B* SelectIn C3* 17 Motor 0, Low limit Select S4 13 Motor 1, Low limit PaperEnd S5 12 Motor 2, Low limit Busy S7* 11 All motors, high limit Error* S3 15 External Timer Ack* . Network Programming P ART III 348 2872316072 CH24 7/26/99 2:20 PM Page 348 50 } 51 52 extern void err_prn(const char *fmt, va_list ap, char *logfile) 53 { 54 int save_err; 55 char buf[MAXLINELEN]; 56 . libc6. libc5 evolved in parallel with Linux as Linux matured, the original GNU C library was modified to coincide with kernel changes. While this made for the C library tightly integrated with Linux, . errtest.c Interprocess Communication and Network Programming P ART III 350 2872316072 CH24 7/26/99 2:20 PM Page 350 3 * Test program for error-handling library 4 * Listing 24.3 5 */ 6 7 #include <stdio.h> 8