GUJ Discuss√Ķes ¬† : ¬† √ļltimos t√≥picos ¬† | ¬† categorias ¬† | ¬† GUJ Respostas

Duvida Server/Client


#1

Oi,como se faz em c++ uma distancia em um server e cliente por exemplo: manhattan distance

Alguem me pode ajudar


#2

Voc√™ quer saber a dist√Ęncia f√≠sica entre os computadores de cliente e servidor? N√£o existe nenhuma maneira confi√°vel de se fazer isso.

O mais pr√≥ximo que voc√™ pode fazer √© tentar estimar a localiza√ß√£o do cliente pelo IP e calcular a dist√Ęncia do servidor at√© essa localiza√ß√£o. Ainda assim, n√£o vai estar correta, porque a localiza√ß√£o geralmente √© do ISP e n√£o do cliente em si. Fora isso, se tiver qualquer tipo de desvio na rede (e.g. uma VPN) entre o cliente e o servidor, essa conta deixa de ser √ļtil.

Outra coisa que d√° pra fazer √© calcular o tempo de comunica√ß√£o entre cliente e servidor. Isso pode dar uma no√ß√£o da dist√Ęncia que os pacotes tem que percorrer para ir do cliente ao servidor e vice-versa (e essa dist√Ęncia n√£o tem nenhuma correla√ß√£o com a dist√Ęncia f√≠sica entre os dois computadores, que podem estar um ao lado do outro conectados por um cabo de 20km). Tem protocolos de rede para calcular isso, mas eu n√£o domino o assunto.


#3

O que eu estava a dizer era que o client e o server tem de se comunicar e depois com os dados que o servidor mandar para o client é entao calculada a manhattan distance
Tou utilizar este server e o client:

// Server 
#include <unistd.h>
#include <stdio.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#include <string.h>
#define PORT 65432
int main(int argc, char const *argv[])
{
    int server_fd, new_socket, valread;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);
    char buffer[1024] = {0};
    char *hello = "Hello from server";

    // Creating socket file descriptor
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }

    // Forcefully attaching socket to the port 65432
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,&opt, sizeof(opt)))
    {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }
    address.sin_family = AF_INET;
    address.sin_addr.s_addr = INADDR_ANY;
    address.sin_port = htons( PORT );

    // Forcefully attaching socket to the port 65432
    if (bind(server_fd, (struct sockaddr *)&address,sizeof(address))<0)
    {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }
    if (listen(server_fd, 3) < 0)
    {
        perror("listen");
        exit(EXIT_FAILURE);
    }//9
    if ((new_socket = accept(server_fd, (struct sockaddr *)&address,(socklen_t*)&addrlen))<0)
    {
        perror("accept");
        exit(EXIT_FAILURE);
    }
    while(1){
        valread = read( new_socket , buffer, 1024);
        printf("%s\n",buffer );// é isto que recebe

    }
    send(new_socket , hello , strlen(hello) , 0 );
    printf("Hello message sent\n");
    return 0;   }

// Client 
#include <stdio.h> 
#include <sys/socket.h> 
#include <stdlib.h> 
#include <netinet/in.h> 
#include <string.h> 
#define PORT 8080 
   
int main(int argc, char const *argv[]) 
{ 
    struct sockaddr_in address; 
    int sock = 0, valread; 
    struct sockaddr_in serv_addr; 
    char *hello = "Hello from client"; 
    char buffer[1024] = {0}; 
    if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) 
    { 
        printf("\n Socket creation error \n"); 
        return -1; 
    } 
   
    memset(&serv_addr, '0', sizeof(serv_addr)); 
   
    serv_addr.sin_family = AF_INET; 
    serv_addr.sin_port = htons(PORT); 
       
    // Convert IPv4 and IPv6 addresses from text to binary form 
    if(inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr)<=0)  
    { 
        printf("\nInvalid address/ Address not supported \n"); 
        return -1; 
    } 
   
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 
    { 
        printf("\nConnection Failed \n"); 
        return -1; 
    } 
    send(sock , hello , strlen(hello) , 0 ); 
    printf("Hello message sent\n"); 
    valread = read( sock , buffer, 1024); 
    printf("%s\n",buffer ); 
    return 0; 
}

