Duvida Server/Client

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

Alguem me pode ajudar

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.

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]"

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;
    }
}

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.

2 curtidas

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;
}
3 curtidas

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

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.

Neste caso posso tambem acrescenta a distância de hamming