Sockets (Part 1)
This page was last modified 2010-04-23 12:51:32 by Puchu.Net user Choco. Based on work by Puchu.Net user(s) Omoikane. (Show history)

Contents

Introduction

This article will be divided into two parts. Part 1 (you are reading it) will be a quick look at various related system calls. While these functions are for Linux and UNIX platforms, the same functions exist under Windows, and have similarly named methods for other platforms.

Information related to client/server interaction, Winsock2, DNS, and references used in these articles is in Sockets (Part 2).

Byte Ordering

Different processor architecture and network protocol operate with different byte ordering (endianness, for example x86 is little-endian, TCP/IP is big-endian), so to bridge the different ends of a connection macros are used to shift bytes to network byte order:

ulong htonl(ulong value);
ushort htons(ushort value);

Or, when converting from network byte order:

ulong ntohl(ulong value);
ushort ntohs(ushortvalue);

System Calls

socket

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

Create a new socket. If value 0 is used for protocol then the function will determine the protocol based on domain and type. This function returns a socket descriptor, which will be used later in place of parameter fd.

int fd = socket(PF_INET, SOCK_STREAM, 0);

Socket programming always involve the socket descriptor in some ways, and socket abstracts the session for application. This is how your application will keep track of different connections.

bind / listen / accept

int bind(int fd, const struct sockaddr *addr, int addr_len);

This function binds your socket to a local IP address, something you want to do if you are the server that will be listening on an address and a port.

The structure sockaddr may have fields you don't use, depending on the address family. The first unsigned short will identify the socket address family, and the next bytes change depending on the address family. For example (by including netinet/in.h):

IPv4: IPv6:
struct sockaddr_in {
  ushort sin_family;
  ushort sin_port;
  struct in_addr sin_addr;
  char   sin_zero[8]; // no info
};
struct sockaddr_in6 {
  ushort sin6_family;
  ushort sin6_port;
  ulong  sin6_flowinfo;
  struct in6_addr sin6_addr;
  ulong  sin6_scope_id;
};

Once your server is bound to an address, it should be listening for a connection.

int listen(int fd, int n);

Here the parameter n determines now many requests will be queued before the server starts to refuse them. The number varies depending on your platform and your application.

Once you have determined that there are some connection requests queued up, you can remove those requests by accepting them.

int accept(int fd, const struct sockaddr *addr, int *addr_len);

By calling the function to accept a request, if there is a connection request queued the function will fill in the client address information so that we can transfer data to/from the client. accept() will block until there is a request.

An example of the function calls for a server would be:

int fd = socket(PF_INET, SOCK_STREAM, 0);
struct sockaddr_in daddr, saddr;

if (fd > 0) {
  saddr.sin_family = AF_INET;
  saddr.sin_port = htons(5112);
  saddr.sin_addr.s_addr = inet_addr("10.10.10.100");
  // note that if address is zero, it'll be the IP address
  // of the machine running your process.

  if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr)) == -1) {
    // bind failed, check error code and
    // either look for another port or retry in a little while
  }

  if (listen(fd, 10) == -1) {
    // listen failed
  }

  socklen_t s = sizeof(daddr);
  int nd = accept(fd, (struct sockaddr *)&daddr, &s));
  if (nd == -1) {
    // accept failed
  }
}

If you need to handle multiple connections, your code needs to store and maintain the associated socket descriptor and address information.

connect

int connect(int fd, const struct sockaddr *addr, int addr_len);

This function will connect you to the server specified in the socket address information.

if (connect(fd, (struct sockaddr *)&addr, sizeof(struct sockaddr)) == -1) {
  // connect request failed
}

This is required for connection-based protocol like TCP, but optional for UDP.

send / sendto

int   send(int fd, const void *buf, int n, int flags);
int sendto(int fd, const void *buf, int n, int flags,
           const struct sockaddr *addr, int addr_len);

Both send() and sendto() sends data stored in buf, but sendto() is only used when you are sending datagrams.

These functions will return the number of bytes actually sent, and it may not match the amount you specified. Therefore it is the responsibility of the application to check for this situation and send the remaining data.

recv / recvfrom

int     recv(int fd, void *buf, int n, int flags);
int recvfrom(int fd, void *buf, int n, int flags,
             const struct sockaddr *addr, int addr_len);

These functions will read data into buf from the network. recvfrom() is used for datagrams. Similar to send(), you must check how much data is actually read.

shutdown

int shutdown(int fd, int how);

This function will shut down all or part of the connection as specified by fd. The parameter how is used to determine:

Constant Usage
SHUT_RD No more receptions
SHUT_WR No more transmissions
SHUT_RDWR Cannot read/write

shutdown() will change read/write permissions for your application, but does not actually close the connection for you. Note that Windows Sockets 2 use different constants. Please see Sockets (Part 2).

close

int close(int fd);

This will close the socket descriptor, and your connection. It is possible for close to fail due to final I/O not finishing. In addition, because the kernel will buffer read/write operations, it may take a brief delay after calling close() for the last byte to be in place.

To Be Continued...

In part 2 of this article we will study socket programming using system calls described here.

Puchu.Net

Document is accessible from http://www.puchu.net. © 2002-2010 Sean Yang, Karen Yang, Don Yang and/or respective authors, all rights reserverd.

This material may contain (biased) opinions, inappropriate materials for numerous individuals, work of other authors from the internet, links that refer to other web documents and resources, or origial work that cannot be use for personal or commercial purposes. Please respect the work of original authors.


Creative Commons License
Powered By MediaWiki

© 2002-2010 Sean Yang, all rights reserved.