Sabtu, 01 Oktober 2011


6. Client-Server Background 6. Client-Server Latar Belakang


It's a client-server world, baby. Ini adalah client-server dunia, bayi. Just about everything on the network deals with client processes talking to server processes and vice-versa. Hanya tentang segala sesuatu di penawaran jaringan dengan proses klien berbicara dengan proses server dan sebaliknya. Take telnet , for instance. Ambil telnet, misalnya. When you connect to a remote host on port 23 with telnet (the client), a program on that host (called telnetd , the server) springs to life. Bila Anda terhubung ke sebuah host remote pada port 23 dengan telnet (klien), sebuah program pada host (telnetd disebut, server) mata air untuk hidup. It handles the incoming telnet connection, sets you up with a login prompt, etc. Ini menangani koneksi telnet yang masuk, membuat Anda dengan sebuah prompt login, dll
[Client-Server Diagram Interaksi]
Client-Server Interaction. Client-Server Interaksi.
The exchange of information between client and server is summarized in the above diagram . Pertukaran informasi antara klien dan server adalah diringkas dalam diagram di atas .
Note that the client-server pair can speak SOCK_STREAM , SOCK_DGRAM , or anything else (as long as they're speaking the same thing.) Some good examples of client-server pairs are telnet / telnetd , ftp / ftpd , or Firefox / Apache . Perhatikan bahwa pasangan client-server dapat berbicara SOCK_STREAM, SOCK_DGRAM, atau apapun (selama mereka berbicara hal yang sama.) Beberapa contoh yang baik dari klien-server pasangan telnet / telnetd, ftp / ftpd, atau Firefox / Apache . Every time you use ftp , there's a remote program, ftpd , that serves you. Setiap kali Anda menggunakan ftp, ada program remote, ftpd, yang melayani Anda.
Often, there will only be one server on a machine, and that server will handle multiple clients using Seringkali, hanya akan ada satu server pada mesin, dan server yang akan menangani beberapa klien menggunakan fork() . fork (). The basic routine is: server will wait for a connection, accept() it, and fork() a child process to handle it. Rutinitas dasar adalah: server akan menunggu untuk koneksi, menerima () itu, dan garpu () proses anak untuk menanganinya. This is what our sample server does in the next section. Ini adalah apa server sampel kami tidak dalam bagian berikutnya.

6.1. A Simple Stream Server 6.1. Streaming Server Sederhana

All this server does is send the string " Hello, World!\n " out over a stream connection. Semua server ini dilakukan adalah mengirim string "Hello, World \ n" keluar melalui koneksi stream. All you need to do to test this server is run it in one window, and telnet to it from another with: Yang perlu Anda lakukan untuk menguji server ini dijalankan dalam satu jendela, dan telnet ke sana dari yang lain dengan:
$ telnet remotehostname 3490 $ 3490 remotehostname telnet 
where remotehostname is the name of the machine you're running it on. mana remotehostname adalah nama dari mesin Anda menjalankan pada.
The server code : Kode server :
/* ** server.c -- a stream socket server demo */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <netdb.h> #include <arpa/inet.h> #include <sys/wait.h> #include <signal.h> #define PORT "3490" // the port users will be connecting to #define BACKLOG 10 // how many pending connections queue will hold void sigchld_handler(int s) { while(waitpid(-1, NULL, WNOHANG) > 0); } // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(void) { int sockfd, new_fd; // listen on sock_fd, new connection on new_fd struct addrinfo hints, *servinfo, *p; struct sockaddr_storage their_addr; // connector's address information socklen_t sin_size; struct sigaction sa; int yes=1; char s[INET6_ADDRSTRLEN]; int rv; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and bind to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("server: socket"); continue; } if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) { perror("setsockopt"); exit(1); } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("server: bind"); continue; } break; } if (p == NULL) { fprintf(stderr, "server: failed to bind\n"); return 2; } freeaddrinfo(servinfo); // all done with this structure if (listen(sockfd, BACKLOG) == -1) { perror("listen"); exit(1); } sa.sa_handler = sigchld_handler; // reap all dead processes sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; if (sigaction(SIGCHLD, &sa, NULL) == -1) { perror("sigaction"); exit(1); } printf("server: waiting for connections...\n"); while(1) { // main accept() loop sin_size = sizeof their_addr; new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); if (new_fd == -1) { perror("accept"); continue; } inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s); printf("server: got connection from %s\n", s); if (!fork()) { // this is the child process close(sockfd); // child doesn't need the listener if (send(new_fd, "Hello, world!", 13, 0) == -1) perror("send"); close(new_fd); exit(0); } close(new_fd); // parent doesn't need this } return 0; } / * ** Server.c - soket streaming server * demo / # include # include # include # include <unistd.h> <errno.h> # include <string.h > # include # include <sys/types.h> <sys/socket.h> # include # include <netinet/in.h> <netdb.h> # include <arpa/inet.h> # include <sys / menunggu . h> # include # define PORT <signal.h> "3490" / / para pengguna port akan menghubungkan ke # define Backlog 10 / / berapa banyak antrian koneksi yang tertunda akan mengadakan sigchld_handler void (int s) {while (waitpid (- 1, NULL, WNOHANG)> 0);} / / mendapatkan sockaddr, IPv4 atau IPv6: void * get_in_addr (struct sockaddr * sa) {if (sa-> sa_family == AF_INET) {return & (((struct sockaddr_in *) sa) -> sin_addr);} return & (((struct sockaddr_in6 *) sa) -> sin6_addr);} int main (void) {int sockfd, new_fd; / / mendengarkan pada sock_fd, sambungan baru pada petunjuk struct new_fd addrinfo, * servinfo, * p; struct their_addr sockaddr_storage; / / alamat informasi konektor sin_size socklen_t; struct sigaction sa; int yes = 1; arang s [INET6_ADDRSTRLEN]; int rv; memset (& petunjuk, 0, sizeof petunjuk); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; / / menggunakan IP saya jika ((rv = getaddrinfo (NULL, PORT, & petunjuk, & servinfo)) = 0!) {fprintf (stderr, "getaddrinfo:% s \ n ", gai_strerror (rv)); return 1;} / / loop melalui semua hasil dan mengikat dengan yang pertama kita bisa untuk (p = servinfo; p = NULL;! p = p-> ai_next) {if ((sockfd = socket (p-> ai_family, p-> ai_socktype, p-> ai_protocol)) == -1) {perror ("server: soket"); melanjutkan;} if (setsockopt (sockfd, SOL_SOCKET, SO_REUSEADDR, & ya, sizeof (int)) == -1) {perror ("setsockopt"); exit (1);} if (bind (sockfd, p-> ai_addr, p-> ai_addrlen) == -1) {close (sockfd); perror ("server: mengikat"); melanjutkan;} break;} if (p == NULL) {fprintf (stderr, "server: gagal untuk mengikat \ n"); kembali 2;} freeaddrinfo (servinfo); / / semua dilakukan dengan struktur ini jika (mendengarkan (sockfd, backlog) == -1) {perror ("mendengarkan"); exit (1);} sa.sa_handler = sigchld_handler; / / meraup semua proses mati sigemptyset (& sa.sa_mask); sa.sa_flags = SA_RESTART, jika (sigaction (SIGCHLD, & sa, NULL) == -1) {perror ("sigaction"); exit (1);} printf ("server: menunggu untuk koneksi ... \ n") ; sementara (1) {/ / main menerima () loop = sizeof their_addr sin_size; new_fd = menerima (sockfd, (struct sockaddr *) & their_addr, & sin_size), jika (new_fd == -1) {perror ("menerima"); melanjutkan;} inet_ntop (their_addr.ss_family, get_in_addr ((struct sockaddr *) & their_addr), s, sizeof s); printf ("server: punya koneksi dari% s \ n", s); if (fork ()!) { / / ini adalah proses anak dekat (sockfd); / / anak tidak perlu pendengar jika (mengirim (new_fd, "Halo, dunia!", 13, 0) == -1) perror ("kirim"); dekat (new_fd); exit (0);} dekat (new_fd); / / orang tua tidak perlu ini kembali} 0;} 
In case you're curious, I have the code in one big main() function for (I feel) syntactic clarity. Dalam kasus Anda penasaran, saya memiliki kode dalam satu utama besar () fungsi untuk (Saya merasa) kejelasan sintaksis. Feel free to split it into smaller functions if it makes you feel better. Jangan ragu untuk membagi ke dalam fungsi yang lebih kecil jika itu membuat Anda merasa lebih baik.
(Also, this whole (Juga, ini seluruh sigaction() thing might be new to you—that's ok. sigaction () mungkin hal baru bagi Anda-itu ok. The code that's there is responsible for reaping Kode yang ada di sana bertanggung jawab untuk menuai zombie processes that appear as the fork() ed child processes exit. zombie proses yang muncul sebagai fork () ed anak proses keluar. If you make lots of zombies and don't reap them, your system administrator will become agitated.) Jika Anda membuat banyak zombie dan tidak menuai mereka, administrator sistem Anda akan menjadi gelisah.)
You can get the data from this server by using the client listed in the next section. Anda bisa mendapatkan data dari server ini dengan menggunakan klien yang tercantum dalam bagian berikutnya.

6.2. A Simple Stream Client 6.2. Sebuah Klien Streaming Sederhana

This guy's even easier than the server. Orang ini bahkan lebih mudah daripada server. All this client does is connect to the host you specify on the command line, port 3490. Semua klien ini adalah menyambung ke host Anda tentukan pada baris perintah, port 3490. It gets the string that the server sends. Ia mendapat string yang server mengirimkan.
The client source : Sumber klien :
/* / *
** client.c -- a stream socket client demo ** Client.c - soket aliran demo klien
*/ * /

#include <stdio.h> # Include
#include <stdlib.h> # Include
#include <unistd.h> # Include <unistd.h>
#include <errno.h> # Include <errno.h>
#include <string.h> # Include <string.h>
#include <netdb.h> # Include <netdb.h>
#include <sys/types.h> # Include <sys/types.h>
#include <netinet/in.h> # Include <netinet/in.h>
#include <sys/socket.h> # Include <sys/socket.h>

#include <arpa/inet.h> # Include <arpa/inet.h>

#define PORT "3490" // the port client will be connecting to # Define PORT "3490" / / klien port akan menghubungkan ke 

#define MAXDATASIZE 100 // max number of bytes we can get at once # Define MAXDATASIZE 100 / / max jumlah byte yang kita bisa sekaligus 

// get sockaddr, IPv4 or IPv6: / / Mendapatkan sockaddr, IPv4 atau IPv6:
void *get_in_addr(struct sockaddr *sa) void * get_in_addr (struct sockaddr * sa)
{ {
    if (sa->sa_family == AF_INET) { if (sa-> sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr); kembali & (((struct sockaddr_in *) sa) -> sin_addr);
    } }

    return &(((struct sockaddr_in6*)sa)->sin6_addr); kembali & (((struct sockaddr_in6 *) sa) -> sin6_addr);
} }

int main(int argc, char *argv[]) int main (int argc, char * argv [])
{ {
    int sockfd, numbytes; int sockfd, numbytes;  
    char buf[MAXDATASIZE]; buf char [MAXDATASIZE];
    struct addrinfo hints, *servinfo, *p; struct petunjuk addrinfo, * servinfo, * p;
    int rv; int rv;
    char s[INET6_ADDRSTRLEN]; arang s [INET6_ADDRSTRLEN];

    if (argc != 2) { if (argc = 2!) {
        fprintf(stderr,"usage: client hostname\n"); fprintf (stderr, "penggunaan: hostname client \ n");
        exit(1); exit (1);
    } }

    memset(&hints, 0, sizeof hints); memset (& petunjuk, 0, sizeof petunjuk);
    hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM; hints.ai_socktype = SOCK_STREAM;

    if ((rv = getaddrinfo(argv[1], PORT, &hints, &servinfo)) != 0) { if ((rv = getaddrinfo (argv [1], PORT, & petunjuk, & servinfo)) = 0!) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); fprintf (stderr, "getaddrinfo:% s \ n", gai_strerror (rv));
        return 1; return 1;
    } }

    // loop through all the results and connect to the first we can / / Loop melalui semua hasil dan terhubung dengan yang pertama kita dapat
    for(p = servinfo; p != NULL; p = p->ai_next) { untuk (p = servinfo; p = NULL;! p = p-> ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype, if ((sockfd = socket (p-> ai_family, p-> ai_socktype,
                p->ai_protocol)) == -1) { p-> ai_protocol)) == -1) {
            perror("client: socket"); perror ("klien: socket");
            continue; melanjutkan;
        } }

        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) { if (connect (sockfd, p-> ai_addr, p-> ai_addrlen) == -1) {
            close(sockfd); dekat (sockfd);
            perror("client: connect"); perror ("klien: koneksi");
            continue; melanjutkan;
        } }

        break; break;
    } }

    if (p == NULL) { if (p == NULL) {
        fprintf(stderr, "client: failed to connect\n"); fprintf (stderr, "Klien: gagal untuk menghubungkan \ n");
        return 2; kembali 2;
    } }

    inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), inet_ntop (p-> ai_family, get_in_addr ((struct sockaddr *) p-> ai_addr),
            s, sizeof s); s, sizeof s);
    printf("client: connecting to %s\n", s); printf ("Klien: terhubung ke% s \ n", s);

    freeaddrinfo(servinfo); // all done with this structure freeaddrinfo (servinfo); / / semua dilakukan dengan struktur ini

    if ((numbytes = recv(sockfd, buf, MAXDATASIZE-1, 0)) == -1) { if ((numbytes = recv (sockfd, buf, MAXDATASIZE-1, 0)) == -1) {
        perror("recv"); perror ("recv");
        exit(1); exit (1);
    } }

    buf[numbytes] = '\0'; buf [numbytes] = '\ 0';

    printf("client: received '%s'\n",buf); printf ("Klien: menerima \ '% s' n", buf);

    close(sockfd); dekat (sockfd);

    return 0; return 0;
} } 
Notice that if you don't run the server before you run the client, connect() returns Perhatikan bahwa jika Anda tidak menjalankan server sebelum Anda menjalankan klien, menghubungkan () mengembalikan "Connection refused". "Koneksi ditolak". Very useful. Sangat berguna.

