Servidor de ECO

Um servidor de ECO simplesmente recebe uma mensagem e retorna a mesma mensagem (eco) sem modificações.

Cliente TCP de ECO

Este cliente recebe uma mensagem via linha de comando e envia 10 vezes (1 por segundo) para o servidor de eco.

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>
 
int main(int argc, char ** argv )
{
   int iSock;
   int iBytes;
 
   struct sockaddr_in dest_addr;
   char buffer1[100];
   char buffer[100];
   int iContador;
 
   iSock = socket(AF_INET, SOCK_STREAM, 0);
 
   if( iSock == -1)
   {
      perror("socket:");
      exit(1);
   }
 
   dest_addr.sin_family = AF_INET;
   dest_addr.sin_port = htons(4950);
   dest_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
   bzero(&(dest_addr.sin_zero), 8);
 
   if( connect(iSock, (struct sockaddr *)&dest_addr, sizeof(struct sockaddr)) < 0)
   {
      perror("connect:");
      exit(1);
   }
 
   for( iContador = 0; iContador < 10; iContador ++)
   {
      sprintf(buffer1, "%s %s %d", argv[1], ":Teste de eco", iContador+1);
      printf("\nEnviando [%s]", buffer1);
 
      if ((iBytes=send(iSock, buffer1, 100, 0)) < 0 )
      {
         perror("send");
         exit(1);
      }
      memset(buffer, 0, sizeof(buffer));
 
      if ((iBytes=recv(iSock, buffer, 100, 0)) < 0 )
      {
         perror("recv");
         exit(1);
      }
 
      buffer[iBytes] = '\0';
      printf("Recebido: %s\n",buffer);
      sleep(1);
   }
 
   close(iSock);
}

Servidor TCP tratando múltiplos clientes com a função select

Este exemplo utiliza a função select para receber e responder para um determinado cliente.

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/un.h>
#include <sys/select.h>
 
#define MAXLINE 4096
 
 
int MySocket(int iFamily, int iType, int iProtocol)
{
   int iBytes;
 
   if ( (iBytes = socket(iFamily, iType, iProtocol)) < 0)
   {
      perror("socket error");
   }
   return(iBytes);
}
 
void MyBind(int iFd, const struct sockaddr *sa, socklen_t iLen)
{
   if (bind(iFd, sa, iLen) < 0)
   {
      perror("bind error");
   }
   return;
}
 
void MyListen(int iFd, int backlog)
{
   if (listen(iFd, backlog) < 0)
   {
      perror("listen error");
   }
   return;
}
 
int MySelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout)
{
   int iBytes;
 
   if ( (iBytes = select(nfds, readfds, writefds, exceptfds, timeout)) < 0)
   {
      perror("select error");
   }
   return(iBytes); 
}
 
int MyAccept(int iFd, struct sockaddr *sa, socklen_t *salenptr)
{
   int iSocket;
 
   if ( (iSocket = accept(iFd, sa, salenptr)) < 0) 
   {
      perror("accept error");
   }
   return(iSocket);
}
 
void MyClose(int iFd)
{
   if (close(iFd) == -1)
   {
      perror("close error");
   }
   return;
}
 
