CS360 Lecture notes -- Thread #4 - Sockets and Threads

  • James S. Plank
  • Directory: /home/plank/cs360/notes/Thread-4-Sockets
  • Lecture notes: http://web.eecs.utk.edu/~jplank/plank/classes/cs360/360/notes/Thread-4-Sockets/lecture.html
    Last revised: Mon Apr 5 11:18:27 EDT 2021

    Threaded Telnet, and Minitalk Done Right

    Threads provide the perfect framework for writing programs that deal with asynchrony. In particular, in our lecture notes on sockets, we had some problems writing programs that needed to do the following operations simultaneously: We solved that problem by forking off processes. With threads, you can do these simultaneous operations in one process. That is often essential because you want your various operations to share information.

    In this section, we'll first write a threaded telnet client. This is a client that will request a connection to a socket, and then do what we specify above -- anything typed into standard input will go to the socket, and anything that comes from the socket will go to standard output.

    The program is in src/th_telnet.c, and you should study it. The comments specify exactly what it is doing:

    #include <pthread.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include "sockettome.h"
    
    /* As input, this procedure takes an array of two FILE *'s, typecast to
       a void *.  Let's call this array "connection."  This procedure will read
       lines of text from from connection[0] and write them to connection[1].
       This is convenient, because it works regardless of whether the FILE *'s 
       are socket connections or stdin/stdout. */
    
    void *process_connection(void *c)
    {
      FILE **connection;
      char buf[1000];
    
      connection = (FILE **) c;
      while (fgets(buf, 1000, connection[0]) != NULL) {
        printf("Read: %s", buf);
        fflush(stdout);
        fputs(buf, connection[1]);
        fflush(connection[1]);
      }
      exit(0);
    }
    
    int main(int argc, char **argv)
    {
      int fd;
      FILE *fin, *fout;
      FILE *stdin_to_socket[2];
      FILE *socket_to_stdout[2];
      pthread_t tid;
    
      if (argc != 3 || atoi(argv[2]) <= 0) {
        fprintf(stderr, "usage: th_telnet host port\n");
        exit(1);
      }
    
      /* Open a socket connection to a server, and convert the file 
         descriptor to two FILE *'s, one for reading and one for 
         writing. */
    
      fd = request_connection(argv[1], atoi(argv[2]));
      fin = fdopen(fd, "r");
      fout = fdopen(fd, "w");
      
      /* Create arrays of FILE *'s for process_connection. */
    
      stdin_to_socket[0] = stdin;
      stdin_to_socket[1] = fout;
    
      socket_to_stdout[0] = fin;
      socket_to_stdout[1] = stdout;
    
      /* Fork off a thread to read from the socket and print to standard output.
         The main thread will read from standard input and print to the socket. */
    
      if (pthread_create(&tid, NULL, process_connection, socket_to_stdout) != 0) {
        perror("pthread_create");
        exit(1);
      }
    
      (void) process_connection(stdin_to_socket);
      return 0;
    }
    

    Let's try it, using alternate from the Socket lecture notes as the server:

    UNIX> bin/th_telnet localhost 5555
    Hey
    Read: Hey
    
    
    Read: Hey is for horses.
    Hey is for horses.
    I hate it when people say that.  
    Read: I hate it when people say that.  
    
    So stop saying that.
    Read: So stop saying that.
    
    Read: It is only proper.
    It is only proper.
    < CNTL-D >
    UNIX> 
    
    UNIX> ../Sockets/bin/alternate localhost 5555 s
    Connection established.  Client should start talking
    
    Hey
    Hey is for horses.
    
    
    
    
    I hate it when people say that.  
    
    
    It is only proper.
    So stop saying that.
    
    
    UNIX> 
    

    You'll note, when the left person wrote "So stop saying that," it was read and sent along the socket instantly. However, because alternate alternates strictly, it was not read from the socket until after the second person wrote "It is only proper."

    The program src/real_minitalk.c has both the client and server code for a two-person talk program. It is very much like th_telnet, except it has code for setting up the server, and it doesn't print the "Read" like like th_telnet. What you should notice is that it's ok for one of the two programs to type lots of input, and it works fine. That's because each program has two threads -- one to handle standard input, and one to handle the thread.

    UNIX> bin/real_minitalk localhost 5555 c
    Hi
    
    I said Hi
    
    Why aren't you talking to me?
    
    Is it because I am overbearing?
    
    
    No.  Bye
    UNIX> 
    
    UNIX> bin/real_minitalk localhost 5555 s
    
    Hi
    
    I said Hi
    
    Why aren't you talking to me?
    
    Is it because I am overbearing?
    No.  Bye
    
    UNIX>