Table of Contents

Vortrag/Workshop Einführung in Unix Socket Programmierung

Beispielcode

Es folgen ein paar simple Beispielprogramme die die Verwendung von Sockets unter Unix zeigen. Alle Beispiele und ein kleines Makefile können auch direkt per unten stehendem Link heruntergeladen werden:

socket-examples.tar.gz

Es folgt noch der Code für einen sehr simplen Chat Server anhand dessen die Verwendung des Resolvers (DNS etc.) gezeigt wird.

Beispiel: udpclient

/*
 *  udpclient
 *
 *  This is a very basic UDP client example to show the usage of
 *  sockets. 
 *  
 *  Copyright (C) 2010 Christian Pointner <equinox@realraum.at>
 *
 *  udpclient is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *
 *  udpclient is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with udpclient. If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <arpa/inet.h>

int main(int argc, char** argv)
{
  if(argc <= 2) {
    fprintf(stderr,"too few arguments\n");
    exit(1);
  }
  printf("starting UDP Client\n");

  int sock = socket(AF_INET, SOCK_DGRAM, 0);
  if(sock < 0) { 
    perror("socket() call failed");
    exit(-1);
  }
    
  struct sockaddr_in remote_addr;
  int alen, len;
  alen = sizeof(remote_addr);
  remote_addr.sin_family = AF_INET;
  remote_addr.sin_port = htons(atoi(argv[2]));
  if (inet_aton(argv[1], &remote_addr.sin_addr)==0) {
    perror("inet_aton() call failed");
    exit(-1);
  }

  uint8_t buffer[1500];
  for (;;) {
    if((len = read(0, buffer, 1500))==-1) {
      perror("read() call failed");
      exit(-1);
    }

    if((len = sendto(sock, buffer, len, 0, (struct sockaddr *)&remote_addr, alen))==-1) {
      perror("sendto() call failed");
      exit(-1);
    }
  }

  close(sock);
  
  printf("exiting UDP Client\n");

  return 0;
}

Beispiel: udpserver

/*
 *  udpserver
 *
 *  This is a very basic UDP client example to show the usage of
 *  sockets. 
 *  
 *  Copyright (C) 2010 Christian Pointner <equinox@realraum.at>
 *
 *  udpserver is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *
 *  udpserver is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with udpserver. If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <arpa/inet.h>

int main(int argc, char** argv)
{
  printf("starting UDP Server\n");

  int sock = socket(AF_INET, SOCK_DGRAM, 0);
  if(sock < 0) { 
    perror("socket() call failed");
    exit(-1);
  }
    
  struct sockaddr_in local_addr;
  memset((char *) &local_addr, 0, sizeof(local_addr));
  local_addr.sin_family = AF_INET;
  local_addr.sin_port = htons(1234);
  local_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  if(bind(sock, (struct sockaddr *)&local_addr, sizeof(local_addr))==-1) { 
    perror("bind() call failed");
    exit(-1);
  }

  struct sockaddr_in remote_addr;
  int alen, len;
  alen = sizeof(remote_addr);
  uint8_t buffer[1500];
  for (;;) {
    if((len = recvfrom(sock, buffer, 1500, 0, (struct sockaddr *)&remote_addr, &alen))==-1) {
      perror("recvfrom() call failed");
      exit(-1);
    }

    printf("Received %d Bytes from %s:%d\n", len, inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port));
  }

  close(sock);
  
  printf("exiting UDP Server\n");

  return 0;
}

Beispiel: tcpclient

/*
 *  tcpclient
 *
 *  This is a very basic TCP client example to show the usage of
 *  sockets. 
 *  
 *  Copyright (C) 2010 Christian Pointner <equinox@realraum.at>
 *
 *  tcpclient is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *
 *  tcpclient is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with tcpclient. If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>

#include <arpa/inet.h>

int main(int argc, char** argv)
{
  if(argc <= 2) {
    fprintf(stderr,"too few arguments\n");
    exit(1);
  }
  printf("starting TCP Client\n");

  int sock = socket(AF_INET, SOCK_STREAM, 0);
  if(sock < 0) { 
    perror("socket() call failed");
    exit(-1);
  }
    
  struct sockaddr_in remote_addr;
  remote_addr.sin_family = AF_INET;
  remote_addr.sin_port = htons(atoi(argv[2]));
  if (inet_aton(argv[1], &remote_addr.sin_addr)==0) {
    perror("inet_aton() call failed");
    exit(-1);
  }

  if(connect(sock, (struct sockaddr *)&remote_addr, sizeof(remote_addr))==-1) { 
    perror("connect() call failed");
    exit(-1);
  }

  int len;
  uint8_t buffer[1500];
  for (;;) {
    if((len = read(0, buffer, 1500))==-1) {
      perror("read() call failed");
      exit(-1);
    }

    int offset = 0;
    int wlen;
    for(;;) {
      wlen = send(sock, &buffer[offset], len - offset, 0);
      if(wlen == -1) {
        if(errno != EINTR) {
          perror("write() call failed");
          exit(-1);
        }
        wlen = 0;
      }

      offset += wlen;
      if(offset+1 >= len)
        break;
    }
  }

  close(sock);
  
  printf("exiting TCP Client\n");

  return 0;
}

Beispiel: tcpserver

/*
 *  tcpserver
 *
 *  This is a very basic TCP server example to show the usage of
 *  sockets. 
 *  
 *  Copyright (C) 2010 Christian Pointner <equinox@realraum.at>
 *
 *  tcpserver is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  any later version.
 *
 *  tcpserver is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with tcpserver. If not, see <http://www.gnu.org/licenses/>.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>

#include <sys/select.h>

int main(int argc, char** argv)
{
  printf("starting TCP Server\n");

  int server = socket(AF_INET, SOCK_STREAM, 0);
  if(server < 0) { 
    perror("socket() call failed");
    exit(-1);
  }
    
  struct sockaddr_in local_addr;
  memset((char *) &local_addr, 0, sizeof(local_addr));
  local_addr.sin_family = AF_INET;
  local_addr.sin_port = htons(1234);
  local_addr.sin_addr.s_addr = htonl(INADDR_ANY);

  if(bind(server, (struct sockaddr *)&local_addr, sizeof(local_addr))==-1) { 
    perror("bind() call failed");
    exit(-1);
  }

  if(listen(server, 5)==-1) { 
    perror("listen() call failed");
    exit(-1);
  }

  fd_set readfds, tmpfds;
  FD_ZERO(&readfds);
  FD_SET(server, &readfds);
  int max_fd = server;
  uint8_t buffer[1500];
  struct sockaddr_in remote_addr;
  memset (&remote_addr, 0, sizeof(remote_addr));
  int len, alen=sizeof(remote_addr);
  for (;;) {
    memcpy(&tmpfds, &readfds, sizeof(tmpfds));
    int num = select(max_fd+1, &tmpfds, NULL, NULL, NULL);
    if(num == -1 && errno != EINTR) {
      perror("select() call failed");
      exit(-1);
    }
    if(num == -1 || !num)
      continue;

    if(FD_ISSET(server, &tmpfds)) {
      int new_client = accept(server, (struct sockaddr *)&remote_addr, &alen);
      if(new_client==-1) {
        perror("accept() call failed");
        exit(-1);
      }
      printf("new connection %s:%d (fd=%d)\n", inet_ntoa(remote_addr.sin_addr), ntohs(remote_addr.sin_port), new_client);
      FD_SET(new_client, &readfds);
      max_fd = (max_fd < new_client) ? new_client : max_fd;
      FD_CLR(server, &tmpfds);
    }

    int fd;
    for(fd=0; fd<=max_fd; ++fd) {
      if(FD_ISSET(fd, &tmpfds)) {
        len = recv(fd, buffer, 1500, 0);
        if(len <= 0) {
          if(len < 0) perror("recv() call failed");
          else fprintf(stderr, "client closed connection\n");
          
          printf("removing client (fd=%d)\n", fd);
          FD_CLR(fd, &readfds);
          close(fd);
        }
        else
          printf("Received %d Bytes from client (fd=%d)\n", len, fd);
      }
    }
  }

  close(server);
  
  printf("exiting TCP Server\n");

  return 0;
}