6.3. Datagram Sockets 6.3. Datagram Socket

We've already covered the basics of UDP datagram sockets with our discussion of sendto() and recvfrom() , above, so I'll just present a couple of sample programs: talker.c and listener.c . Kami sudah membahas dasar-dasar soket UDP datagram dengan diskusi kita tentang sendto () dan recvfrom (), di atas, jadi saya hanya akan menyajikan beberapa contoh program: talker.c dan listener.c.
listener sits on a machine waiting for an incoming packet on port 4950. talker sends a packet to that port, on the specified machine, that contains whatever the user enters on the command line. pendengar duduk pada mesin menunggu sebuah paket masuk pada port 4950. pembicara yang mengirimkan sebuah paket ke port itu, pada mesin tertentu, yang berisi apa pun pengguna masuk pada baris perintah.
Here is the source for listener.c : Berikut adalah sumber untuk listener.c :
/* ** listener.c -- a datagram sockets "server" demo */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netdb.h> #define MYPORT "4950" // the port users will be connecting to #define MAXBUFLEN 100 // get sockaddr, IPv4 or IPv6: void *get_in_addr(struct sockaddr *sa) { if (sa->sa_family == AF_INET) { return &(((struct sockaddr_in*)sa)->sin_addr); } return &(((struct sockaddr_in6*)sa)->sin6_addr); } int main(void) { int sockfd; struct addrinfo hints, *servinfo, *p; int rv; int numbytes; struct sockaddr_storage their_addr; char buf[MAXBUFLEN]; socklen_t addr_len; char s[INET6_ADDRSTRLEN]; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; // set to AF_INET to force IPv4 hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; // use my IP if ((rv = getaddrinfo(NULL, MYPORT, &hints, &servinfo)) != 0) { fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); return 1; } // loop through all the results and bind to the first we can for(p = servinfo; p != NULL; p = p->ai_next) { if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) { perror("listener: socket"); continue; } if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { close(sockfd); perror("listener: bind"); continue; } break; } if (p == NULL) { fprintf(stderr, "listener: failed to bind socket\n"); return 2; } freeaddrinfo(servinfo); printf("listener: waiting to recvfrom...\n"); addr_len = sizeof their_addr; if ((numbytes = recvfrom(sockfd, buf, MAXBUFLEN-1 , 0, (struct sockaddr *)&their_addr, &addr_len)) == -1) { perror("recvfrom"); exit(1); } printf("listener: got packet from %s\n", inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof s)); printf("listener: packet is %d bytes long\n", numbytes); buf[numbytes] = '\0'; printf("listener: packet contains \"%s\"\n", buf); close(sockfd); return 0; } / * ** Listener.c - datagram socket "server" demo * / # include # include # include # include <unistd.h> <errno.h> # menyertakan string < h>. # include # include <sys/types.h> <sys/socket.h> # include # include <netinet/in.h> <arpa/inet.h> # include # define <netdb.h> MYPORT " 4950 "/ / para pengguna port akan menghubungkan ke # define MAXBUFLEN 100 / / mendapatkan sockaddr, IPv4 atau IPv6: void * get_in_addr (struct sockaddr * sa) {if (sa-> sa_family == AF_INET) {return & ((( struct sockaddr_in *) sa) -> sin_addr); - int rv;;} int main (void) {int sockfd; struct petunjuk addrinfo, * servinfo, * p> sin6_addr)} return & (((struct sockaddr_in6 *) sa) int numbytes; struct their_addr sockaddr_storage; buf char [MAXBUFLEN]; socklen_t addr_len; arang s [INET6_ADDRSTRLEN]; memset (& petunjuk, 0, sizeof petunjuk); hints.ai_family = AF_UNSPEC; / / set AF_INET untuk memaksa IPv4 hints.ai_socktype = SOCK_DGRAM; hints.ai_flags = AI_PASSIVE; / / menggunakan IP saya jika ((rv = getaddrinfo (NULL, MYPORT, & petunjuk, & servinfo)) = 0!) {fprintf (stderr, "getaddrinfo:% s \ n", gai_strerror ( rv)); return 1;} / / loop melalui semua hasil dan mengikat dengan yang pertama kita bisa untuk (p = servinfo; p = NULL;! p = p-> ai_next) {if ((sockfd = socket (p- > ai_family, p-> ai_socktype, p-> ai_protocol)) == -1) {perror ("pendengar: socket"); melanjutkan;} if (bind (sockfd, p-> ai_addr, p-> ai_addrlen) == -1) {close (sockfd); perror ("pendengar: mengikat"); melanjutkan;} break;} if (p == NULL) {fprintf (stderr, "pendengar: gagal untuk mengikat socket \ n"); kembali 2 ;} freeaddrinfo (servinfo); printf ("pendengar: menunggu untuk recvfrom ... \ n"); addr_len = sizeof their_addr, jika ((numbytes = recvfrom (sockfd, buf, MAXBUFLEN-1, 0, (struct sockaddr *) & their_addr, & addr_len)) == -1) {perror ("recvfrom"); exit (1);} printf ("pendengar: mendapat paket dari% s \ n", inet_ntop (their_addr.ss_family, get_in_addr ((struct sockaddr * ) & their_addr), s, sizeof s)); printf ("pendengar: paket adalah% d byte panjang \ n", numbytes); buf [numbytes] = '\ 0'; printf ("pendengar: paket berisi \"% s \ "\ n", buf); dekat (sockfd); return 0;} 
Notice that in our call to getaddrinfo() we're finally using SOCK_DGRAM . Perhatikan bahwa dalam panggilan kita untuk getaddrinfo () kita akhirnya menggunakan SOCK_DGRAM. Also, note that there's no need to listen() or accept() . Juga, perhatikan bahwa tidak perlu untuk mendengarkan () atau menerima (). This is one of the perks of using unconnected datagram sockets! Ini adalah salah satu manfaat dari menggunakan soket datagram tidak tersambung!
Next comes the source for talker.c : Selanjutnya muncul sumber untuk talker.c :
/* / *
** talker.c -- a datagram "client" demo ** Talker.c - datagram "client" demo
*/ * /

