Slide 1: CS110 Lecture 16: Network System Calls

Principles of Computer Systems

Winter 2020

Stanford University

Computer Science Department

Instructors: Chris Gregg and

                            Nick Troccoli

PDF of this presentation

Slide 2: CS110 Topic 4: How can we write programs that communicate over a network with other programs?

Slide 3: Learning About Networking

Introduction to Networking

API Servers

Network System Calls

2/24

2/26

Today

Slide 4: Today's Learning Goals

Slide 5: Plan For Today

Slide 6: Plan For Today

Slide 7: Networking So Far

Slide 8: Networking So Far

Slide 9: Networking So Far

static void writeToSocket(int socketDescriptor) {
  sockbuf sb(socketDescriptor);
  iosockstream ss(&sb);
  ss << [CONTENT HERE] << endl;
} // sockbuf destructor closes client

Slide 10: Plan For Today

Slide 11: Clients And Servers

"client" and "server" are the two main program "roles" in networking.

Slide 12: Clients

int main(int argc, char *argv[]) {
    int clientSocket = createClientSocket("myserver.com", 12345);
    sockbuf sb(clientSocket);
    iosockstream ss(&sb);
    string responseData;
    getline(ss, responseData);
    cout << responseData << endl;
    return 0;
}
  1. We create a client socket to connect to a given server
  2. This returns a descriptor we can use to read/write
  3. We use an iosockstream to simplify using this file descriptor
  4. Finally, we print out the line of data sent from the server

 

But what is createClientSocket really doing?

Slide 13: createClientSocket

  1. Check that the specified server and port are valid
  2. Create a new socket descriptor
  3. Associate this socket descriptor with a connection to that server
  4. Return the socket descriptor
int createClientSocket(const string& host, unsigned short port);

Slide 14: createClientSocket

  1. Check that the specified server and port are valid - gethostbyname()
  2. Create a new socket descriptor - socket()
  3. Associate this socket descriptor with a connection to that server - connect()
  4. Return the socket descriptor
int createClientSocket(const string& host, unsigned short port);

Slide 15: createClientSocket

  1. Check that the specified server and port are valid - gethostbyname()
  2. Create a new socket descriptor - socket()
  3. Associate this socket descriptor with a connection to that server - connect()
  4. Return the socket descriptor
int createClientSocket(const string& host, unsigned short port);

 

 

Idea: let's use gethostbyname() to look up this host and see if it's valid (non-NULL).

struct hostent *gethostbyname(const char *name);
struct hostent *gethostbyaddr(const char *addr, int len, int type);

Slide 16: createClientSocket

// represents an IP Address
struct in_addr {
    unsigned int s_addr // stored in network byte order (big endian)
};

// represents a host's info
struct hostent {
    // official name of host
    char *h_name;

    // NULL-terminated list of aliases
    char **h_aliases;

    // host address type (typically AF_INET for IPv4)
    int h_addrtype;

    // address length (typically 4, or sizeof(struct in_addr) for IPv4)
    int h_length;

    // NULL-terminated list of IP addresses
    // This is really a struct in_addr ** when hostent contains IPv4 addresses
    char **h_addr_list; 
}; 

Slide 17: gethostbyname()

Note: h_addr_list is typed to be a char * array, but for IPv4 records it's really struct in_addr **, so we cast it to that in our code.

 

Why the confusion?

 

  1. Check that the specified server and port are valid - gethostbyname()

Slide 18: createClientSocket

