Отправляет email-рассылки с помощью сервиса Sendsay
  Все выпуски  

Сетевое программирование в UNIX


Информационный Канал Subscribe.Ru


Сетевое программирование в UNIX

Выпуск No. 2

Здравствуйте, дорогие подписчики!

Большинство сетевых приложений могут подразделяться на две части: клиент и сервер. Мы можем нарисовать канал связи между ними:

Клиенты обычно взаимодействуют с одним сервером за раз, хотя, используя, например, Web-броузеры мы можем взаимодействовать со многими различными Web-серверами, скажем, за 10-минутный промежуток времени. Но с точки зрения сервера, в данной точки времени, сервер может взаимодействовать с несколькими клиентами (рис.1.2)

Давайте, рассмотрим, специальный пример, который включает в себя множество концепций и терминов которыми мы будем оперировать далее. Ниже приведен пример реализации TCP - time-of-day клиента. Клиент устанавливает TCP соединение с сервером, а сервер просто посылает обратно текущее время и дату в читабельном формате.

/* File:  daytimetcpcli.c 
 * Establish connection to server and receive current data and time
*/
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

#include "errorx.h"

#define MAXLINE 4096
#define SA struct sockaddr

int main(int argc, char **argv)
{
  int sockfd,n;
  char recvline[MAXLINE + 1];
  struct sockaddr_in servaddr,myaddr;
  socklen_t len=sizeof(myaddr);
  
  if(argc !=2) 
    err_quit("usage: %s <IP-address>", argv[0]);

  if( (sockfd = socket(AF_INET,SOCK_STREAM,0) ) < 0)
    err_sys("socket error");
  
  bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(13);
  
  if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr) <=0)
    err_quit("inet_pton error for %s",argv[1]);

  if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(myaddr)) < 0)
    err_sys("connect error");
  
  while ( (n = read(sockfd,recvline,MAXLINE)) > 0)
  {
    recvline[n] = 0;
    if(fputs(recvline,stdout) == EOF)
      err_sys("fputs error");
  }
  if(n < 0)
    err_sys("read error");

  exit(0);
}

Простой TCP daytime клиент

Мы использовали наш собственный заголовочный файл errorx.h обработчика ошибок

/* File: errorx.h
 * Our header file error handler
*/
#define MAXLINE 4096

void err_sys(const char *, ...);
void err_quit(const char *, ...);
void err_ret(const char *, ...);
void err_dump(const char *,...);
void pr_exit (int);

Ниже приведен файл errorx.c - сами функции обработки ошибок.

/* File: errorx.c
 * Our Error handler functions
*/
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "errorx.h"

static void err_doit(int, const char *, va_list);

char  *pname=NULL;


void err_sys(const char *fmt, ...)
{
  va_list ap;

  va_start(ap,fmt);
  err_doit(1,fmt,ap);
  va_end(ap);

  exit(1);
}


void err_quit(const char *fmt, ...)
{
  va_list  ap;
 
  va_start(ap, fmt);
  err_doit(0,fmt,ap);
  va_end(ap);

  exit(1);
}


static void err_doit(int errnoflag, const char *fmt, va_list ap)
{
  int errno_save;
  char buf[MAXLINE];

  errno_save=errno;   
  vsprintf(buf,fmt,ap);
  if(errnoflag)
      sprintf(buf+strlen(buf), ": %s", strerror(errno_save));
  strcat(buf, "\n");
  fflush(stdout);
  fputs(buf,stderr);
  fflush(NULL);

  return;
}

/* Non fatal error related to a system call.
   Print a mrssage and return 
*/
void err_ret(const char *fmt, ...)
{
  va_list  ap;
  va_start (ap,fmt);
  err_doit(1, fmt, ap);
  va_end(ap);

  return;
}

/* Fatal error related to a system call.
   Print a message, dump core, and terminate
   */
void err_dump(const char *fmt,...)
{
  va_list ap;

  va_start(ap,fmt);
  err_doit(1,fmt,ap);
  va_end(ap);

  abort();   // dump core and terminate
}

void pr_exit (int status) {
  if( WIFEXITED(status))
    printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
  else if (WIFSIGNALED(status)) 
    printf("abnormal termination, signal number %d%s\n",WTERMSIG(status),
#ifdef WCOREDUMP
 WCOREDUMP(status) ? " (core file generated)" :"");
#else
   "");
#endif
     else if (WIFSTOPPED(status))
   printf("child stopped, signal number = %d\n", WSTOPSIG(status));
}

Компилируем следующим образом. Считаем, что у нас установлен компилятор gcc.

#  gcc -Wall  -o daytimetcpcli daytimetcpcli.c errorx.c
#  ./daytimetcpcli  localhost
Mon  Mar  9  14:27:52   2004

Клиент соединятется с сервером даты-времени, который висит на 13 порту и получает с него текущие время и дату.

Итак, рассмотрим основные моменты программы. Если сейчас что-то непонятно по ее работе, то ничего страшного - мы все это еще разберем подробнее в следующих выпусках:

1. Создаем TCP -сокет

Функция socket() создает Internet (AF_INET) потоковый (SOCK_STREAM) сокет, т.е. TCP сокет. Функция возвращает целое число - дескриптор - который мы будем использовать для идентификации сокета во всех последующих вызовах сетевых функций.

  if( (sockfd = socket(AF_INET,SOCK_STREAM,0) ) < 0)
    err_sys("socket error");

А также поверяем, что функция отработала без ошибок, в противном случае вызываем err_sys() - нашу функцию - обработчик ошибки. Она выводит сообщение об ошибке и прерывает выполнение программы. Более подробно - см. файл errorx.c

2. Указываем IP адрес сервера и порт

Мы заполняем структуру Internet-адреса IP адресом сервера и номером порта


  bzero(&servaddr,sizeof(servaddr));
  servaddr.sin_family = AF_INET;
  servaddr.sin_port = htons(13);

  if(inet_pton(AF_INET,argv[1],&servaddr.sin_addr) <=0)
    err_quit("inet_pton error for %s",argv[1]);

Мы полагаем, что сервер даты-времени слушает на 13 порту. Поля IP адреса и номера порта - должны быть в определенном формате, поэтому мы вызываем системную функцию htons(), для преобразования двоичного номера порта и функцию inet_pton(), чтобы конвертировать ASCII строку (такую как 127.0.0.1) в соответствующий формат.

3. Установка соединения с сервером

Функция connect(), примененная к TCP сокету, устанавливает TCP соединение с сервером, на который указывает структура адреса, переданная в качестве второго аргумента.


  if(connect(sockfd, (struct sockaddr *) &servaddr, sizeof(myaddr)) < 0)
    err_sys("connect error");


Мы также должны указать длину структуры - третий аргумент.

4 . Чтение ответа от сервера

Далее в цикле читаем ответ от сервера - по сути просто читаем из файла, пока не получим конец файла и завершаем работу программы.

На сегодня пока все!


http://subscribe.ru/
E-mail: ask@subscribe.ru
Отписаться
Убрать рекламу

В избранное