| Winsock & .NET | Winsock | < Socket & Client-server Design Considerations | Linux Socket Index | TCP, UDP Program Examples > |


 

 

 

 

 

NETWORK PROGRAMMING

LINUX SOCKET PART 7 - CODE SNIPPET EXAMPLES

 

 

 

 

 

Menu

 

Network Story 1

Network Story 2

Network Story 3

Network Story 4

Network Story 5

Network Story 6

Socket Example 1

Socket Example 2

Socket Example 3

Socket Example 4

Socket Example 5

Socket Example 6

Socket Example 7

Advanced TCP/IP 1

Advanced TCP/IP 2

Advanced TCP/IP 3

Advanced TCP/IP 4

Advanced TCP/IP 5

 

Working program examples if any compiled using gcc, tested using the public IPs, run on Linux/Fedora Core 3, with several times of update, as normal user.  The Fedora machine used for the testing having the "No Stack Execute" disabled and the SELinux set to default configuration.

 

Iterative, Connectionless Servers (UDP)

 

Creating a Passive UDP Socket

  • The following is a sample codes for a passive UDP socket.

int passiveUDP(const char *service)
{
    return passivesock(service, "udp", 0);
}

u_short portbase = 0;
 
int passivesock(const char *service, const char *transport, int qlen)
{
    struct servent  *pse;
    struct protoent *ppe;
    struct sockaddr_in sin;
    int     s, type;

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = INADDR_ANY;

    /* Map service name to port number */
    if(pse = getservbyname(service, transport))
        sin.sin_port = htons(ntohs((u_short)pse->s_port) + portbase);
    else if((sin.sin_port = htons((u_short)atoi(service))) == 0)
        errexit("can't get \"%s\" service entry\n", service);

    /* Map protocol name to protocol number */
    if((ppe = getprotobyname(transport)) == 0)
        errexit("can't get \"%s\" protocol entry\n", transport);

    /* Use protocol to choose a socket type */
    if(strcmp(transport, "udp") == 0)
        type = SOCK_DGRAM;
    else
        type = SOCK_STREAM;

    /* Allocate a socket */
    s = socket(PF_INET, type, ppe->p_proto);
    if(s < 0)
        errexit("can't create socket: %s\n", strerror(errno));

    /* Bind the socket */
    if(bind(s, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        errexit("can't bind to %s port: %s\n", service, strerror(errno));
    if(type == SOCK_STREAM && listen(s, qlen) < 0)
        errexit("can't listen on %s port: %s\n", service, strerror(errno));
    return s;
}

A TIME Server

/* main() - Iterative UDP server for TIME service */
int main(int argc, char *argv[ ])
{
    struct sockaddr_in fsin;
    char *service = "time";
    char buf[1];
    int sock;
    time_t now;
    int alen;

    sock = passiveUDP(service);

 while (1)
{
     alen = sizeof(fsin);
     if(recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen) < 0)
        errexit("recvfrom: %s\n", strerror(errno));
     time(&now);
     now = htonl((u_long)now);
     sendto(sock, (char *)&now, sizeof(now), 0, (struct sockaddr *)&fsin, sizeof(fsin));
 }
}

Iterative, Connection-Oriented Servers (TCP)

 

A DAYTIME Server

int passiveTCP(const char *service, int qlen)
{
    return passivesock(service, "tcp", qlen);
}

int main(int argc, char *argv[ ])
{
    struct sockaddr_in fsin;
    char *service = "daytime";
    int msock, ssock;
    int alen;

    msock = passiveTCP(service, 5);

    while (1) {
        ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
        if(ssock < 0)
            errexit("accept failed: %s\n", strerror(errno));
        TCPdaytimed(ssock);
        close(ssock);
  }
}

void TCPdaytimed(int fd)
{
    char *pts;
    time_t now;
    char *ctime();

    time(&now);
    pts = ctime(&now);
    write(fd, pts, strlen(pts));
    return;
}

Concurrent, Connection-Oriented Servers (TCP)

 

The Value of Concurrency

A Concurrent Echo Server Using fork()

int main(int argc, char *argv[ ])
{
    char   *service = "echo";  /* service name or port number */
    struct sockaddr_in fsin;   /* the address of a client */
    int alen;                  /* length of client's address */
    int msock;                 /* master server socket  */
    int ssock;                 /* slave server socket */

    msock = passiveTCP(service, QLEN);
    signal(SIGCHLD, reaper);
 while (1)
 {
     alen = sizeof(fsin);
     ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
     if(ssock < 0) {
        if(errno == EINTR)
            continue;
       errexit("accept: %s\n", strerror(errno));
  }
  switch (fork())
 {
     /* child */
     case 0:
       close(msock);
     exit(TCPechod(ssock));
     /* parent */
     default:
       close(ssock);
       break;
     case -1:
        errexit("fork: %s\n", strerror(errno));
   }
   }
}

int TCPechod(int fd)
{
    char  buf[BUFSIZ];
    int   cc;

 while (cc = read(fd, buf, sizeof buf))
 {
        if(cc < 0)
            errexit("echo read: %s\n", strerror(errno));
        if(write(fd, buf, cc) < 0)
            errexit("echo write: %s\n", strerror(errno));
  }
    return 0;
}

void reaper(int sig)
{
    int status;

    while (wait3(&status, WNOHANG, (struct rusage *)0) >= 0)
    /* empty ;*/
}

Single-Process, Concurrent Servers (TCP)

 

Data-driven Processing

  • Arrival of data triggers processing.

  • A message is typically a request.

  • Server replies and awaits additional requests.

  • If processing time is small, the requests may be possible to handle sequentially.

  • Timesharing would be necessary only when the processing load is too high for sequential processing.

  • Timesharing with multiple slaves is easier.

Using Select for Data-driven Processing

  • A process calls select to wait for one (or more) of a collection of open files (or sockets) to be ready for I/O.

int select(int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

FD_CLR(int fd, fd_set *set);
FD_ISSET(int fd, fd_set *set);
FD_SET(int fd, fd_set *set);
FD_ZERO(fd_set *set);

An ECHO Server using a Single Process

int main(int argc, char *argv[ ])
{
    char   *service = "echo";
    struct sockaddr_in fsin;
    int    msock;
    fd_set rfds;
    fd_set afds;
    int    alen;
    int    fd, nfds;
    msock = passiveTCP(service, QLEN);
 
    nfds = getdtablesize();
    FD_ZERO(&afds);
    FD_SET(msock, &afds);

    while (1) {
        memcpy(&rfds, &afds, sizeof(rfds));

      if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
            errexit("select: %s\n", strerror(errno));
        if(FD_ISSET(msock, &rfds))
 {
    int ssock;

    alen = sizeof(fsin);
    ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
    if(ssock < 0)
       errexit("accept: %s\n", strerror(errno));
     FD_SET(ssock, &afds);
   }
   for(fd=0; fd < nfds; ++fd)
     if(fd != msock && FD_ISSET(fd, &rfds))
        if(echo(fd) == 0)
          {
              (void) close(fd);
              FD_CLR(fd, &afds);
           }
    }
}

int echo(int fd)
{
    char buf[BUFSIZ];
    int  cc;

    cc = read(fd, buf, sizeof buf);
    if(cc < 0)
        errexit("echo read: %s\n", strerror(errno));
    if(cc && write(fd, buf, cc) < 0)
        errexit("echo write: %s\n", strerror(errno));
    return cc;
}

Multiprotocol Servers

 

Why use multiple protocols in a server?

A Multiprotocol DAYTIME Server

int main(int argc, char *argv[])
{
    char   *service = "daytime"; /* service name or port number */
    char   buf[LINELEN+1];       /* buffer for one line of text */
    struct sockaddr_in fsin;     /* the request from address */
    int    alen;                 /* from-address length  */
    int    tsock;                /* TCP master socket  */
    int    usock;                /* UDP socket  */
    int    nfds;
    fd_set rfds;                 /* readable file descriptors */

    tsock = passiveTCP(service, QLEN);
    usock = passiveUDP(service);
    /* bit number of max fd */
    nfds = MAX(tsock, usock) + 1;

    FD_ZERO(&rfds);

    while (1) {
        FD_SET(tsock, &rfds);
        FD_SET(usock, &rfds);

        if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
            errexit("select error: %s\n", strerror(errno));
        if(FD_ISSET(tsock, &rfds))
       {
            /* TCP slave socket */
            int ssock; 
            alen = sizeof(fsin);
            ssock = accept(tsock, (struct sockaddr *)&fsin, &alen);
            if(ssock < 0)
                errexit("accept failed: %s\n", strerror(errno));
            daytime(buf);
            (void) write(ssock, buf, strlen(buf));
            (void) close(ssock);
        }
  if(FD_ISSET(usock, &rfds))
 {
   alen = sizeof(fsin);
   if(recvfrom(usock, buf, sizeof(buf), 0, (struct sockaddr *)&fsin, &alen) < 0)
      errexit("recvfrom: %s\n", strerror(errno));
   daytime(buf);
   (void) sendto(usock, buf, strlen(buf), 0, (struct sockaddr *)&fsin, sizeof(fsin));
   }
  }
}

int daytime(char buf[])
{
    char   *ctime();
    time_t now;
 
    (void) time(&now);
    sprintf(buf, "%s", ctime(&now));
}

 

Multiservice Servers

 

Why combine services into one server?

Iterative Connectionless Server Design

Iterative Connection-Oriented Server Design

Concurrent Connection-Oriented Server Design

Single-Process Server Design

Invoking Separate Programs from a Server

Multiservice, Multiprotocol Servers

Super Server Code Example

 

 

 

 

 

 

 

 

 

 

 

 

struct service {
    char  *sv_name;
    char  sv_useTCP;
    int   sv_sock;
    int   (*sv_func)(int);
};

struct service svent[ ] = {
    { "echo", TCP_SERV, NOSOCK, TCPechod },
    { "chargen", TCP_SERV, NOSOCK, TCPchargend },
    { "daytime", TCP_SERV, NOSOCK, TCPdaytimed },
    { "time", TCP_SERV, NOSOCK, TCPtimed },
    { 0, 0, 0, 0 },
};

int main(int argc, char *argv[ ])
{
    struct service  *psv,    /* service table pointer */
            *fd2sv[NOFILE];  /* map fd to service pointer */
    int     fd, nfds;
    fd_set  afds, rfds;      /* readable file descriptors */

    nfds = 0;
    FD_ZERO(&afds);
    for(psv = &svent[0]; psv->sv_name; ++psv)
 {
        if(psv->sv_useTCP)
            psv->sv_sock = passiveTCP(psv->sv_name, QLEN);
        else
            psv->sv_sock = passiveUDP(psv->sv_name);
        fd2sv[psv->sv_sock] = psv;
        nfds = MAX(psv->sv_sock+1, nfds);
        FD_SET(psv->sv_sock, &afds);
  }
 
  (void) signal(SIGCHLD, reaper);

    while (1) {
      memcpy(&rfds, &afds, sizeof(rfds));
      if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0)
       {
         if(errno == EINTR)
           continue;
         errexit("select error: %s\n", strerror(errno));
       }
        for(fd=0; fd<nfds; ++fd)
        {
            if(FD_ISSET(fd, &rfds))
            {
                psv = fd2sv[fd];
                if(psv->sv_useTCP)
                   doTCP(psv);
                else
                   psv->sv_func(psv->sv_sock);
            }
          }
    }
}

/* doTCP() - handle a TCP service connection request */
void doTCP(struct service *psv)
{
    /* the request from address */
    struct  sockaddr_in fsin;
    /* from-address length */
    int alen;
    int fd, ssock;

    alen = sizeof(fsin);
    ssock = accept(psv->sv_sock, (struct sockaddr *)&fsin, &alen);
    if(ssock < 0)
        errexit("accept: %s\n", strerror(errno));
    switch (fork())
   {
    case 0: 
        break;
    case -1:
        errexit("fork: %s\n", strerror(errno));
    default:
        (void) close(ssock);
        /* parent */
        return;
    }
    /* child */
    for(fd = NOFILE; fd >= 0; --fd)
        if(fd != ssock) (void) close(fd);
    exit(psv->sv_func(ssock));
}

/* reaper() - clean up zombie children */
void reaper(int sig)
{
    int status;
    while(wait3(&status, WNOHANG, (struct rusage *)0) >= 0)
    /* empty */;
}

Continue on next Moduleā€¦

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

 

  1. Check the best selling C / C++, Networking, Linux and Open Source books at Amazon.com.

  2. GCC, GDB and other related tools.

 

 

 

 

 

 


 

| Winsock & .NET | Winsock | < Socket & Client-server Design Considerations | Linux Socket Index | TCP, UDP Program Examples > |