zoukankan      html  css  js  c++  java
  • Notes for Advanced Linux Programming 5. Interprocess Communication

    5. Interprocess Communication

    • Five types of interprocess communication:
    • Shared memory permits processes to communicate by simply reading and writing to a specified memory location.
    • Mapped memory is similar to shared memory, except that it is associated with a file in the filesystem.
    • Pipes permit sequential communication from one process to a related process.
    • FIFOs are similar to pipes, except that unrelated processes can communicate because the pipe is given a name in the filesystem.
    • Sockets support communication between unrelated processes even on different computers.

    5.1 Shared Memory

    • Shared memory is the fastest form of interprocess communication because all processes share the same piece of memory.
    • The kernel does not synchronize accesses to shared memory, you must provide your own synchronization.
    • To use a shared memory segment, one process must allocate the segment.
    • The process desiring to access the segment must attach the segment.
    • After finishing using the segment, each process detaches the segment.
    • At some point, one process must deallocate the segment.
    • All shared memory segments are allocated as integral multiples of the system’s page size (4KB).

    5.1.1. Allocation

    • A process allocates a shared memory segment using shmget
    • The first parameter is an integer key for the segment.
    • Different processes can access the same shared segment by specifying the same key value.
    • Using IPC_PRIVATE as the key value guarantees that a brand new memory segment is created.
    • For multiple processes to use a shared segment, they must make arrangements to use the same key.
    • The second parameter specifies the number of bytes in the segment.
    • The third parameter is the bitwise or of flag values
    • IPC_CREAT: A new segment should be created.
    • IPC_EXCL: This flag is always used with IPC_CREAT. It will causes shmget to fail if a segment key is specified that already exists.
    • Mode flags: This value is made of 9 bits indicating permissions granted to owner, group, and world to control access to the segment.

    5.1.2. Attachment and Detachment

    • To make the shared memory segment available, a process must use shmat:
    • The first argument is the shared memory segment identifier SHMID returned by shmget.
    • The second argument is a pointer that specifies where in your process’s address space you want to map the shared memory.
    • If you specify NULL, Linux will choose an available address.
    • The third argument is a flag:
    • SHM_RND indicates that the address specified for the second parameter should be rounded down to a multiple of the page size.
    • SHM_RDONLY indicates that the segment will be only read, not written.
    • It returns the address of the attached shared segment.
    • The segment can be detached using shmdt.
    • Pass it the address returned by shmat.
    • If the segment has been deallocated and this was the last process using it, it is removed.
    • Calls to exit and any of the exec family automatically detach segments.

    5.1.3. Controlling and Deallocating Shared Memory

    • The shmctl call returns information about a shared memory segment and can modify it.
    • The first parameter is a shared memory segment identifier.
    • To obtain information about a shared memory segment, pass IPC_STAT as the second argument and a pointer to a struct shmid_ds.
    • To remove a segment, pass IPC_RMID as the second argument, and pass NULL as the third argument
    • Each shared memory segment should be explicitly deallocated using shmctl when you’re finished with it.
    • Invoking exit and exec detaches memory segments but does not deallocate them.

    #include <stdio.h>

    #include <sys/shm.h>

    #include <sys/stat.h>

    int main ()

    {

        int segment_id;

        char* shared_memory;

        struct shmid_ds shmbuffer;

        int segment_size;

        const int shared_segment_size = 0x6400;

        /* Allocate a shared memory segment. */

        segment_id = shmget (IPC_PRIVATE, shared_segment_size, IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);

        /* Attach the shared memory segment. */

        shared_memory = (char*) shmat (segment_id, 0, 0);

        printf (“shared memory attached at address %p\n”, shared_memory);

        /* Determine the segment’s size. */

        shmctl (segment_id, IPC_STAT, &shmbuffer);

        segment_size = shmbuffer.shm_segsz;

        printf (“segment size: %d\n”, segment_size);

        /* Write a string to the shared memory segment. */

        sprintf (shared_memory, “Hello, world.”);

        /* Detach the shared memory segment. */

        shmdt (shared_memory);

        /* Reattach the shared memory segment, at a different address. */

        shared_memory = (char*) shmat (segment_id, (void*) 0x5000000, 0);

        printf (“shared memory reattached at address %p\n”, shared_memory);

        /* Print out the string from shared memory. */

        printf (“%s\n”, shared_memory);

        /* Detach the shared memory segment. */

        shmdt (shared_memory);

        /* Deallocate the shared memory segment. */

        shmctl (segment_id, IPC_RMID, 0);

        return 0;

    • The ipcs command provides information on interprocess communication facilities.
    • Use the -m flag to obtain information about shared memory.

    % ipcs -m

    ------ Shared Memory Segments --------

    key shmid owner perms bytes nattch status

    0x00000000 1627649 user 640 25600 0

    • The ipcrm command can be used to remove it.

    % ipcrm shm 1627649

    [liuchao@localhost ~]$ ipcs

    ------ Shared Memory Segments --------

    key shmid owner perms bytes nattch status

    0x00000000 196608 liuchao 600 393216 2 dest

    0x764867bd 65537 liuchao 600 1 0

    0x2c0056d5 98306 liuchao 600 1 0

    0x500e7827 131075 liuchao 600 1 0

    0x20e0f21d 163844 liuchao 600 1 0

    0x00000000 229381 liuchao 600 393216 2 dest

    0x00000000 262150 liuchao 600 393216 2 dest

    0x00000000 294919 liuchao 600 393216 2 dest

    0x00000000 327688 liuchao 600 393216 2 dest

    0x00000000 360457 liuchao 600 393216 2 dest

    0x00000000 393226 liuchao 600 393216 2 dest

    0x00000000 425995 liuchao 600 393216 2 dest

    0x00000000 458764 liuchao 600 393216 2 dest

    0x00000000 491533 liuchao 600 393216 2 dest

    0x00000000 557070 liuchao 600 393216 2 dest

    0x00000000 589839 liuchao 600 393216 2 dest

    ------ Semaphore Arrays --------

    key semid owner perms nsems

    0x59d9bc4a 0 liuchao 600 1

    0x3bd464f2 32769 liuchao 600 1

    ------ Message Queues --------

    key msqid owner perms used-bytes messages

    5.2 Processes Semaphores

    5.2.1. Allocation and Deallocation

    • The calls semget and semctl allocate and deallocate semaphores.
    • Invoke semget with a key specifying a semaphore set, the number of semaphores in the set, and permission flags as for shmget; the return value is a semaphore set identifier.
    • Invoke semctl with the semaphore identifier, the number of semaphores in the set, IPC_RMID as the third argument, and any union semun value as the fourth argument (which is ignored).
    • Semaphores continue to exist even after all processes using them have terminated.
    • The last process to use a semaphore set must explicitly remove it.
    • Allocating and Deallocating a Binary Semaphore

    #include <sys/ipc.h>

    #include <sys/sem.h>

    #include <sys/types.h>

    /* We must define union semun ourselves. */

    union semun {

        int val;

        struct semid_ds *buf;

        unsigned short int *array;

        struct seminfo *__buf;

    };

    /* Obtain a binary semaphore’s ID, allocating if necessary. */

    int binary_semaphore_allocation (key_t key, int sem_flags)

    {

        return semget (key, 1, sem_flags);

    }

    /* Deallocate a binary semaphore. All users must have finished their

    use. Returns -1 on failure. */

    int binary_semaphore_deallocate (int semid)

    {

        union semun ignored_argument;

        return semctl (semid, 1, IPC_RMID, ignored_argument);

    }

    5.2.2. Initializing Semaphores

    • Initializing a Binary Semaphore

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    /* We must define union semun ourselves. */

    union semun {

        int val;

        struct semid_ds *buf;

        unsigned short int *array;

        struct seminfo *__buf;

    };

    /* Initialize a binary semaphore with a value of 1. */

    int binary_semaphore_initialize (int semid)

    {

        union semun argument;

        unsigned short values[1];

        values[0] = 1;

        argument.array = values;

        return semctl (semid, 0, SETALL, argument);

    }

    5.2.3. Wait and Post Operations

    • The semop system call support wait and post operations.
    • The first parameter specifies a semaphore set identifier.
    • The second parameter is an array of struct sembuf elements.
    • The third parameter is the length of this array.
    • The fields of struct sembuf:
    • sem_num is the semaphore number in the semaphore set on which the operation is performed.
    • sem_op is an integer that specifies the semaphore operation.
    • If sem_op is a positive number, that number is added to the semaphore value.
    • If sem_op is a negative number, the get the absolute value.
    • If this would make the semaphore value negative, the call blocks until the semaphore value becomes as large as the absolute value of sem_op.
    • If sem_op is zero, the operation blocks until the semaphore value becomes zero.
    • sem_flg is a flag value.
    • IPC_NOWAIT to prevent the operation from blocking;
    • SEM_UNDO will let Linux automatically undoes the operation on the semaphore when the process exits.
    • Wait and Post Operations for a Binary Semaphore

    #include <sys/types.h>

    #include <sys/ipc.h>

    #include <sys/sem.h>

    /* Wait on a binary semaphore. Block until the semaphore value is positive, then

    decrement it by 1. */

    int binary_semaphore_wait (int semid)

    {

        struct sembuf operations[1];

        /* Use the first (and only) semaphore. */

        operations[0].sem_num = 0;

        /* Decrement by 1. */

        operations[0].sem_op = -1;

        /* Permit undo’ing. */

        operations[0].sem_flg = SEM_UNDO;

        return semop (semid, operations, 1);

    }

    /* Post to a binary semaphore: increment its value by 1.

    This returns immediately. */

    int binary_semaphore_post (int semid)

    {

        struct sembuf operations[1];

        /* Use the first (and only) semaphore. */

        operations[0].sem_num = 0;

        /* Increment by 1. */

        operations[0].sem_op = 1;

        /* Permit undo’ing. */

        operations[0].sem_flg = SEM_UNDO;

        return semop (semid, operations, 1);

    }

    5.3 Mapped Memory

    5.3.1. Mapping an Ordinary File

    • To map an ordinary file to a process’s memory, use the mmap call.
    • The first argument is the address at which you would like Linux to map the file into your process’s address space; the value NULL allows Linux to choose an available start address.
    • The second argument is the length of the map in bytes.
    • The third argument specifies the protection on the mapped address range. PROT_READ or PROT_WRITE or PROT_EXEC.
    • The fourth argument is a flag.
    • MAP_FIXED: If you specify this flag, Linux uses the address you request to map the file rather than treating it as a hint. This address must be page-aligned.
    • MAP_PRIVATE: Writes to the memory range should not be written back to the attached file, but to a private copy of the file. No other process sees these writes.
    • MAP_SHARED: Writes are immediately reflected in the underlying file rather than buffering writes.
    • The fifth argument is a file descriptor opened to the file to be mapped.
    • The last argument is the offset from the beginning of the file from which to start the map
    • (mmap-write.c) Write a Random Number to a Memory-Mapped File

    #include <stdlib.h>

    #include <stdio.h>

    #include <fcntl.h>

    #include <sys/mman.h>

    #include <sys/stat.h>

    #include <time.h>

    #include <unistd.h>

    #define FILE_LENGTH 0x100

    /* Return a uniformly random number in the range [low,high]. */

    int random_range (unsigned const low, unsigned const high)

    {

        unsigned const range = high - low + 1;

        return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));

    }

    int main (int argc, char* const argv[])

    {

        int fd;

        void* file_memory;

        /* Seed the random number generator. */

        srand (time (NULL));

        /* Prepare a file large enough to hold an unsigned integer. */

        fd = open (argv[1], O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);

        lseek (fd, FILE_LENGTH+1, SEEK_SET);

        write (fd, “”, 1);

        lseek (fd, 0, SEEK_SET);

        /* Create the memory mapping. */

        file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);

        close (fd);

        /* Write a random integer to memory-mapped area. */

        sprintf((char*) file_memory, “%d\n”, random_range (-100, 100));

        /* Release the memory (unnecessary because the program exits). */

        munmap (file_memory, FILE_LENGTH);

        return 0;

    }

    • (mmap-read.c) Read an Integer from a Memory-Mapped File, and Double It

    #include <stdlib.h>

    #include <stdio.h>

    #include <fcntl.h>

    #include <sys/mman.h>

    #include <sys/stat.h>

    #include <unistd.h>

    #define FILE_LENGTH 0x100

    int main (int argc, char* const argv[])

    {

        int fd;

        void* file_memory;

        int integer;

        /* Open the file. */

        fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);

        /* Create the memory mapping. */

        file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

        close (fd);

        /* Read the integer, print it out, and double it. */

        sscanf (file_memory, “%d”, &integer);

        printf (“value: %d\n”, integer);

        sprintf ((char*) file_memory, “%d\n”, 2 * integer);

        /* Release the memory (unnecessary because the program exits). */

        munmap (file_memory, FILE_LENGTH);

        return 0;

    }

    5.3.2. Shared Access to a File

    • Different processes can communicate using memory-mapped regions associated with the same file.
    • Specify the MAP_SHARED flag so that any writes to these regions are immediately transferred to the underlying file and made visible to other processes.
    • Otherwise, Linux may buffer writes before transferring them to the file.
    • You can force Linux to incorporate buffered writes into the disk file by calling msync.
    • The first two parameters specify a memory-mapped region.
    • The third parameter can take these flag values:
    • MS_ASYNC: The update is scheduled but not necessarily run before the call returns.
    • MS_SYNC: The update is immediate; the call to msync blocks until it’s done.
    • MS_INVALIDATE: All other file mappings are invalidated so that they can see the updated values.

    msync (mem_addr, mem_length, MS_SYNC | MS_INVALIDATE);

    • Specifying MAP_PRIVATE to mmap creates a copy-on-write region.
    • Any write to the region is reflected only in this process’s memory; other processes that map the same file won’t see the changes.

    5.4 Pipes

    5.4.1. Creating Pipes

    int pipe_fds[2];

    int read_fd;

    int write_fd;

    pipe (pipe_fds);

    read_fd = pipe_fds[0];

    write_fd = pipe_fds[1];

    5.4.2. Communication Between Parent and Child Processes

    #include <stdlib.h>

    #include <stdio.h>

    #include <unistd.h>

    /* Write COUNT copies of MESSAGE to STREAM, pausing for a second between each. */

    void writer (const char* message, int count, FILE* stream)

    {

        for (; count > 0; --count) {

            /* Write the message to the stream, and send it off immediately. */

            fprintf (stream, “%s\n”, message);

            fflush (stream);

            /* Snooze a while. */

            sleep (1);

        }

    }

    /* Read random strings from the stream as long as possible. */

    void reader (FILE* stream)

    {

        char buffer[1024];

        /* Read until we hit the end of the stream. fgets reads until either a newline or the end-of-file. */

        while (!feof (stream) && !ferror (stream) && fgets (buffer, sizeof (buffer), stream) != NULL)

            fputs (buffer, stdout);

    }

    int main ()

    {

        int fds[2];

        pid_t pid;

        /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */

        pipe (fds);

        /* Fork a child process. */

        pid = fork ();

        if (pid == (pid_t) 0) {

            FILE* stream;

            /* This is the child process. Close our copy of the write end of the file descriptor. */

            close (fds[1]);

            /* Convert the read file descriptor to a FILE object, and read from it. */

            stream = fdopen (fds[0], “r”);

            reader (stream);

            close (fds[0]);

        }

        else {

            /* This is the parent process. */

            FILE* stream;

            /* Close our copy of the read end of the file descriptor. */

            close (fds[0]);

            /* Convert the write file descriptor to a FILE object, and write to it. */

            stream = fdopen (fds[1], “w”);

            writer (“Hello, world.”, 5, stream);

            close (fds[1]);

        }

        return 0;

    }

    5.4.3. Redirecting the Standard Input, Output, and Error Streams

    #include <stdio.h>

    #include <sys/types.h>

    #include <sys/wait.h>

    #include <unistd.h>

    int main ()

    {

        int fds[2];

        pid_t pid;

        /* Create a pipe. File descriptors for the two ends of the pipe are placed in fds. */

        pipe (fds);

        /* Fork a child process. */

        pid = fork ();

        if (pid == (pid_t) 0) {

            /* This is the child process. Close our copy of the write end of the file descriptor. */

            close (fds[1]);

            /* Connect the read end of the pipe to standard input. */

            dup2 (fds[0], STDIN_FILENO);

            /* Replace the child process with the “sort” program. */

            execlp (“sort”, “sort”, 0);

        }

        else {

            /* This is the parent process. */

            FILE* stream;

            /* Close our copy of the read end of the file descriptor. */

            close (fds[0]);

            /* Convert the write file descriptor to a FILE object, and write to it. */

            stream = fdopen (fds[1], “w”);

            fprintf (stream, “This is a test.\n”);

            fprintf (stream, “Hello, world.\n”);

            fprintf (stream, “My dog has fleas.\n”);

            fprintf (stream, “This program is great.\n”);

            fprintf (stream, “One fish, two fish.\n”);

            fflush (stream);

            close (fds[1]);

            /* Wait for the child process to finish. */

            waitpid (pid, NULL, 0);

       }

       return 0;

    }

    5.4.4. popen and pclose

    • The popen call
    • The first argument is executed as a shell command in a subprocess running /bin/sh.
    • If the second argument is “r”, the function returns the child process’s standard output stream.
    • If the second argument is “w”, the function returns the child process’s standard input stream.
    • Call pclose to close a stream returned by popen.

    #include <stdio.h>

    #include <unistd.h>

    int main ()

    {

        FILE* stream = popen (“sort”, “w”);

        fprintf (stream, “This is a test.\n”);

        fprintf (stream, “Hello, world.\n”);

        fprintf (stream, “My dog has fleas.\n”);

        fprintf (stream, “This program is great.\n”);

        fprintf (stream, “One fish, two fish.\n”);

        return pclose (stream);

    }

    5.4.5. FIFOs

    • A first-in, first-out (FIFO) file is a pipe that has a name in the filesystem.
    • FIFOs are also called named pipes.
    • You can make a FIFO using the mkfifo command.

    % mkfifo /tmp/fifo

    % ls -l /tmp/fifo

    prw-rw-rw- 1 samuel users 0 Jan 16 14:04 /tmp/fifo

    • Creating a FIFO
    • Create a FIFO programmatically using the mkfifo function.
    • The first argument is the path at which to create the FIFO.
    • The second parameter specifies the pipe’s owner, group, and world permissions.
    • Accessing a FIFO
    • Access a FIFO just like an ordinary file.
    • To communicate through a FIFO, one program must open it for writing, and another program must open it for reading.

    5.5 Sockets

    • Socket: Creates a socket
    • When you create a socket, specify the three socket choices:
    • Namespace: use constants beginning with PF_ (protocol families). PF_LOCAL or PF_UNIX specifies the local namespace, and PF_INET specifies Internet namespaces.
    • communication style: use constants beginning with SOCK_. Use SOCK_STREAM for a connection-style socket, or use SOCK_DGRAM for a datagram-style socket.
    • protocol: it specifies the low-level mechanism to transmit and receive data. Because there is usually one best protocol for each such pair, specifying 0 is usually the correct protocol.
    • Closes: Destroys a socket
    • Connect: Creates a connection between two sockets
    • To create a connection between two sockets, the client calls connect, specifying the address of a server socket to connect to.
    • A client is the process initiating the connection, and a server is the process waiting to accept connections.
    • Bind: Labels a server socket with an address
    • Listen: Configures a socket to accept conditions
    • Accept: Accepts a connection and creates a new socket for the connection
    • A server’s life cycle consists of
    • the creation of a connection-style socket,
    • binding an address to its socket,
    • listen that enables connections to the socket,
    • accept incoming connections, and then closing the socket.

    5.5.1. Local Namespace Sockets

    • Sockets connecting processes on the same computer can use the local namespace represented by the synonyms PF_LOCAL and PF_UNIX.
    • Their socket addresses, specified by filenames, are used only when creating connections.
    • (socket-server.c) Local Namespace Socket Server

    #include <stdio.h>

    #include <stdlib.h>

    #include <string.h>

    #include <sys/socket.h>

    #include <sys/un.h>

    #include <unistd.h>

    /* Read text from the socket and print it out. Continue until the

    socket closes. Return nonzero if the client sent a “quit”

    message, zero otherwise. */

    int server (int client_socket)

    {

        while (1) {

            int length;

            char* text;

            /* First, read the length of the text message from the socket. If read returns zero, the client closed the connection. */

            if (read (client_socket, &length, sizeof (length)) == 0)

                return 0;

            /* Allocate a buffer to hold the text. */

            text = (char*) malloc (length);

            /* Read the text itself, and print it. */

            read (client_socket, text, length);

            printf (“%s\n”, text);

            /* Free the buffer. */

            free (text);

            /* If the client sent the message “quit,” we’re all done. */

            if (!strcmp (text, “quit”))

                return 1;

        }

    }

    int main (int argc, char* const argv[])

    {

        const char* const socket_name = argv[1];

        int socket_fd;

        struct sockaddr_un name;

        int client_sent_quit_message;

        /* Create the socket. */

        socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);

        /* Indicate that this is a server. */

        name.sun_family = AF_LOCAL;

        strcpy (name.sun_path, socket_name);

        bind (socket_fd, &name, SUN_LEN (&name));

        /* Listen for connections. */

        listen (socket_fd, 5);

        /* Repeatedly accept connections, spinning off one server() to deal with each client. Continue until a client sends a “quit” message. */

        do {

            struct sockaddr_un client_name;

            socklen_t client_name_len;

            int client_socket_fd;

            /* Accept a connection. */

            client_socket_fd = accept (socket_fd, &client_name, &client_name_len);

            /* Handle the connection. */

            client_sent_quit_message = server (client_socket_fd);

            /* Close our end of the connection. */

            close (client_socket_fd);

        } while (!client_sent_quit_message);

        /* Remove the socket file. */

        close (socket_fd);

        unlink (socket_name);

        return 0;

    }

    • (socket-client.c) Local Namespace Socket Client

    #include <stdio.h>

    #include <string.h>

    #include <sys/socket.h>

    #include <sys/un.h>

    #include <unistd.h>

    /* Write TEXT to the socket given by file descriptor SOCKET_FD. */

    void write_text (int socket_fd, const char* text)

    {

        /* Write the number of bytes in the string, including NUL-termination. */

        int length = strlen (text) + 1;

        write (socket_fd, &length, sizeof (length));

        /* Write the string. */

        write (socket_fd, text, length);

    }

    int main (int argc, char* const argv[])

    {

        const char* const socket_name = argv[1];

        const char* const message = argv[2];

        int socket_fd;

        struct sockaddr_un name;

        /* Create the socket. */

        socket_fd = socket (PF_LOCAL, SOCK_STREAM, 0);

        /* Store the server’s name in the socket address. */

        name.sun_family = AF_LOCAL;

        strcpy (name.sun_path, socket_name);

        /* Connect the socket. */

        connect (socket_fd, &name, SUN_LEN (&name));

        /* Write the text on the command line to the socket. */

        write_text (socket_fd, message);

        close (socket_fd);

        return 0;

    }

    5.5.2. Internet-Domain Sockets

    • (socket-inet.c) Read from a WWW Server

    #include <stdlib.h>

    #include <stdio.h>

    #include <netinet/in.h>

    #include <netdb.h>

    #include <sys/socket.h>

    #include <unistd.h>

    #include <string.h>

    /* Print the contents of the home page for the server’s socket. Return an indication of success. */

    void get_home_page (int socket_fd)

    {

        char buffer[10000];

        ssize_t number_characters_read;

        /* Send the HTTP GET command for the home page. */

        sprintf (buffer, “GET /\n”);

        write (socket_fd, buffer, strlen (buffer));

        /* Read from the socket. The call to read may not

        return all the data at one time, so keep trying until we run out. */

        while (1) {

            number_characters_read = read (socket_fd, buffer, 10000);

            if (number_characters_read == 0)

                return;

            /* Write the data to standard output. */

            fwrite (buffer, sizeof (char), number_characters_read, stdout);

        }

    }

    int main (int argc, char* const argv[])

    {

        int socket_fd;

        struct sockaddr_in name;

        struct hostent* hostinfo;

        /* Create the socket. */

        socket_fd = socket (PF_INET, SOCK_STREAM, 0);

        /* Store the server’s name in the socket address. */

        name.sin_family = AF_INET;

        /* Convert from strings to numbers. */

        hostinfo = gethostbyname (argv[1]);

        if (hostinfo == NULL)

            return 1;

        else

            name.sin_addr = *((struct in_addr *) hostinfo->h_addr);

        /* Web servers use port 80. */

        name.sin_port = htons (80);

        /* Connect to the Web server */

        if (connect (socket_fd, &name, sizeof (struct sockaddr_in)) == -1) {

            perror (“connect”);

            return 1;

        }

        /* Retrieve the server’s home page. */

        get_home_page (socket_fd);

        return 0;

    }

  • 相关阅读:
    别忘了调用Page.IsValid
    在网站更新时使用App_Offline.htm
    转:零命令玩转Ubuntu 8.10(Wubi安装图文教程)
    转:画Web流程图的一点心得
    c#点对点聊天程序示例
    c#dns解析示例
    c++输出n以内素数问题(埃拉托色尼筛法)
    c#简单字符操作
    C++简单邮箱问题
    c#广播示例
  • 原文地址:https://www.cnblogs.com/forfuture1978/p/1667805.html
Copyright © 2011-2022 走看看