#4

Primeiro você precisa entender de verdade como esse código que você colou aqui funciona. Você entende que quando o cliente escreve no socket, o dado fica disponível para o servidor ler? O contrário também, quando o servidor escreve algo no socket, aquele dado vai aparecer na stream de leitura no lado do cliente.

Depois de entender isso, você precisa criar uma espécie de protocolo de comunicação para definir como o cliente vai mandar os dados, e como vai ser a resposta do servidor. O TCP garante que todos os dados que você envia vão chegar em ordem e com consistência, mas isso não é suficiente, porque você precisa de alguma forma interpretar as mensagens dos dois lados. Você pode criar algo assim:

Para enviar uma mensagem ao servidor para que ele calcule uma dist√Ęncia, o cliente deve enviar a seguinte string:

"[x1,y1][x2,y2]"

Do lado do servidor, como você sabe que as mensagens tem esse formato, você sabe vai saber como extrair os dois pontos da mensagem.

A resposta do servidor pode ser do mesmo jeito, a dist√Ęncia envolvida em colchetes:

"[distancia]"

#5

Exatamente, aqui quando voc√™ fala em ‚Äú‚Ķcriar uma esp√©cie de protocolo de comunica√ß√£o para definir como o cliente vai mandar os dados, e como vai ser a resposta do servidor‚ÄĚ,ai est√° o meu problema como e que vou implementar no meu c√≥digo para conseguir interpretar os dados,
entao no servidor eu tenho de enviar ‚Äú[x1,y1][x2,y2]‚ÄĚ como disse
mas em que parte do codigo e que eu implemento?

int distancia(std::string x, std::string y) {
    if (x == y) {
        return 0;
    } else {
        return 1;
    }
}

#6

Que tal depois de chamar a função read? Você vai ler uma determinada quantidade de bytes fixa ou vai ler char por char, procurando pelos delimitadores da mensagem [ e ]. Acho que a primeira forma é mais fácil.

Você pode definir que a mensagem do cliente para o servidor é assim:

[tamanho(um n√ļmero com X d√≠gitos][p1][p2]

No servidor voc√™ pode fazer: read(sockid, buffer, X + 2) (o + 2 por causa dos colchetes). Esse tamanho X te diz quantos bytes ler pra frente depois desse cabe√ßalho. Assim voc√™ pode chamar read de novo esperando o tamanho certo de bytes. √Č como o header Content-Length do HTML.


#7

Estou de bom humor e fiz o servidor para você. Agora falta você fazer o cliente. Leia o código para entender o que está acontecendo.

O protocolo funciona assim:

  • Os 3 primeiros caracteres da mensagem do cliente indicam o tamanho total da mensagem (sem incluir esses 3 primeiros). Por exemplo, se a mensagem tem 30 caracteres, os 3 primeiros caracteres ser√£o 030, seguidos de 30 caracteres que indicam os inputs da fun√ß√£o.

  • Os inputs da fun√ß√£o s√£o n√ļmeros reais separados pelo caractere |. Se voc√™ deseja passar os pontos (0,0) e (1,1) como entrada, por exemplo, a mensagem fica: 0070|0|1|1. Se o input s√£o os pontos (0.003, 0.005) e (10, 50.32), a mensagem fica 0200.003|0.005|10|50.32. Lembre que os 3 primeiros indicam o tamanho da mensagem com os n√ļmeros.

  • Em outras palavras: [cabe√ßalho]x1|y1|x2|y2 (sem os colchetes).

Testando com o netcat:

$ nc localhost 8000
0070|0|1|1
2.000000

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <netinet/in.h>
#include <sys/socket.h>

typedef struct {
  int descriptor;
  struct sockaddr_in address;
} sSocket;


typedef struct {
  double x;
  double y;
} sPoint;


typedef struct {
  sPoint p1;
  sPoint p2;
} sInput;

sSocket create_server (short int port) {
  int server_fd;
  struct sockaddr_in server_address;

  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
    perror("Could not open the socket.\n");
    exit(EXIT_FAILURE);
  }

  server_address.sin_family = AF_INET; 
  server_address.sin_addr.s_addr = INADDR_ANY; 
  server_address.sin_port = htons(port);
  
  if (bind(server_fd, (struct sockaddr*) &server_address, sizeof(server_address)) == -1) {
    fprintf(stderr, "Could not bind the socket to port %d.\n", port);
    exit(EXIT_FAILURE);
  }

  sSocket s;
  s.descriptor = server_fd;
  s.address = server_address;
  
  return s;
}


