Like Tree1Likes

How to pass data using Sockets

This is a discussion on How to pass data using Sockets within the Linux Programming forums, part of the Platform Specific Boards category; Guys can anyone help me to How to pass data between two different processes using sockets. Here are the steps ...

  1. #1
    Registered User
    Join Date
    Sep 2011
    Posts
    23

    How to pass data using Sockets

    Guys can anyone help me to How to pass data between two different processes using sockets.

    Here are the steps using sockets (correct me if I am wrong)

    Process1(server):
    1. Create a socket
    2. Bind
    3. listen
    4. Accept
    5. Close

    Process2(Client):
    1. Create a Socket
    2. Connect
    3. Close

    In sockets, we have to use the same name for both the sockets. Can anyone please tell me how to give the same name.

    While coming to pass the data between processes, If I wish to pass a struct of data using linked lists...Is it possible.

    Can anyone please help me with this and kindly share any sample programs using Sockets if you have any. Thank you.

  2. #2
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    Code:
    SERVER.C
    int server (int client_socket)
    {
    while (1) {
    int length;
    char* text;
    /* First, read the length of the text message from the socket.
    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;
    }
    Code:
    CLIENT.C
    
    /* 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;
    }
    Here for this program we are giving the same name in command prompt for both server & client. What we have to do to give the same program name for the sockets in the program itself (can we use #define and assign a name for program)
    How to send a struct of data for employees like name, address, email, etc using linked lists from client to server.
    Can anyone please help me with this, I am not getting it. I sincerely appreciate your help. Thank you.

  3. #3
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Most people, including me, will not want to read your code unless you edit the post and INDENT PROPERLY.

    Quote Originally Posted by chaituchemico View Post
    Here for this program we are giving the same name in command prompt for both server & client.
    Yeah, PF_LOCAL socket "addresses" are special files. Beware that if the file already exists and you try and bind() to it, you'll fail. I notice you have unlink() on the file at the end of the server code, that's good.

    How to send a struct of data for employees like name, address, email, etc using linked lists from client to server.
    You have to serialize it according to some protocol that you make up, and apply that.

    http://sourceforge.net/apps/mediawik...=Serialization

    You might find the part about linked lists (under "Example Uses") interesting.

    IMO, a lot of IPC is better done with UDP (SOCK_DGRAM) sockets. They are easier to use/less prone to problems.
    Last edited by MK27; 09-08-2011 at 12:24 PM.
    Salem likes this.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  4. #4
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    Thank you MK27.
    Code:
     const char* const socket_name = argv[1];
    Here we are giving the same socket name for server & client using command prompt.
    Is there any other way I can include same socket name for both server & client in the program itself.

  5. #5
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by chaituchemico View Post
    Here we are giving the same socket name for server & client using command prompt.
    Is there any other way I can include same socket name for both server & client in the program itself.
    Hardcode it:

    Code:
    const char* const socket_name = "/tmp/mysocket";
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  6. #6
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    Thank you MK27.
    I have gone through Serialization, it was a good document.
    Code:
    const char* const message = argv[2];
    In the above program, I am sending data from the command prompt.
    If I wish to send employee data (name, address, email). If I initialize a structure and array or linked list can I pass this type of data using sockets. Please help me in how to send data from client to sockets and how to read it in server.

  7. #7
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    Did you come up with a serialization scheme for your data yet? Once you do so, then that will basically tell you how to build your packet. You seem to have the syntax for write/read (based on skimming your code, since I also am not going to spend a lot of time working through unindented code).

  8. #8
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    I am trying to send details of a person from client to sever and display them by server.
    I am errors while compiling this code. Please help me, whether is this the correct way or not.

    Code:
    Server.c
    #include<stdlib.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<unistd.h>
    
    
    typedef struct 
    {
      char lastname[25];
      char firstname[25];
      char address[25];
      char phonenumber[25];
    }addressbook;
    
    addressbook a={0,0};
    
    int main (int argc, char* const argv[])
    {
        const char* const socket_name ="/tmp/socket";
        int socket_fd;
        int client_socket;
        struct sockaddr_un name;
        int client_sent_quit_message;
        int length;
        char* text; 
    
       /* 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, (struct sockaddr*)&name, SUN_LEN (&name));
    
       /* Listen for connections. */
       listen (socket_fd, 5);
       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);
       read (client_socket, &length, sizeof (length));
       text = (char*) malloc (length);
       read (client_socket, &a, sizeof(length));
       printf("lastname of person : %s\n", a.lastname);
       printf("firstname of person : %s\n", a.firstname);
       printf("address of person : %s\n", a.address);
       printf("phone number of person : %s\n", a.phonenumber);
    
       /* Free the buffer. */
       free (text);
    
       /* Close our end of the connection. */
       close (client_socket_fd);
    
       /* Remove the socket file.*/
       close (socket_fd);
       unlink (socket_name);
       return 0;
    }
    
    errors:
    socket.c: In function ‘main’:
    socket.c:44: warning: passing argument 2 of ‘accept’ from incompatible pointer type
    /usr/include/sys/socket.h:214: note: expected ‘struct sockaddr * __restrict__’ but argument is of type ‘struct sockaddr_un *’
    Code:
    #include<stdio.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<unistd.h>
    
    
    typedef struct 
    {
      char lastname[25];
      char firstname[25];
      char address[25];
      char phonenumber[25];
    }addressbook;
    
    addressbook a={0,0};
    int main (int argc, char* const argv[])
    {
       const char* const socket_name = "/tmp/socket";
    
       const char* const message;
       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.*/
        printf("enter details\n");
        printf("enter lastname of person :\n");
        scanf("%s", a.lastname);
        printf("enter firstname of person :\n");
        scanf("%s", a.firstname);
        printf("enter address of person :\n");
        scanf("%s", a.address);
        printf("enter phone number of person :\n");
        scanf("%s", a.phonenumber);
    
        int length = strlen (a) + 1;
        write (socket_fd, &length, sizeof (length));
        write (socket_fd, a, length);
        close (socket_fd);
        return 0;
    }
    
    errors:
    socket1.c: In function ‘main’:
    socket1.c:30: warning: passing argument 2 of ‘connect’ from incompatible pointer type
    /usr/include/sys/socket.h:129: note: expected ‘const struct sockaddr *’ but argument is of type ‘struct sockaddr_un *’
    socket1.c:41: error: incompatible type for argument 1 of ‘strlen’
    /usr/include/string.h:397: note: expected ‘const char *’ but argument is of type ‘addressbook’
    socket1.c:43: error: incompatible type for argument 2 of ‘write’
    /usr/include/unistd.h:363: note: expected ‘const void *’ but argument is of type ‘addressbook’
    Last edited by chaituchemico; 09-09-2011 at 12:04 PM. Reason: properly indended code

  9. #9
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,185
    You'll have to cast your pointers from sockaddr_un to sockaddr.

    The rest indicate some level of bafflement. Read requires a pointer to a piece of memory where you intend to put the incoming information; so you will need to provide it with such a thing. strlen requires a string to find the length of; so you will need to provide it with such a thing. (Perhaps you meant "sizeof" instead.) Write requires a pointer to the information that is to be written; so you will need to provide it with such a thing.

  10. #10
    spurious conceit MK27's Avatar
    Join Date
    Jul 2008
    Location
    segmentation fault
    Posts
    8,300
    Quote Originally Posted by chaituchemico View Post
    Please help me
    Quote Originally Posted by MK27 View Post
    Most people, including me, will not want to read your code unless you edit the post and INDENT PROPERLY.
    Quote Originally Posted by tabstop View Post
    I also am not going to spend a lot of time working through unindented code).
    I am not trying to be mean, chaituchemico, but if you cannot put some effort in to help us help you, how much effort do you expect to see in return?

    There are a number of accepted ways of indenting C source code; yours is not one of them.

    Properly indented code:
    Code:
     
    int main(void) {
        int i;
        char str[666];
    
        for (i = 0; i < 666; i++) {
            str[i] = '*';
        }
    Unindented code which is AWKWARD TO READ:
    Code:
    int main(void) {
    int i;
    char str[666];
    for (i = 0; i < 666; i++) {
    str[i] = '*';
    }
    If you can understand the difference, please take some time to format your code correctly, and other people will be happy to look at it. If that is "a waste of time for you", do not expect anyone else to waste theirs.

    Does that make sense?

    Here's how to get rid of your first warning:
    socket1.c:30: warning: passing argument 2 of ‘connect’ from incompatible pointer type

    Code:
    bind (socket_fd, (struct sockaddr*)&name, SUN_LEN (&name));
    This is because bind() works with various kinds of sockets which use different structs to store address information -- eg, struct sockaddr_in and struct sockaddr_un -- but those structs share some features common to a base, struct sockaddr (this is a primitive form of object-oriented inheritance, if you are interested in that). So with bind(), you need to cast the second argument to a struct sockaddr.

    If you indent your code I might be able to help with the rest of it.
    Last edited by MK27; 09-08-2011 at 06:50 PM.
    C programming resources:
    GNU C Function and Macro Index -- glibc reference manual
    The C Book -- nice online learner guide
    Current ISO draft standard
    CCAN -- new CPAN like open source library repository
    3 (different) GNU debugger tutorials: #1 -- #2 -- #3
    cpwiki -- our wiki on sourceforge

  11. #11
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    I also am not going to spend a lot of time working through unindented code).
    I am sorry, I did not do it by purpose. May be I just overlooked it. Sorry man.
    Sorry for the late reply because we did not have power for last 11 hours.
    I edited my post with indented code and and corrections for bind and read.

    Thank you @tabstop & @Mk27
    Last edited by chaituchemico; 09-09-2011 at 12:06 PM.

  12. #12
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    I am able to correct my errors guys with your suggestions. Thank you.
    Code:
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<unistd.h>
    #include<errno.h>
    
    typedef struct 
    {
      char lastname[25];
      char firstname[25];
      char address[25];
      char phonenumber[25];
    }addressbook;
    
    addressbook a={0,0};
    
    int main (int argc, char* const argv[])
    {
      int ret;
      const char* const socket_name ="/tmp/socket";
      int socket_fd;
      struct sockaddr_un name;
       
      /* 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, (struct sockaddr*)&name, SUN_LEN (&name));
      
      /* Listen for connections. */
      listen (socket_fd, 5);
      
        struct sockaddr_un client_name;
        socklen_t client_name_len;
        int client_socket_fd;
        int client_socket;
        
        /* Accept a connection. */
        client_socket_fd = accept (socket_fd, (struct sockaddr*)&client_name, &client_name_len);
      
        ret = read (client_socket_fd, &a, sizeof(a));
      
        if(ret != 0) {
          printf("error: %s",strerror(errno));
        }
        printf("lastname of person : %s\n", a.lastname);
        printf("firstname of person : %s\n", a.firstname);
        printf("address of person : %s\n", a.address);
        printf("phone number of person : %s\n", a.phonenumber);
        
         /* Close our end of the connection. */
        close (client_socket_fd);
        
      /* Remove the socket file.*/
      close (socket_fd);
      unlink (socket_name);
      return 0;
    }
    Code:
    #include<stdio.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<unistd.h>
    
    
    typedef struct 
    {
      char lastname[25];
      char firstname[25];
      char address[25];
      char phonenumber[25];
    }addressbook;
    
    addressbook a={0,0};
    
    int main (int argc, char* const argv[])
    {
      const char* const socket_name = "/tmp/socket";
    
      const char* const message;
      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, (struct sockaddr*)&name, SUN_LEN (&name));
      
      /* Write the text on the command line to the socket.*/
        printf("enter details\n");
        printf("enter lastname of person :\n");
        scanf("%s", a.lastname);
        printf("enter firstname of person :\n");
        scanf("%s", a.firstname);
        printf("enter address of person :\n");
        scanf("%s", a.address);
        printf("enter phone number of person :\n");
        scanf("%s", a.phonenumber);
      write (socket_fd, (struct sockaddr*)&a, sizeof(a));
      
      /*close the socket */
      close (socket_fd);
      return 0;
    }

  13. #13
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    Hi guys, With your help I am able to send data between two processes using sockets. Thank you.
    I tried to extend my program. This is to insert and display the details of a person.
    there are two processes- server.c and client.c.
    for insertion - client process takes the input data and sends to server. Server must read the data and write to a file.
    for display - client must retrieve the data from the sever(which is stored in file) and display it.
    Can anyone help me with my code. First I am sending the select option for insertion and display then sending the data from client to server. Is this the correct or is there any good approach for this kind of situation.
    I also had one error, can anyone please help me.

    Code:
    server.c
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<unistd.h>
    #include<errno.h>
    
    typedef struct 
    {
      char lastname[25];
      char firstname[25];
      char address[25];
      char phonenumber[25];
    }addressbook;
    
    addressbook a={0,0};
    
    int main (int argc, char* const argv[])
    {
      int ret;
      FILE *fp;
      const char* const socket_name ="/tmp/socket";
      int socket_fd;
      int select;
      struct sockaddr_un name;
       
      /* 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, (struct sockaddr*)&name, SUN_LEN (&name));
      
      /* Listen for connections. */
      listen (socket_fd, 5);
      
      struct sockaddr_un client_name;
      socklen_t client_name_len;
      int client_socket_fd;
            
      /* Accept a connection. */
      client_socket_fd = accept (socket_fd, (struct sockaddr*)&client_name, &client_name_len);
      read (client_socket_fd, &select, sizeof(select));
      if(select == 1){
        ret = read (client_socket_fd, &a, sizeof(a));
        if(ret != 0) {
          printf("error: %s\n",strerror(errno));
        }
        printf("lastname of person : %s\n", a.lastname);
        printf("firstname of person : %s\n", a.firstname);
        printf("address of person : %s\n", a.address);
        printf("phone number of person : %s\n", a.phonenumber);
        fp = fopen("addressbook.dat","a+");
        fwrite(&a, sizeof(addressbook), 1, fp);
        fclose(fp);
      } elseif (select == 2){
        fp = fopen("addressbook.dat", "r");
        fread(&a, sizeof(addressbook), 1, fp); 
        write (client_socket_fd, (struct sockaddr*)&a, sizeof(a));
       }else{
        printf("wrong selection");
       }
          
       /* Close our end of the connection. */
      close (client_socket_fd);
        
      /* Remove the socket file.*/
      close (socket_fd);
      unlink (socket_name);
      return 0;
    }
    Code:
    error: 
    socket.c: In function ‘main’:
    socket.c:58: error: expected ‘;’ before ‘{’ token
    Code:
    client.c
    #include<stdio.h>
    #include<string.h>
    #include<sys/socket.h>
    #include<sys/un.h>
    #include<unistd.h>
    
    
    typedef struct 
    {
      char lastname[25];
      char firstname[25];
      char address[25];
      char phonenumber[25];
    }addressbook;
    
    addressbook a={0,0};
    
    int main (int argc, char* const argv[])
    {
      const char* const socket_name = "/tmp/socket";
    
      const char* const message;
      int socket_fd;
      int select;
      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, (struct sockaddr*)&name, SUN_LEN (&name));
      do {
        printf("Address book: \n Press\n 1: Insert \n 2: Display \n Enter:");
        scanf("%d", &select);
        if(select == 1){
          write (socket_fd, select, sizeof(select));
          /* Write the text on the command line to the socket.*/
          printf("enter details\n");
          printf("enter lastname of person :\n");
          scanf("%s", a.lastname);
          printf("enter firstname of person :\n");
          scanf("%s", a.firstname);
          printf("enter address of person :\n");
          scanf("%s", a.address);
          printf("enter phone number of person :\n");
          scanf("%s", a.phonenumber);
          write (socket_fd, (struct sockaddr*)&a, sizeof(a));
        }elseif(select == 2){
          write (socket_fd, select, sizeof(select));
          read (socket_fd, &a, sizeof(a));
          printf("lastname of person : %s\n", a.lastname);
          printf("firstname of person : %s\n", a.firstname);
          printf("address of person : %s\n", a.address);
          printf("phone number of person : %s\n", a.phonenumber);
        }else{
          printf("wrong selection");
        }
        if((select > 4) || (select < 1))
        break;
      }while(1);
      /*close the socket */
       close (socket_fd);
       return 0;
    }
    Code:
    error:
    socket1.c: In function ‘main’:
    socket1.c:39: warning: passing argument 2 of ‘write’ makes pointer from integer without a cast
    /usr/include/unistd.h:363: note: expected ‘const void *’ but argument is of type ‘int’
    socket1.c:51: error: expected ‘;’ before ‘{’ token
    Can anyone please help me with this. Thank you.

  14. #14
    Registered User
    Join Date
    Nov 2010
    Location
    Long Beach, CA
    Posts
    5,636
    Your overall approach of sending the select option (or "command") to the server, then reading/writing data as appropriate is a fine approach. What you aren't doing well is checking the results of all your IO functions. You need to check the return code of socket, bind, listen, accept, connect, read, write, fopen, fread, fwrite, and maybe some others I missed.

    Highlighting the lines that have errors is a big help to us. As for the "expected ';' before '{' token" errors, you used "elseif" insted of "else if" (you need a space). As for the "passing argument 2 of 'write'" error, you're calling it incorrectly. The write function isn't type-aware, it just wants a memory address to the start of the data it's going to send. You need to pass the address of the data it's sending, i.e. &select.

  15. #15
    Registered User
    Join Date
    Sep 2011
    Posts
    23
    Thank you anduril462. I edited my code, now it is running with no errors.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. DLL's to pass data
    By MotorCityMadMan in forum Windows Programming
    Replies: 3
    Last Post: 05-11-2007, 12:36 AM
  2. How does windows pass data to drivers?
    By Xanth in forum Windows Programming
    Replies: 1
    Last Post: 10-21-2006, 01:38 PM
  3. pass extra data to a function
    By asmileguo in forum C++ Programming
    Replies: 12
    Last Post: 08-09-2006, 12:17 PM
  4. How to pass data between 2 Threads
    By dv007 in forum C Programming
    Replies: 2
    Last Post: 02-22-2006, 01:18 PM
  5. Open & pass data onto a file on cmd line
    By code_guru in forum C Programming
    Replies: 1
    Last Post: 11-03-2005, 09:17 PM

Tags for this Thread


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21