====== 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 #include #include #include #include #include #include #include #include #include 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 [[sinal|sinais SIGCHLD]] fará com que o sistema operacional entregue apenas o último. #include #include #include #include #include #include #include #include #include #include #include #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 #include #include #include #include #include #include #include #include #include #include #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|threads POSIX]] do Linux. #include #include #include #include #include #include #include #include #include #include #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 #include #include #include #include #include #include #include #include #include #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.eti.br|Marcos Laureano]] 2009/02/14 12:30//