Ferramentas do usuário

Ferramentas do site


exemplo_eco

Diferenças

Aqui você vê as diferenças entre duas revisões dessa página.


exemplo_eco [2023/09/12 16:14] (atual) – criada - edição externa 127.0.0.1
Linha 1: Linha 1:
 +====== 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.
 +
 +<code c>
 +#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);
 +}
 +</code>
 +
 +===== 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.
 +<code c>
 +#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;
 +}
 +</code>
 +
 +===== 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 [[sinal|sinais SIGCHLD]] fará com que o sistema operacional entregue apenas o último.
 +
 +<code 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);
 +   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;
 +}
 +</code>
 +
 +===== 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.
 +
 +<code c>
 +/* 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;
 +}
 +</code>
 +
 +===== Servidor de ECO tratando múltiplos clientes com threads POSIX =====
 +
 +Este exemplo trabalha com as [[threads_posix|threads POSIX]] do Linux.
 +<code c>
 +#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;
 +}
 +</code>
 +
 +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.
 +
 +<code c>
 +#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;
 +}
 +</code>
 +
 + --- //[[marcos@laureano.eti.br|Marcos Laureano]] 2009/02/14 12:30//
exemplo_eco.txt · Última modificação: 2023/09/12 16:14 por 127.0.0.1