Problemas com Sockets em C

1. Problemas com Sockets em C

Carlos Eduardo Castro da Silva
eduinfo10

(usa Ubuntu)

Enviado em 09/04/2014 - 21:14h

Boa Noite Pessoal,

Preciso fazer uma espécie de QUIZ com sockets.

Consegui fazer boa parte do código.

A idéia é a seguinte:

O cliente responde 10 perguntas (operações matemáticas), logo que ele coloca o valor da conta, este valor vai para o servidor, e lá compara se a resposta corresponde ao resultado, se corresponder, manda uma mensagem de correto para o cliente e conta 1 para depois no fim poder dizer quantas ele acertou, e o mesmo procedimento é feito se o cara errar a conta.

Só não estou conseguindo mandar para o cliente o valor dos contadores, pois os contadores são "int", e o socket só envia tipo "char". Já tentei converter usando a função sprintf, mas não rolou. Alguem me da uma luz ? Vou postar o código do cliente e do servidor logo abaixo. Lembrando que tudo está correto, apenas preciso arrumar o final dos dois códigos, para enviar o resultado dos contadores para o cliente. E não faço a menor ideia como faz ...

Obrigado.



***************************************** Servidor ***************************************

/*--------------------------------------------
Função que usa o TCP para receber uma mensagem
do cliente. O parametro de entrada desta função
é o número da porta do socket
----------------------------------------------*/

#include <stdio.h> //printf e scanf
#include <stdlib.h> //exit
#include <string.h> //sizeof
#include <unistd.h>
#include <sys/types.h> //tipos de dados para chamadas de sistemas
#include <sys/socket.h> //estrutura de dados para sockets (structs)
#include <netinet/in.h> //estrutura de dados para acesso a internet (structs)



/*--------------------------------------------
função chamada quando ocorre um erro
em uma chamada de sistema
----------------------------------------------*/




void error(const char *msg) //inicio da função
{
perror(msg); //função que apresenta mensagem na tela sobre o erro
exit(1); //termina o processo
} //fim da função

/*--------------------------------------------
função main que recebe o número
da porta como parametro
----------------------------------------------*/