#include <stdio.h> # Include
#include <stdlib.h> # Include
#include <unistd.h> # Include <unistd.h>
#include <errno.h> # Include <errno.h>
#include <string.h> # Include <string.h>
#include <sys/types.h> # Include <sys/types.h>
#include <sys/socket.h> # Include <sys/socket.h>
#include <netinet/in.h> # Include <netinet/in.h>
#include <arpa/inet.h> # Include <arpa/inet.h>
#include <netdb.h> # Include <netdb.h>

#define SERVERPORT "4950" // the port users will be connecting to # Define SERVERPORT "4950" / / para pengguna port akan menghubungkan ke

int main(int argc, char *argv[]) int main (int argc, char * argv [])
{ {
    int sockfd; int sockfd;
    struct addrinfo hints, *servinfo, *p; struct petunjuk addrinfo, * servinfo, * p;
    int rv; int rv;
    int numbytes; int numbytes;

    if (argc != 3) { if (argc = 3!) {
        fprintf(stderr,"usage: talker hostname message\n"); fprintf (stderr, "penggunaan: Pesan pembicara hostname \ n");
        exit(1); exit (1);
    } }

    memset(&hints, 0, sizeof hints); memset (& petunjuk, 0, sizeof petunjuk);
    hints.ai_family = AF_UNSPEC; hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_DGRAM; hints.ai_socktype = SOCK_DGRAM;

    if ((rv = getaddrinfo(argv[1], SERVERPORT, &hints, &servinfo)) != 0) { if ((rv = getaddrinfo (argv [1], SERVERPORT, & petunjuk, & servinfo)) = 0!) {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); fprintf (stderr, "getaddrinfo:% s \ n", gai_strerror (rv));
        return 1; return 1;
    } }

    // loop through all the results and make a socket / / Loop melalui semua hasil dan membuat soket
    for(p = servinfo; p != NULL; p = p->ai_next) { untuk (p = servinfo; p = NULL;! p = p-> ai_next) {
        if ((sockfd = socket(p->ai_family, p->ai_socktype, if ((sockfd = socket (p-> ai_family, p-> ai_socktype,
                p->ai_protocol)) == -1) { p-> ai_protocol)) == -1) {
            perror("talker: socket"); perror ("pembicara: socket");
            continue; melanjutkan;
        } }

        break; break;
    } }

    if (p == NULL) { if (p == NULL) {
        fprintf(stderr, "talker: failed to bind socket\n"); fprintf (stderr, "pembicara: gagal untuk mengikat socket \ n");
        return 2; kembali 2;
    } }

    if ((numbytes = sendto(sockfd, argv[2], strlen(argv[2]), 0, if ((numbytes = sendto (sockfd, argv [2], strlen (argv [2]), 0,
             p->ai_addr, p->ai_addrlen)) == -1) { p-> ai_addr, p-> ai_addrlen)) == -1) {
        perror("talker: sendto"); perror ("pembicara: sendto");
        exit(1); exit (1);
    } }

    freeaddrinfo(servinfo); freeaddrinfo (servinfo);

    printf("talker: sent %d bytes to %s\n", numbytes, argv[1]); printf ("pembicara:% d byte dikirim ke% s \ n", numbytes, argv [1]);
    close(sockfd); dekat (sockfd);

    return 0; return 0;
} } 
And that's all there is to it! Dan itu semua ada untuk itu! Run listener on some machine, then run talker on another. Jalankan pendengar pada mesin tertentu, kemudian jalankan pembicara yang lain. Watch them communicate! Menonton mereka berkomunikasi! Fun G-rated excitement for the entire nuclear family! Fun G-rated kegembiraan bagi seluruh keluarga inti!
You don't even have to run the server this time! Anda bahkan tidak harus menjalankan server saat ini! You can run talker by itself, and it just happily fires packets off into the ether where they disappear if no one is ready with a recvfrom() on the other side. Anda dapat menjalankan pembicara dengan sendirinya, dan hanya gembira kebakaran dari paket ke dalam eter di mana mereka menghilang jika tidak ada yang siap dengan recvfrom () di sisi lain. Remember: data sent using UDP datagram sockets isn't guaranteed to arrive! Ingat: data yang dikirim menggunakan UDP datagram socket tidak dijamin tiba!
Except for one more tiny detail that I've mentioned many times in the past: Kecuali untuk satu detail kecil lagi yang telah saya sebutkan berkali-kali di masa lalu: connected datagram sockets. terhubung soket datagram. I need to talk about this here, since we're in the datagram section of the document. Aku perlu bicara tentang ini di sini, karena kita berada di bagian datagram dokumen. Let's say that talker calls connect() and specifies the listener 's address. Mari kita mengatakan bahwa pembicara panggilan terhubung () dan menentukan alamat pendengar 's. From that point on, talker may only sent to and receive from the address specified by connect() . Sejak saat itu, pembicara hanya dapat dikirim ke dan menerima dari alamat yang ditentukan oleh koneksi (). For this reason, you don't have to use sendto() and recvfrom() ; you can simply use send() and recv() . Untuk alasan ini, Anda tidak harus menggunakan sendto () dan recvfrom (); Anda hanya dapat menggunakan send () dan recv ().