msersock.c

Go to the documentation of this file.
00001 /*****************************************************
00002  Programa para testar comunicação usando sockets
00003  **  servidor **
00004 
00005  Versao multiplataforma (Funciona e Linux e em Windows)
00006  Suporta varios clientes simultaneamente
00007 
00008  Marcos A. Stemmer
00009  -------
00010  Ao fazer o projeto no Dev-cpp acrescente a biblioteca libwsock32.a
00011  No menu Project
00012  Submenu Project Options
00013  Tab    Parameters
00014  Botao  Add Library Object
00015  Selecionar o arquivo:
00016  C/Dev-Cpp/lib/libwsock32.a
00017 
00018  *****************************************************/
00019 
00020 #include <stdio.h>
00021 
00022 #ifdef unix
00023 #include <string.h>
00024 #include <errno.h>
00025 #include <stdlib.h>
00026 #include <unistd.h>
00027 #include <sys/types.h>
00028 #include <sys/socket.h>
00029 #include <netdb.h>
00030 #include <netinet/in.h>
00031 #include <arpa/inet.h>
00032 #define closesocket close
00033 #else
00034 #include <winsock2.h>
00035 #endif
00036 
00037 #define PORT 5555
00038 #define MAXMSG 512
00039 #define MAXCLI 64
00040 /* Rotina geral de tratamento de erro fatal
00041  escreve a mensagem e termina o programa */
00042 void erro_fatal(char *mensagem) {
00043         perror(mensagem);
00044         exit(EXIT_FAILURE);
00045 }
00046 
00047 /*Função cria socket para o servidor*/
00048 int cria_soquete_serv(int porta) {
00049         int sock, b;
00050         struct sockaddr_in nome;
00051 
00052         /* Cria um soquete */
00053         sock = socket(PF_INET, SOCK_STREAM, 0);
00054         if (sock < 0)
00055                 erro_fatal("socket");
00056 
00057         /* Preenche os campos da estrutura tipo struct sockaddr_in */
00058         nome.sin_family = AF_INET; /* Seleciona protocolo IPv4 */ //AF_INET - para conexoes com protocolos internet
00059         nome.sin_port = htons(porta); /* Numero da porta de serviço    */
00060         nome.sin_addr.s_addr = htonl(INADDR_ANY); /* Aceita conexões vindas de qualquer IP */
00061 
00062         /* bind: Liga um socket a uma porta de servico */
00063         b = bind(sock, (struct sockaddr *) &nome, sizeof(nome));//bind - junta a socket com a estrutura.
00064         if (b < 0)
00065                 erro_fatal("bind");
00066 
00067         /* Libera para atender conexoes na porta */
00068         /* listen(int socket, int tamanho_da_fila); */
00069         if (listen(sock, 1) < 0)
00070                 erro_fatal("socket");
00071         return sock;
00072 }
00073 
00074 /* Envia uma mensagem atraves do socket */
00075 int envia_pro_cliente(int filedes, char *msg) {
00076         int nbytes;
00077 
00078         nbytes = send(filedes, msg, strlen(msg) + 1, 0);
00079         if (nbytes < 0)
00080                 erro_fatal("send");
00081         return nbytes;
00082 }
00083 
00084 /* Apenas a rotina atende_o_cliente deve ser modificada
00085  para acrescentar novas funcionalidades ao servidor.
00086  * Le uma solicitacao do cliente.
00087  * Se fracassou retorna -1.
00088  * Se ok, processa a solicitacao, e prepara uma resposta
00089  * Retorna o numero de bytes recebidos
00090  */
00091 int atende_o_cliente(int sock) {
00092         char buffer[MAXMSG]; /* Buffer para armazenar a mensagem recebida */
00093         char msgg[MAXMSG];
00094         int nbytes; /* Numer de bytes recebidos */
00095 
00096         nbytes = recv(sock, buffer, MAXMSG - 1, 0); /* Le a mensagem recebida */
00097         if (nbytes <= 0)
00098                 return -1; /* Retorna -1 em caso de erro */
00099 
00100         printf("Recebi do cliente #%d:\n%s\n", sock, buffer); /* mensagem local */
00101         sprintf(msgg,"Vc eh o cliente: %d", sock);
00102         envia_pro_cliente(sock,msgg ); /* Resposta para o cliente */
00103 
00104         return nbytes; /* Se OK retorna o numero de bytes recebido */
00105 }
00106 
00107 int numcli; /* Numero de clientes */
00108 
00109 /* Versão multi-cliente */
00110 int main() {
00111 
00112         int sock_ini, fd_sock;
00113         int i, erro;
00114         struct sockaddr_in clientname;
00115         int cli[MAXCLI]; /* Lista dos Handles dos sockets dos clientes */
00116 
00117         fd_set ativo_fd_set, le_fd_set;
00118         int size;
00119 
00120         /* Esta inicializacao e' necessaria no Windows */
00121 #ifndef unix
00122         WSADATA wsaData;
00123         if (WSAStartup(MAKEWORD(1, 1), &wsaData)) {
00124                 fputs("Erro no WAStartup\n", stderr);
00125         }
00126 #endif
00127 
00128         /* Cria um socket para receber o contato inicial com um cliente */
00129         sock_ini = cria_soquete_serv(PORT);
00130 
00131         printf("Socket inicial: handle=%d\n", sock_ini);
00132 
00133         FD_ZERO(&ativo_fd_set);
00134 
00135         FD_SET(sock_ini, &ativo_fd_set);
00136         numcli = 0;
00137         do {
00138                 /* A funcao select espera que algo aconteca nos sockets */
00139                 le_fd_set = ativo_fd_set;
00140                 erro = select(FD_SETSIZE, &le_fd_set, NULL, NULL, NULL);
00141                 if (erro < 0)
00142                         erro_fatal("select");
00143 
00144                 /* Entra neste if se esta' chegando um novo cliente */
00145                 if (FD_ISSET(sock_ini, &le_fd_set)) {
00146                         if (numcli >= MAXCLI) {
00147                                 fputs("Ultrapassou o numero maximo de clientes.", stderr);
00148                                 continue;
00149                         }
00150 
00151                         size = sizeof(clientname);
00152 
00153                         /* Aceita a conexao e cria um socket para comunicar-se com este cliente */
00154                         fd_sock = accept(sock_ini, (struct sockaddr *) &clientname, &size);
00155 
00156                         if (fd_sock < 0)
00157                                 erro_fatal("accept");
00158 
00159                         printf("Servidor: aceitei conexão do host \"%s\", handle=%d\n",
00160                                         inet_ntoa(clientname.sin_addr), fd_sock);
00161 
00162                         FD_SET(fd_sock, &ativo_fd_set);
00163 
00164                         cli[numcli] = fd_sock; /* Acrescenta na lista */
00165                         numcli++; /* Um cliente a mais */
00166 
00167                         printf("Agora tem %d clientes\n", numcli);
00168                         continue;
00169                 } //para quando tem clientes novos,
00170                 //parte comum para todos os clientes.
00171 
00172                 /* Aqui o cliente ja tem uma conexao estabelecida */
00173                 /* Verifica qual cliente desbloqueou o select */
00174                 for (i = 0; i < numcli; i++) {
00175                         if (!FD_ISSET(cli[i], &le_fd_set))
00176                                 continue;
00177                         /* Quando identificou o cliente, verifica o que ele quer */
00178                         erro = atende_o_cliente(cli[i]);
00179 
00180                         if (erro < 0) { /* atende_o_cliente retorna negativo quando o cliente saiu */
00181 
00182                                 closesocket(cli[i]); /* Fecha o socket deste cliente */
00183                                 FD_CLR(cli[i], &ativo_fd_set); /* Elimina o cliente da lista */
00184 
00185                                 printf("O cliente #%d saiu; ", cli[i]);
00186                                 numcli--; /* Um cliente a menos */
00187 
00188                                 printf("Agora tem %d clientes.\n", numcli);
00189 
00190                                 if (i < numcli) /* Elimina o cliente que saiu da lista de clientes */
00191                                         memmove(cli + i, cli + i + 1, (numcli - i) * sizeof(int));
00192                         }
00193                 }
00194         } while (1);
00195         return 0;
00196 }
00197