int main(int argc, char **argv)
{
    int	i, maxi, maxfd, listenfd, connfd, sockfd;
    int	nready, client[FD_SETSIZE];
    ssize_t n;
    fd_set rset, allset;
    char buf[MAXLINE];
    socklen_t clilen;
    struct sockaddr_in cliaddr, servaddr;
 
    listenfd = MySocket(AF_INET, SOCK_STREAM, 0);
 
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family      = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port        = htons(4950);
 
    MyBind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr));
 
    MyListen(listenfd, 10);
 
    maxfd = listenfd; /* 1 conexao */
    maxi = -1;        /* indice do vetor que vai conter todos os sockets abertos */
    for (i = 0; i < FD_SETSIZE; i++)
    {
       client[i] = -1; /* inicializando o vetor */
    }
    FD_ZERO(&allset);
    FD_SET(listenfd, &allset);
 
    while(1)
    {
       rset = allset; /* zerando a estrutura */
       nready = MySelect(maxfd+1, &rset, NULL, NULL, NULL);
 
       if (FD_ISSET(listenfd, &rset)) /* eh uma nova conexao ?*/
       {
          clilen = sizeof(cliaddr);
          connfd = MyAccept(listenfd, (struct sockaddr *) &cliaddr, &clilen);
          printf("\nServidor recebeu conexao de %s:%d", inet_ntoa(cliaddr.sin_addr), ntohs(cliaddr.sin_port));
 
          for (i = 0; i < FD_SETSIZE; i++)
          {
             if (client[i] < 0)
             {
	        client[i] = connfd; /* salva o descritor no vetor */
                break;
             }
          }
          if (i == FD_SETSIZE)
          {
             perror("Muitos Clientes");
             exit(1);
          }
 
          FD_SET(connfd, &allset); /* adiciona o novo descritor na estrutura */
          if (connfd > maxfd)
          {
             maxfd = connfd; /* maior descritor possivel, utilizado no select */
          }
          if (i > maxi)
          {
             maxi = i; /* maximo de clientes */
          }
 
          if (--nready <= 0)
          {
             continue; /* se não houve mais descritores, volta para o select */
          }
       }
 
       for (i = 0; i <= maxi; i++) /* verifica se os clientes tem dados */
       {
          if ( (sockfd = client[i]) < 0)
          {
             continue;
          }
          if (FD_ISSET(sockfd, &rset)) 
          {
             if ( (n = recv(sockfd, buf, MAXLINE,0)) <= 0) /* le o cliente, se não tiver dados, fecha a conexão */
             {
                MyClose(sockfd);
                FD_CLR(sockfd, &allset);
                client[i] = -1;
             } 
             else
             {
                printf("\nsockfd =%d, n = %d, buffer=[%s]", sockfd, n, buf); /* envia o eco para o cliente */
                send(sockfd, buf, n, 0); 
             }
 
             if (--nready <= 0)
             {
                break;
             }
          }
       }
   }
   return 0;
}

Servidor TCP tratando múltiplos clientes com fork/wait

Este servidor utiliza as funções fork e wait para tratamento de vários clientes. Neste exemplo, caso vários clientes terminem simultâneamente, a função wait deixa de capturar a interrupção de fim de algum filho e este processo ficará como defunct no sistema. Isto ocorre devido ao sistema não infileirar todos os sinais recebidos, ou seja, 2 sinais SIGCHLD fará com que o sistema operacional entregue apenas o último.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
 
#define MAXLINE 4096
 
/* função que irá verificar o status dos processos filhos */
void signal_handler_function(int iSignal)
{
   pid_t iPid;
   int iStatus;
   fprintf(stderr, "\nRecebido o sinal %d.", iSignal);
   iPid = wait(&iStatus);
 
   fprintf(stderr, "\nProcesso %d terminou.", iPid);
   if( WIFEXITED(iStatus) )
   {
      fprintf(stderr, " Terminou OK com status %d.\n",  WEXITSTATUS(iStatus));
   }
   else if(WIFSIGNALED(iStatus))
   {
      fprintf(stderr, " Terminou de forma anormal com status %d.\n",  WTERMSIG(iStatus));
   }
   else if(WIFSTOPPED(iStatus))
   {
      fprintf(stderr, " Paralisado por sinal %d.\n",  WSTOPSIG(iStatus));
   }
   return;
}
 