int main(int argc,char *argv[])
{
/*--------------------------------------------
sockfd: socket file description
- cada processo tem um número que representa
uma linha na tabela descritora de arquivos
- recebe valor da chamada de sistema socket

newsockfd: new socket file description
- recebe valor da chamada de sistema accept

portno: guarda o número da porta usada pelo
servidor para aceitar as conexões
----------------------------------------------*/

int sockfd, newsockfd, portno;
socklen_t clilen;//registro que guarda o tamanho do endereço do cliente
char buffer[256];//buffer para guardar caracteres lidos do socket
char respostas[10][100];
int aux=0;
int contacertos = 0;
int conterros = 0;

strcpy (respostas[0], "4") ;
strcpy (respostas[1], "6");
strcpy (respostas[2], "16");
strcpy (respostas[3], "49");
strcpy (respostas[4], "64");
strcpy (respostas[5], "81");
strcpy (respostas[6], "0");
strcpy (respostas[7], "1");
strcpy (respostas[8], "100");
strcpy (respostas[9], "16");





/*--------------------------------------------
sockaddr: struct que guarda endereço internet
struct sockaddr_in
{
short sin_family; --> deve ser AF_INET
u_short sin_port;
struct in_addr sin_addr;
char sin_zero[8]; --> não é usado
};
----------------------------------------------*/

struct sockaddr_in serv_addr, cli_addr;

/*--------------------------------------------
serv_addr:endereço do servidor
cli_addr:endereço do cliente conectado com o servidor
----------------------------------------------*/

int n;
if(argc<2) //se número da porta recebido for menor do que 2
{
//exibe mensagem de erro
fprintf(stderr,"Numero da porta nao fornecido ou incorreto\n");
exit(1);//termina o processo
} //fim do if


/*--------------------------------------------
chamada de sistema --> socket(a,b,c)
- a:AF_UNIX(emdereço domínio unix)
ou AF_INET(endereço domínio internet)
- b:SOCK_STREAM(stream de dados)
ou SOCK_DGRAM(pacotes de dados)
- c:0(permite ao sistema opercaional definir
o melhor protocolo entre IP, TCP e UDP)
----------------------------------------------*/

/*abre o socket e joga em sockfd o número da
linha da tabela descritora de arquivos */

sockfd=socket(AF_INET,SOCK_STREAM,0);

if(sockfd<0) error("Erro de abertura do socket");
//se linha menor que 0 exibir mensagem de erro

/*--------------------------------------------
bzero(a,b): buffer 0 - função que inicializa buffer com zeros
- a:ponteiro para o buffer
- b:tamanho do buffer
----------------------------------------------*/

//inicializa buffer serv_addr com zeros
bzero((char *) &serv_addr, sizeof(serv_addr));


//atoi(argv[1]):converte a string armazenada
//no vetor argv[] em um numero inteiro
portno=atoi(argv[1]);
//portno recebe o número da porta que o servidor vai ouvir

serv_addr.sin_family=AF_INET;
//recebe endereço domínio internet (obrigatório)


//unsigned long s_addr: recebe o IP do host
//INADDR_ANY: possui o endereço IP da máquina corrente
serv_addr.sin_addr.s_addr=INADDR_ANY;//recebe o endereço IP do host onde está o servidor

//htons: host to network - converte o numero da porta
//do computador para o numero usado na rede - conversão em byte ordem
serv_addr.sin_port=htons(portno);//recebe o número da porta usado na rede (net byte order)

/*--------------------------------------------
bind(a,b,c)
- a:numero da linha do descritor de arquivos
- b:endereço internet do servidor
- c:tamanho do endereço internet do servidor
----------------------------------------------*/

if(bind(sockfd, (struct sockaddr *) &serv_addr,sizeof(serv_addr))<0)
//se o bind não conseguiu amarrar o endereço ao socket
error("Erro no bind - o endereço não foi atado ao socket");//mensagem na tela com o erro

/*--------------------------------------------
listen(a,b)
- a:numero da linha do descritor de arquivos
- b:numero máximo de conexões que podem ficar
esperando para serem ouvidas
----------------------------------------------*/

listen(sockfd,5); //o servidor ouve pelo socket
clilen=sizeof(cli_addr);//clilen recebe o tamanho do endereço do cliente

/*--------------------------------------------
accept(a,b,c): bloqueia o serviço até conexão com um cliente
- a:socket file description
- b:endereço do cliente conectado
- c:tamanho do endereço do cliente
----------------------------------------------*/

newsockfd=accept(sockfd,(struct sockaddr *) &cli_addr, &clilen);
if(newsockfd<0)
//se novo endereço do socket menor do que 0, mensagem de erro
error("Erro ao aceitar conexao");
bzero(buffer,256); //inicializando buffer com zeros

do
{
/*--------------------------------------------
read(a,b,c)
- a:novo endereço socket
- b:buffer
- c:número máximo de caracteres lidos
- n:recebe a quantidade de caracteres lidos
----------------------------------------------*/

n = read(newsockfd,buffer,255);
if (n<0)
//se nada foi lido do socket, mensagem de erro
error("Erro de leitura do socket");

printf("Resposta: %s\n",buffer);//exibe na tela a mensagem contida no buffer

/*--------------------------------------------
write(a,b,c)
- a:novo endereço socket
- b:mensagem
- c:tamanho da mensagem
- n:recebe o número de caracteres enviados
pelo write ao cliente
----------------------------------------------*/
//Comecei a mexer aqui //
int teste;
//teste = strcmp(buffer[1],"4") ;
//printf("teste: %d\n",o);

if(atoi(buffer)==atoi(respostas[aux])){
contacertos++;
n = write(newsockfd,"correta a questao",200);
}else
{ n = write(newsockfd,"resposta errada",200);
conterros++;
}

if(n<0)
//se nada foi escrito no socket, mensagem de erro
error("Erro de escrita para o socket");

aux++;




}
// Limita para 10 perguntas
while(aux<10);


char auxstring[256];
sprintf(auxstring, "%d",conterros);
write(newsockfd,auxstring,200);

close(newsockfd); //fecha novo endereço
close(sockfd); //fecha endereço do servidor
return 0; //retorna 0 para o sistema operacional
} //fim da função main