int createClientSocket(const string& host, unsigned short port) {
    struct hostent *he = gethostbyname(host.c_str());
    if (he == NULL) return -1;
    ...

Slide 19: createClientSocket

  1. Check that the specified server and port are valid - gethostbyname()
  2. Create a new socket descriptor - socket()

 

 

 

 

int socket(int domain, int type, int protocol);

int createClientSocket(const string& host, unsigned short port) {
    ...
    int s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) return -1;
    ...

Slide 20: createClientSocket

  1. Check that the specified server and port are valid - gethostbyname()
  2. Create a new socket descriptor - socket()
  3. Associate this socket descriptor with a connection to that server - connect()
int connect(int clientfd, const struct sockaddr *addr, socklen_t addrlen);

Slide 21: Lecture 15: Network System Calls, Library Functions

struct sockaddr { // generic socket
    unsigned short sa_family; // protocol family for socket
    char sa_data[14];
    // address data (and defines full size to be 16 bytes)
};
struct sockaddr_in { // IPv4 socket address record
    unsigned short sin_family;
    unsigned short sin_port;
    struct in_addr sin_addr;
    unsigned char sin_zero[8];
};
struct sockaddr_in6 { // IPv6 socket address record
    unsigned short sin6_family;
    unsigned short sin6_port;
    unsigned int sin6_flowinfo;;
    struct in6_addr sin6_addr;
    unsigned int sin6_scope_id;
};

Slide 22: Lecture 15: Network System Calls, Library Functions

struct sockaddr { // generic socket
    unsigned short sa_family; // protocol family for socket
    char sa_data[14];
    // address data (and defines full size to be 16 bytes)
};
struct sockaddr_in { // IPv4 socket address record
    unsigned short sin_family;
    unsigned short sin_port;
    struct in_addr sin_addr;
    unsigned char sin_zero[8];
};
struct sockaddr_in6 { // IPv6 socket address record
    unsigned short sin6_family;
    unsigned short sin6_port;
    unsigned int sin6_flowinfo;;
    struct in6_addr sin6_addr;
    unsigned int sin6_scope_id;
};

Slide 23: Lecture 15: Network System Calls, Library Functions

struct sockaddr { // generic socket
    unsigned short sa_family; // protocol family for socket
    char sa_data[14];
    // address data (and defines full size to be 16 bytes)
};
struct sockaddr_in { // IPv4 socket address record
    unsigned short sin_family;
    unsigned short sin_port;
    struct in_addr sin_addr;
    unsigned char sin_zero[8];
};
struct sockaddr_in6 { // IPv6 socket address record
    unsigned short sin6_family;
    unsigned short sin6_port;
    unsigned int sin6_flowinfo;;
    struct in6_addr sin6_addr;
    unsigned int sin6_scope_id;
};

Slide 24: createClientSocket

  1. Check that the specified server and port are valid - gethostbyname()
  2. Create a new socket descriptor - socket()
  3. Associate this socket descriptor with a connection to that server - connect()
int createClientSocket(const string& host, unsigned short port) {
    ...
    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(port);

    // h_addr is #define for h_addr_list[0]
    address.sin_addr = *((struct in_addr *)he->h_addr); 
    if (connect(s, (struct sockaddr *) &address, sizeof(address)) == 0) return s;
    ...

Slide 25: Lecture 15: Network System Calls, Library Functions

int createClientSocket(const string& host, unsigned short port) {
    struct hostent *he = gethostbyname(host.c_str());
    if (he == NULL) return -1;
    int s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) return -1;
    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(port);

    // h_addr is #define for h_addr_list[0]
    address.sin_addr = *((struct in_addr *)he->h_addr); 
    if (connect(s, (struct sockaddr *) &address, sizeof(address)) == 0) return s;

    close(s);
    return -1;
}

Slide 26: Lecture 15: Network System Calls, Library Functions

Slide 27: Plan For Today

Slide 28: Announcements

Slide 29: Plan For Today

Slide 30: createServerSocket

  1. Create a new socket descriptor - socket()
  2. Bind this socket to a given port and IP address- bind()
  3. Make the socket descriptor passive to listen for incoming requests - listen()
  4. Return socket descriptor
int createServerSocket(unsigned short port, int backlog = kDefaultBacklog);

Slide 31: Lecture 15: Network System Calls, Library Functions

int createServerSocket(unsigned short port, int backlog) {
    int s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) return -1;
    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = htonl(INADDR_ANY);
    address.sin_port = htons(port);
    if (bind(s, (struct sockaddr *)&address, sizeof(address)) == 0 &&
            listen(s, backlog) == 0) return s;

    close(s);
    return -1;
}

Slide 32: Lecture 15: Network System Calls, Library Functions

Slide 33: Plan For Today

GET http://www.cornell.edu/research/ HTTP/1.1

GET /research/ HTTP/1.1

Slide 34: Lecture Recap

 

 

 

Next Time: Overview of MapReduce