void start_server (sSocket server) {
  if (listen(server.descriptor, 5) == -1) {
    fprintf(stderr, "Could not put the socket bound to %d in listen mode\n.", ntohs(server.address.sin_port));
    exit(EXIT_FAILURE);
  }
}


void close_socket (sSocket server) {
  if (close(server.descriptor) == -1) {
    fprintf(stderr, "An error occurred while trying to close the socket bound to %d.\n", ntohs(server.address.sin_port));
    exit(EXIT_FAILURE);
  }
}


sSocket accept_client (sSocket server) {
  int client_fd;
  struct sockaddr_in client_address;
  socklen_t address_length = sizeof(client_address);
  if ((client_fd = accept(server.descriptor, (struct sockaddr*) &client_address, &address_length)) == -1) {
    fprintf(stderr, "An error occurred while trying to accept a connection on port %d.\n.", ntohs(server.address.sin_port));
    exit(EXIT_FAILURE);
  }
  sSocket client;
  client.descriptor = client_fd;
  client.address = client_address;
  return client;
}


sInput read_input (sSocket client) {
  size_t buffer_size = 999;
  char* buffer = calloc(sizeof(char), buffer_size);
  size_t header_size = 3;
  read(client.descriptor, (void *) buffer, header_size);
  size_t  message_size = atoi(buffer);
  read(client.descriptor, (void *) buffer, message_size);

  sInput input;
  sscanf(buffer, "%lf|%lf|%lf|%lf", &input.p1.x, &input.p1.y, &input.p2.x, &input.p2.y);
  free(buffer);
  return input;
}


void write_output (sSocket client, double result) {
  char* buffer = (char*) malloc(256 * sizeof(char));
  sprintf(buffer, "%lf", result);
  send(client.descriptor, (void *) buffer, strlen(buffer), 0);
  free(buffer);
}


double manhattan_distance (sPoint p1, sPoint p2) {
  return fabs(p1.x - p2.x) + fabs(p1.y - p2.y);
}


void handle_client (sSocket client) {
  sInput input = read_input(client);
  double result = manhattan_distance(input.p1, input.p2);
  write_output(client, result);
  close_socket(client);
}


int main (int argc, char** argv) {
  int port = 8000;
  sSocket server = create_server(port);
  start_server(server);

  while (1) {
    sSocket client = accept_client(server);
    handle_client(client);
  }

  return 0;
}

#8

Muito Obrigada, agora do lado do cliente o que eu preciso de fazer é com que o cliente envie os pontos para depois calcula


#9

Exatamente. Pra isso você precisa entender como fazer em C:

  1. Ponteiros;
  2. Manipulação de strings e buffers;
  3. Como ler e escrever de/em file descriptors (arquivos, sockets, dispositivos, etc.).

Sem saber isso não tem como fazer. Pesquise e domine tópico por tópico, e aí você vai saber exatamente como implementar o cliente.


#10

Neste caso posso tambem acrescenta a dist√Ęncia de hamming