****************************************** cliente *****************************************

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> //tem a struct hostent

/*--------------------------------------------
função chamada quando ocorre um erro em uma chamada de sistema
----------------------------------------------*/

void error(const char *msg)
{
perror(msg);
exit(0);
} //fim da função

/*--------------------------------------------
função main que recebe nome do host
servidor e o número da porta
----------------------------------------------*/

int main(int argc, char *argv[])
{
int sockfd, portno, n;
char perguntas[10][100];
int aux=0;


strcpy (perguntas[0],"2 + 2");
strcpy (perguntas[1],"3 + 3");
strcpy (perguntas[2],"8 + 8");
strcpy (perguntas[3],"7 * 7");
strcpy (perguntas[4],"8 * 8");
strcpy (perguntas[5],"9 * 9");
strcpy (perguntas[6],"7 - 7");
strcpy (perguntas[7],"4 / 4");
strcpy (perguntas[8],"10 *10");
strcpy (perguntas[9],"12 + 4");






//vai conter o endereço do servidor que será conectado
struct sockaddr_in serv_addr;

/*--------------------------------------------
struct hostent
{
char *h_name; //nome oficial do host
char **h_aliases; //alias
int h_addrtype; //tipo de endereço
int h_length; //comprimento do endereço
char **h_addr_list; //lista de endereço do name server
#define h_addr h_addr_list[0] //endereço de compatibilidade
};
----------------------------------------------*/

//server:ponteiro para a struct hostent que tem o endereço do host na internet
struct hostent *server;
char buffer[256];
if(argc<3)//se parametros de entrada incorretos, mensagem de erro e sai do cliente
{
fprintf(stderr,"Erro - uso da porta do host número %s\n", argv[0]);exit(0);
}

portno=atoi(argv[2]); //pega o número da porta
sockfd=socket(AF_INET, SOCK_STREAM, 0); //pega o socket file description
if(sockfd<0)
error("Erro na abertura do socket");//se file description<0, mensagem de erro

//server recebeinformações sobre o host pelo gethostbyname(vetor com o nome do host)
server=gethostbyname(argv[1]);
if(server==NULL)
{
fprintf(stderr,"Erro, host não encontrado\n");
exit(0);
} //se host não encontrado, mensagem de erro e sai do processo

bzero((char *) &serv_addr, sizeof(serv_addr)); //inicializa buffer serv_adder com zeros

serv_addr.sin_family = AF_INET; //recebe o endereço domínio internet (obrigatório)

//copia de_addr para sin_addr
bcopy((char *)server->h_addr,(char *)&serv_addr.sin_addr.s_addr,server->h_length);
serv_addr.sin_port=htons(portno); //sin_port=numero da porta já convertido para rede

/*--------------------------------------------
connect(a,b,c)
- a:socket file description
- b:endereço do host que o cliente quer buscar serviço
- c:tamanho deste endereço
----------------------------------------------*/

if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr))<0)
//se não conseguiu conectar com o servidor
error("Erro de conexão"); //mensagem de erro

do
{
printf ("\n %s",perguntas[aux]);
printf("\n Responda a questao: ");


bzero(buffer,256);//zera o buffer
fgets(buffer,255,stdin);//pega pela entrada padrão os caracteres

aux++;


//grava através do socket o conteúdo do buffer, no comprimento da mensagem enviada
n=write(sockfd,buffer,strlen(buffer));

if(n<0)
//se n<0 erro de escrita no socket e mensagem de erro
error("Erro ao escrever no socket");

bzero(buffer,256);//zera o buffer novamente

//le através do socket (bloqueante) e joga o conteúdo no buffer até 255 caracteres
n=read(sockfd,buffer,255);

if(n<0)
//se n<0 erro de leitura no socket e mensagem na tela
error("Erro ao ler do socket");


printf("%s\n",buffer); //exibe conteúdo do buffer na tela
}