int main(void)
{
   pid_t iFilho;
   int iSock;
   struct sockaddr_in my_addr;
 
  /* registrando sinal da função para tratar do filho */
  if( signal(SIGCHLD , signal_handler_function) == SIG_ERR )
  {
     perror("signal:");
     exit(1);
  }
 
   iSock = socket(AF_INET, SOCK_STREAM, 0);
   if( iSock == -1)
   {
      perror("socket:");
      exit(1);
   }
 
   my_addr.sin_family = AF_INET;
   my_addr.sin_port = htons(4950);
   my_addr.sin_addr.s_addr = INADDR_ANY;
   bzero(&(my_addr.sin_zero), 8);
 
   if( bind(iSock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
   {
      perror("bind:");
      exit(1);
   }
 
   if( listen( iSock, 10 ) < 0)
   {
      perror("listen:");
      exit(1);
   }
 
   while(1)
   {
      int iFd;
      struct sockaddr_in client_addr;
      socklen_t sin_size;
      char szMensagem[100];
 
      sin_size = sizeof(struct sockaddr_in);
 
      if( (iFd = accept(iSock, (struct sockaddr *) &client_addr, &sin_size)) < 0)
      {
         perror("accept:");
         exit(1);
      }
 
      printf("\nServidor recebeu conexao de %s\n", inet_ntoa(client_addr.sin_addr));
      iFilho = fork();
      printf("Filho %d conexão %d", iFilho, iFd);
      if( iFilho < 0)
      {
         perror("fork:");
         exit(1);
      }
 
      if( iFilho == 0) /* processo filho */
      {
         char buf[MAXLINE];
         ssize_t nBytes;
         while( (nBytes = recv(iFd, buf, MAXLINE,0)) > 0) /* le o cliente, se não tiver dados, fecha a conexão */
         {
            send(iFd, buf, nBytes, 0); 
         } 
         close(iFd); /* fecha no filho */
         exit(0); /* termina o filho */
      }
      close(iFd); /* fecha a conexão no pai, o filho fica aberto */
   }
   return 0;
}

Servidor TCP tratando múltiplos clientes com fork/waitpid

Este servidor utiliza as funções fork e waitpid para tratamento de vários clientes. Neste exemplo, caso vários clientes terminem simultâneamente, a função waitpid consegue capturar a interrupção de fim de todos os filhos.

/* servidor_eco_forktcp_waitpid.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <signal.h>
 
#define MAXLINE 4096
 
/* função que irá verificar o status dos processos filhos */
void signal_handler_function(int iSignal)
{
   pid_t iPid;
   int iStatus;
   fprintf(stderr, "\nRecebido o sinal %d.", iSignal);
   /* espera qualquer filho terminar sem bloquear o processo. Com wait
      ocorre a possibilidade de perder-se sinais de alguns filhos, gerando
      processos defunct. */
   while( (iPid = waitpid(-1, &iStatus, WNOHANG)) > 0)
   {
      fprintf(stderr, "\nProcesso %d terminou.", iPid);
      if( WIFEXITED(iStatus) )
      {
         fprintf(stderr, " Terminou OK com status %d.\n",  WEXITSTATUS(iStatus));
      }
      else if(WIFSIGNALED(iStatus))
      {
         fprintf(stderr, " Terminou de forma anormal com status %d.\n",  WTERMSIG(iStatus));
      }
      else if(WIFSTOPPED(iStatus))
      {
         fprintf(stderr, " Paralisado por sinal %d.\n",  WSTOPSIG(iStatus));
      }
   }
   return;
}
 
int main(void)
{
   pid_t iFilho;
   int iSock;
   struct sockaddr_in my_addr;
 
  /* registrando sinal da função para tratar do filho */
  if( signal(SIGCHLD , signal_handler_function) == SIG_ERR )
  {
     perror("signal:");
     exit(1);
  }
 
   iSock = socket(AF_INET, SOCK_STREAM, 0);
   if( iSock == -1)
   {
      perror("socket:");
      exit(1);
   }
 
   my_addr.sin_family = AF_INET;
   my_addr.sin_port = htons(4950);
   my_addr.sin_addr.s_addr = INADDR_ANY;
   bzero(&(my_addr.sin_zero), 8);
 
   if( bind(iSock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
   {
      perror("bind:");
      exit(1);
   }
 
   if( listen( iSock, 10 ) < 0)
   {
      perror("listen:");
      exit(1);
   }
 
   while(1)
   {
      int iFd;
      struct sockaddr_in client_addr;
      socklen_t sin_size;
      char szMensagem[100];
 
      sin_size = sizeof(struct sockaddr_in);
 
      if( (iFd = accept(iSock, (struct sockaddr *) &client_addr, &sin_size)) < 0)
      {
         perror("accept:");
         exit(1);
      }
 
      printf("\nServidor recebeu conexao de %s\n", inet_ntoa(client_addr.sin_addr));
      iFilho = fork();
      if( iFilho < 0)
      {
         perror("fork:");
         exit(1);
      }
      if( iFilho != 0 )
      {
         printf("\nGerado filho %d para a conexão %d", iFilho, iFd);
      }
 
      if( iFilho == 0) /* processo filho */
      {
         char buf[MAXLINE];
         ssize_t nBytes;
         while( (nBytes = recv(iFd, buf, MAXLINE,0)) > 0) /* le o cliente, se não tiver dados, fecha a conexão */
         {
            send(iFd, buf, nBytes, 0); 
         } 
         close(iFd); /* fecha no filho */
         exit(0); /* termina o filho */
      }
      close(iFd); /* fecha a conexão no pai, o filho fica aberto */
   }
   return;
}

Servidor de ECO tratando múltiplos clientes com threads POSIX

Este exemplo trabalha com as threads POSIX do Linux.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
 
#include <pthread.h>
 
#define MAXLINE 4096
 
static int siFd;
 
void * trata_conexao(void * pArg )
{
   int iFd = siFd;
   char buf[MAXLINE];
   ssize_t nBytes;
 
   fprintf(stderr, "\nExecutando a thread = %d = %d", pthread_self(), iFd);
   while( (nBytes = recv(iFd, buf, MAXLINE,0)) > 0) /* le o cliente, se não tiver dados, fecha a conexão */
   {
      send(iFd, buf, nBytes, 0); 
   } 
   close(iFd); 
 
   pthread_exit(0);
}
 
int main(void)
{
   static int iSock;
   struct sockaddr_in my_addr;
 
   iSock = socket(AF_INET, SOCK_STREAM, 0);
   if( iSock == -1)
   {
      perror("socket:");
      exit(1);
   }
 
   my_addr.sin_family = AF_INET;
   my_addr.sin_port = htons(4950);
   my_addr.sin_addr.s_addr = INADDR_ANY;
   bzero(&(my_addr.sin_zero), 8);
 
   if( bind(iSock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
   {
      perror("bind:");
      exit(1);
   }
 
   if( listen( iSock, 10 ) < 0)
   {
      perror("listen:");
      exit(1);
   }
 
   while(1)
   {
      struct sockaddr_in client_addr;
      socklen_t sin_size;
      pthread_t tId;
 
      sin_size = sizeof(struct sockaddr_in);
 
      if( (siFd = accept(iSock, (struct sockaddr *) &client_addr, &sin_size)) < 0)
      {
         perror("accept:");
         exit(1);
      }
      printf("\nServidor recebeu conexao de %s\n", inet_ntoa(client_addr.sin_addr));
      pthread_create(&tId, NULL, trata_conexao, NULL);
   }
   return 0;
}

Este outro exemplo é só para ilustrar que o programa pode fazer outras coisas, para isto tem-se uma thread que recebe as conexões e chama outras threads para tratamento individual da conexão.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
 
#include <pthread.h>
 
#define MAXLINE 4096
 
void * trata_conexao(void * pArg)
{
   int iFd = *((int *)pArg); /* cópia do ponteiro */
   char buf[MAXLINE];
   ssize_t nBytes;
   pthread_detach( pthread_self()); /* libera os recursos da thread */
 
   fprintf(stderr, "\nExecutando a thread = %d - %d", pthread_self(), iFd);
   while( (nBytes = recv(iFd, buf, MAXLINE,0)) > 0) /* le o cliente, se não tiver dados, fecha a conexão */
   {
      send(iFd, buf, nBytes, 0); 
   } 
   close(iFd); 
 
   pthread_exit(0); /* finaliza a thread */
}
 
void * aceita_conexao(void * pArg)
{
   int iFd, iSock;
   struct sockaddr_in my_addr;
 
   iSock = socket(AF_INET, SOCK_STREAM, 0);
   if( iSock == -1)
   {
      perror("socket:");
      exit(1);
   }
 
   my_addr.sin_family = AF_INET;
   my_addr.sin_port = htons(4950);
   my_addr.sin_addr.s_addr = INADDR_ANY;
   bzero(&(my_addr.sin_zero), 8);
 
   if( bind(iSock, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
   {
      perror("bind:");
      exit(1);
   }
 
   if( listen( iSock, 10 ) < 0)
   {
      perror("listen:");
      exit(1);
   }
 
   while(1)
   {
      struct sockaddr_in client_addr;
      socklen_t sin_size;
      pthread_t tId;
 
      sin_size = sizeof(struct sockaddr_in);
 
      if( (iFd = accept(iSock, (struct sockaddr *) &client_addr, &sin_size)) < 0)
      {
         perror("accept:");
         exit(1);
      }
      fprintf(stderr,"\nServidor recebeu conexao de %s\n", inet_ntoa(client_addr.sin_addr));
 
      if( pthread_create(&tId, NULL, trata_conexao, &iFd) != 0) /* passando o file descriptor por ponteiro */
      {
         perror("pthread_create:");
         exit(1);
      }
   }
 
   pthread_exit(0); /* finaliza a thread */
}
 
int main(void)
{
   pthread_t tId;
 
   pthread_create(&tId, NULL, aceita_conexao, NULL);
 
   while(1)
   {
      fprintf(stderr, "\nFazendo outra coisa...");
      sleep(5);
   }
   return 0;
}

Marcos Laureano 2009/02/14 12:30

exemplo_eco.txt · Última modificação: 2009/02/22 05:02 por laureano
CC Attribution-Noncommercial-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0