while(aux<10);

printf("\n");
bzero(buffer,256);//zera o buffer
read(sockfd,buffer,255);
printf("%s \n valor do buffer\n",buffer);

close(sockfd); //fecha o socket
return 0; //retorna 0 para o sistema operacional
} //fim do main



  


2. Re: Problemas com Sockets em C

Paulo
paulo1205

(usa Ubuntu)

Enviado em 10/04/2014 - 18:16h

eduinfo10 escreveu:

Boa Noite Pessoal,

Preciso fazer uma espécie de QUIZ com sockets.

Consegui fazer boa parte do código.

A idéia é a seguinte:

O cliente responde 10 perguntas (operações matemáticas), logo que ele coloca o valor da conta, este valor vai para o servidor, e lá compara se a resposta corresponde ao resultado, se corresponder, manda uma mensagem de correto para o cliente e conta 1 para depois no fim poder dizer quantas ele acertou, e o mesmo procedimento é feito se o cara errar a conta.

Só não estou conseguindo mandar para o cliente o valor dos contadores, pois os contadores são "int", e o socket só envia tipo "char". Já tentei converter usando a função sprintf, mas não rolou. Alguem me da uma luz ? Vou postar o código do cliente e do servidor logo abaixo. Lembrando que tudo está correto, apenas preciso arrumar o final dos dois códigos, para enviar o resultado dos contadores para o cliente. E não faço a menor ideia como faz ...

Obrigado.


Vamos pegar o cliente primeiro. Você faz uma pergunta e lê uma resposta que tem uns poucos caracteres, e envia somente esses poucos caracteres (ou bytes) para o servidor. Só que o servidor está esperando ler 255 bytes, e não vai se satisfazer com os poucos caracteres da resposta que você leu do teclado e que o cliente enviou.

Como consertar? Um jeito é você definir um tamanho padrão de mensagem, comum ao cliente e ao servidor, e enviar mensagens que tenham sempre esse tamanho padrão, sabendo que vai aproveitar apenas os primeiros bytes e que os demais serão apenas um tipo de “enchimento”. Esse jeito de fazer tem a vantagem de ser fácil de implementar, mas implica em colocar na rede tráfego que não serve para coisa alguma.

Outro jeito mais sofisticado é criar um protocolo de comunicação para a sua aplicação que permita a ela trabalhar com mensagens de tamanho variável. Algo bem rudimentar nesse sentido poderia ser preceder cada mensagem transmitida com um contador dos bytes que seguem. O receptor da mensagem, por sua vez, antes de tentar ler a mensagem diretamente, leria o tamanho primeiro, e depois ficaria esperando por aquela quantidade de caracteres.

/* remetente */
uint32_t msg_len, n_msg_len;
char msg[4096];

/* Preenche msg com dados que podem ser curtos. */

/* Envia uma mensagem de tamanho variável */
msg_len=strlen(msg);
n_msg_len=htonl(msg_len);

/* Envia a quantidade de bytes que vêm depois. */
write(sock, &n_msg_len, sizeof n_msg_len);

/* Agora envia os bytes com os dados propriamente ditos. */
write(sock, msg, msg_len);



/* destinatario */
uint32_t msg_len, n_msg_len, tot_read;
int n_read;
char buffer[4096];

/* Recebe o tamanho da mensagem. */
if(read(sock, &n_msg_len, sizeof n_msg_len)!=sizeof n_msg_len){
/* Erro ao receber o tamanho da mensagem. */
exit(1);
}

msg_len=ntohl(n_msg_len);
if(msg_len>sizeof buffer){
/* Tamanho da mensagem é maior que o buffer. */
exit(1);
}

/*
Recebe a mensagem propriamente dita. Note que ela pode
chegar fragmentada, de modo que pode ser necessário ter um
loop para juntar todos os pedaços.
*/
tot_read=0;
while(
tot_read<msg_len &&
(n_read=read(sock, buffer+tot_read, msg_len-tot_read))>0
){
tot_read+=n_read;
}







Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts