Jump to content

Criar um socket para enviar mensagens entre 2 PCs


PsySc0rpi0n

Recommended Posts

Boas.

Estou a tentar criar o software do lado do servidor para ouvir e enviar dados para outro PC. Estou a seguir um código que encontrei na net mas estou a obter um erro quando compilo que não sou capaz de corrigir porque não sei como o fazer.

O código é este:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>

#define BUFFER 256

typedef struct sockaddr_in sockin;


int main(int argc, char const **argv) {
   int sockfd, newsockfd, portno, clilen;
   char buffer[BUFFER];
   sockin serv_addr, cli_addr;
   int n;

   if(argc < 2){
      fprintf(stderr, "ERROR, no port provided\n");
      exit(-1);
   }

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
      perror("ERROR opening socket!");
      exit(-1);
   }
   memset((char *)&serv_addr, 0, sizeof(serv_addr));
   portno = atoi(argv[1]);

   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(portno);

   if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
      perror("Error binding");
      exit(-1);
   }

   listen(sockfd, 5);
   clilen = sizeof(cli_addr);

   if((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, (socklen_t *)&clilen)) < 0){ //<-- alterado aqui
      perror("ERROR accepting connection");
      exit(-1);
   }

   memset(buffer, 0, sizeof(buffer));
   n = read(newsockfd, buffer, 255);
   if(n < 0){
      perror("ERROR reading from socket");
      exit(-3);
   }

   printf("Here is the message: %s\n", buffer);
   return 0;
}

 

O erro que obtenho a compilar é o seguinte:

Quote

src/server.c: In function ‘main’:
src/server.c:44:65: warning: pointer targets in passing argument 3 of ‘accept’ differ in signedness [-Wpointer-sign]
    if((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, &clilen)) < 0){
                                                                 ^
In file included from /usr/include/netinet/in.h:23:0,
                 from /usr/include/netdb.h:27,
                 from src/server.c:5:
/usr/include/x86_64-linux-gnu/sys/socket.h:243:12: note: expected ‘socklen_t * restrict’ but argument is of type ‘int *’
 extern int accept (int __fd, __SOCKADDR_ARG __addr,
            ^
gcc -Wall -Wextra -pedantic -std=c99 -g -lm -lSDL2 -o bin/server obj/server.o

 

O código que estou a seguir está aqui.

Edited by PsySc0rpi0n
Adicionada correcção no código

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Just now, HappyHippyHippo said:

altera o tipo de dados de clilen para socklen_t

Já lá tinha chegado mas não vim aqui actualizar a thread! Aliás, eu fiz o cast mas nem sei se o podia fazer até porque me acabaram de dizer que o código que eu estou a seguir não é grande exemplo, mas também não sei o que será um bom exemplo!

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

@HappyHippyHippo, fiz umas alterações no código e tenho um novo erro que também não sei resolver nem sei bem o que significa: undefined reference.

Declarei e defini uma função nova no início do código e usei-a/chamei-a no final da função main e dá-me aquele erro juntamente com um ld returned -1.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>

#define BUFFER 256

typedef struct sockaddr_in sockin;


void doprocessing(int sock){
   int n;
   char buffer[BUFFER];

   memset(buffer, 0, szeof(char) * BUFFER);

   if((n = read(sock, buffer, BUFFER - 1)) < 0){
      perror("ERROR reading from socket");
      exit(-1);
   }
   printf("Here is the message: %s\n", buffer);

   n = write(sock, "I got your message". 18);
   if(n < 0){
         perror("ERROR writing to socket");
         exit(-1);
   }
}

int main(int argc, char const **argv) {
   int sockfd, newsockfd, portno, clilen;
   char buffer[BUFFER];
   sockin serv_addr, cli_addr;
   int n, pid;

   if(argc < 2){
      fprintf(stderr, "ERROR, no port provided\n");
      exit(-1);
   }

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
      perror("ERROR opening socket!");
      exit(-1);
   }
   memset((char *)&serv_addr, 0, sizeof(serv_addr));
   portno = atoi(argv[1]);

   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(portno);

   if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
      perror("Error binding");
      exit(-1);
   }

   listen(sockfd, 5);
   clilen = sizeof(cli_addr);

   while(1){
      if((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, (socklen_t *)&clilen)) < 0){
         perror("ERROR accepting connection");
         exit(-1);
      }

      if(( pid = fork() ) < 0){
         perror("Error creating child process");
         exit (-1);
      }

      if(pid == 0){
         close(sockfd);
         doprocessing(newsockfd);
         exit(0);
      }else{
         close(newsockfd);
      }
   }
   return 0;
}
Quote

make
gcc -Wall -Wextra -pedantic -std=c99 -g -lm -lSDL2 -o bin/server_m obj/server_m.o
obj/server_m.o: In function `main':
/home/narayan/3º Ano - Electrónica e Telecomunicações/Cadeiras_3A_2S/Redes_Locais_e_Industriais/Sockets/Multicom/src/server_m.c:57: undefined reference to `doprocessing'
collect2: error: ld returned 1 exit status
Makefile:12: recipe for target 'all' failed
make: *** [all] Error 1

Edited by PsySc0rpi0n
Correcção no código

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Boa noite,

Assim de ler o código sem testar:

memset(buffer, 0, szeof(char) * BUFFER);

o szeof não deveria ser sizeof ?

memset(buffer, 0, sizeof(char) * BUFFER);

Cordiais cumprimentos,

Apocsantos

"A paciência é uma das coisas que se aprendeu na era do 48k" O respeito é como a escrita de código, uma vez perdido, dificilmente se retoma o habito"

Link to comment
Share on other sites

12 hours ago, apocsantos said:

Boa noite,

Assim de ler o código sem testar:


memset(buffer, 0, szeof(char) * BUFFER);

o szeof não deveria ser sizeof ?


memset(buffer, 0, sizeof(char) * BUFFER);

Cordiais cumprimentos,

Apocsantos

Claro que sim. E o erro será disso? É que o output nem sequer refere nada relacionado com o sizeof.

Edited;

Pois, parece mesmo que era disso!

Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Bom dia,

Bem, eu li o erro e comecei a ler o código, a modos que a "interpretar" na "caixa dos pirolitos", e reparei no erro de digitação!

Citação

undefined reference

Cordiais cumprimentos,

Apocsantos

"A paciência é uma das coisas que se aprendeu na era do 48k" O respeito é como a escrita de código, uma vez perdido, dificilmente se retoma o habito"

Link to comment
Share on other sites

Bom, é verdade!

Neste momento tenho dois source files, server.c e client.c . Copiei o server.c para um servidor dedicado que eu tenho, compilei e "corri" com a seguinte sintaxe:

Citação

./server 50000

Fiz o mesmo com o file client.c no meu laptop. Corri com a seguinte sintaxe:

Citação

./client <ip.ip.ip.ip> 50000

mas recebo o seguinte erro:

Citação

ERROR connecting: Socket operation on non-socket

Esta mensagem não vem do código que eu escrevi, por isso não consigo perceber bem em que altura acontece. Já pesquisei na net e na maioria das vezes, o problema é na criação do socket, falham na colocação dos parêntesis, mas penso não ser o meu caso. Mas também não consigo perceber bem onde está o problema! Eu ainda não percebi bem que valores andam em que variáveis, pois ainda me faz alguma confusão alguns termos que usam nesta área em inglês, por isso não consigo ainda fazer um debug mais preciso!

Source code:

client.c

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>

#define h_addr h_addr_list[0] /* for backward compatibility */
#define BUFFER 256

typedef struct sockaddr_in sockin;
typedef struct hostent hostent;

int main(int argc, char **argv){
   int sockfd = 0, portno = 0, n = 0;
   sockin serv_addr;
   hostent *server;
   char buffer[BUFFER];

   if(argc < 3){
      fprintf(stderr, "Usage is: %s <hostname> <port>\n", argv[0]);
      exit(-1);
   }

   if((server = gethostbyname(argv[1])) == NULL){
      fprintf(stderr, "No such host\n");
      exit(-1);
   }

   portno = atoi(argv[2]);
   if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){//<-- adicionado
      perror("ERROR connecting");											 //<-- adicionado
      exit(-1);																 //<-- adicionado
   }
  
   memset(&serv_addr, 0, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);
   serv_addr.sin_port = htons(portno);

   printf("Enter message to send:\n");
   memset(buffer, 0, sizeof(char) * BUFFER);
   fgets(buffer, BUFFER, stdin);

   if((n = write(sockfd, buffer, strlen(buffer))) < 0){
      perror("ERROR writing to socket");
      exit(-1);
   }

   memset(buffer, 0, sizeof(char) * BUFFER);
   if((n = read(sockfd, buffer, strlen(buffer))) < 0){
      perror("ERROR writing to socket");
      exit(-1);
   }
   printf("Received message: %s\n", buffer);

   return 0;
}

 

Edited;

Ok, já descorbi. Faltou-me criar o socket no client.c.

Já alterei o ficheiro e está a funcionar tudo penso eu!

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>

#define BUFFER 256

typedef struct sockaddr_in sockin;


int main(int argc, char const **argv) {
   int sockfd, newsockfd, portno, clilen;
   char buffer[BUFFER];
   sockin serv_addr, cli_addr;
   int n;

   if(argc < 2){
      fprintf(stderr, "ERROR, no port provided\n");
      exit(-1);
   }

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
      perror("ERROR opening socket!");
      exit(-1);
   }
   memset((char *)&serv_addr, 0, sizeof(serv_addr));
   portno = atoi(argv[1]);

   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(portno);

   if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
      perror("Error binding");
      exit(-1);
   }

   listen(sockfd, 5);
   clilen = sizeof(cli_addr);

   if((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, (socklen_t *)&clilen)) < 0){
      perror("ERROR accepting connection");
      exit(-1);
   }

   memset(buffer, 0, sizeof(buffer));
   n = read(newsockfd, buffer, 255);
   if(n < 0){
      perror("ERROR reading from socket");
      exit(-3);
   }

   printf("Here is the message: %s\n", buffer);
   return 0;
}

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Já percebi porque é que não estava a dar.

Mas neste momento queria analisar o código um pouco mais à lupa e tentar perceber o que se passa porque sinceramente o código não foi feito por mim e gostava de perceber o que se está a passar!

Tenho uma linha no código que quero perceber os casts que estão a ser feitos!

memmove((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length); 

Esta variável [tt]serv_addr[/tt] é uma estrutura com a seguinte composição:

struct sockaddr_in { 
    short            sin_family;   // e.g. AF_INET
    unsigned short   sin_port;     // e.g. htons(3490)
    struct in_addr   sin_addr;     // see struct in_addr, below
    char             sin_zero[8];  // zero this if you want to
};

e a variável sin_addr, pelo que percebo é uma variável manhosa e não é definida da mesma forma consoante o SO usado! Mas pelo menos uma das definições é:

struct in_addr { 
    unsigned long s_addr;  // load with inet_aton()
};

ou em Windows:

typedef struct in_addr { 
  union {
    struct {
      u_char s_b1,s_b2,s_b3,s_b4;
    } S_un_b;
    struct {
      u_short s_w1,s_w2;
    } S_un_w;
    u_long S_addr;
  } S_un;
} IN_ADDR, *PIN_ADDR, FAR *LPIN_ADDR;

Bom, mas o que me interessa é mesmo perceber os casts que são feitos na linha de código lá em cima!

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

2 minutes ago, HappyHippyHippo said:

existe algo nessa linha de código que não perece bem, mas como a pergunta não é essa,--

os cast estão mal feitos, isto porque a função espera como argumentos do tipo void *, e como tal nem faz sentido estarem lá ...

Pois, já reparei. Entretanto estou a falar com o pwseo no IRC e já vimos que o memmove() não se interessa pelo tipo das variáveis. No entanto fui eu que alterei esta linha de código. A linha de código original era:

bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length);

Mas na documentação desta função vi uma nota que dizia ser preferível usar a memmove() e o que fiz foi apenas colocar os argumentos nos locais certos na função memmove().

Mas queria perceber os casts na linha de código original!

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Just now, HappyHippyHippo said:

como disse, em C não interessa porque ele come qualquer referência quando o parâmetro é um void *

Pois, então não percebo porque é que no código original estão lá os casts! Aparentemente não eram necessários porque os argumentos da função bcopy() são const void*...

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Bom, ainda ande de volta do código, mas para perceber porque é que o cliente não recebe resposta do servidor! O código está assim:

client.c

#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>

#define h_addr h_addr_list[0] /* for backward compatibility */
#define BUFFER 1024

#define CLEAR_INPUT while(getchar() != '\n') /*void*/

void clear_n(char *str){
   if(str[strlen(str) - 1] == '\n')
      str[strlen(str) - 1] = '\0';
}

typedef struct sockaddr_in sockin;
typedef struct hostent hostent;

int main(int argc, char **argv){
   int sockfd = 0, portno = 0;
   sockin serv_addr;
   hostent *server;
   char buffer[BUFFER];

   /*  Read arguments from command line */
   if(argc < 3){
      fprintf(stderr, "Usage is: %s <hostname> <port>\n", argv[0]);
      exit(-1);
   }

   portno = atoi(argv[2]);

   /* Create the socket file descriptor */
   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
      perror("ERROR opening socket");
      exit(-1);
   }

   if((server = gethostbyname(argv[1])) == NULL){
      fprintf(stderr, "No such host\n");
      exit(-1);
   }

   /* Configure the socket parameters */
   memset(&serv_addr, 0, sizeof(serv_addr));
   serv_addr.sin_family = AF_INET;
   memmove(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
   serv_addr.sin_port = htons(portno);

   /* Connect to the server */
   if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
      perror("ERROR connecting");
      exit(-1);
   }


   /* Ask for message to send to the server */
   printf("Enter message to send:\n");
   memset(buffer, 0, sizeof(char) * BUFFER);
   fgets(buffer, BUFFER, stdin);
   clear_n(buffer);

   /* Write the message to the socket and verify if it was sent*/
   if(write(sockfd, buffer, strlen(buffer)) < 0){
      perror("ERROR writing to socket");
      exit(-1);
   }

   /* Read the server response */
   memset(buffer, 0, sizeof(char) * BUFFER);
   if(read(sockfd, buffer, strlen(buffer)) < 0){
      perror("ERROR reading from socket");
      exit(-1);
   }
   printf("Received message: %s\n", buffer);

   return 0;
}

Do lado do servidor está assim:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <netinet/in.h>
#include <unistd.h>

#define BUFFER 1024

typedef struct sockaddr_in sockin;

void clear_n(char *str){
   if(str[strlen(str) - 1] == '\n')
      str[strlen(str) - 1] = '\0';
}

void doprocessing(int sock){
   char buffer[BUFFER];

   memset(buffer, 0, sizeof(buffer));
   if(read(sock, buffer, BUFFER - 1) < 0){
      perror("ERROR reading from socket");
      exit(-1);
   }
   printf("Here is the message: %s\n", buffer);

   memset(buffer, 0, sizeof(buffer));
   printf("Enter message to send:\n");
   fgets(buffer, BUFFER, stdin);
   clear_n(buffer);
   if((write(sock, buffer, sizeof(buffer))) < 0){
         perror("ERROR writing to socket");
         exit(-1);
   }
}

int main(int argc, char const **argv) {
   int sockfd, newsockfd, portno, clilen;
   sockin serv_addr, cli_addr;
   int pid;

   if(argc < 2){
      fprintf(stderr, "ERROR, no port provided\n");
      exit(-1);
   }

   if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
      perror("ERROR opening socket!");
      exit(-1);
   }
   memset(&serv_addr, 0, sizeof(serv_addr));
   portno = atoi(argv[1]);

   serv_addr.sin_family = AF_INET;
   serv_addr.sin_addr.s_addr = INADDR_ANY;
   serv_addr.sin_port = htons(portno);

   if(bind(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0){
      perror("Error binding");
      exit(-1);
   }

   listen(sockfd, 5);
   clilen = sizeof(cli_addr);

   while(1){
      if((newsockfd = accept(sockfd, (struct sockaddr *)&cli_addr, (socklen_t *)&clilen)) < 0){
         perror("ERROR accepting connection");
         exit(-1);
      }

      if(( pid = fork() ) < 0){
         perror("Error creating child process");
         exit (-1);
      }

      if(pid == 0){
         close(sockfd);
         doprocessing(newsockfd);
         exit(0);
      }
   }
   return 0;
}

Na função doprocessing() é que supostamente a resposta devia ser enviada do servidor para o cliente, mas o cliente está apenas a receber uma string vazia e ainda não percebi porquê!

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

  • 2 weeks later...

Bom, esquecendo o que lá vai para trás porque já resolvi o problema, tenho agora que resolver outro problema.

Vão-me dar na cabeça por causa do problema, mas em vez de andar aqui a experimentar todas as opções possíveis sem perceber o que estou a fazer, mais vale pedir uma explicação!

O problema, tenho quase a certeza ser com os ponteiros.

 

A situação é a seguinte:

typedef struct sockaddr_in sockin;
int sockfd;

sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(*sockfd < 0)
	error("ERROR opening socket");

memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(portno);

if(bind(sockfd, (struct sockaddr *) serv_addr, sizeof(serv_addr)) < 0)
	error("ERROR on binding");

Este código está na função main e como este código é para repetir várias vezes num novo programa, coloquei-o dentro de uma função e como tal, tive que passar alguns parâmetros por referência para dentro dessa função e estou com algumas dificuldades em perceber como aceder, nomeadamente ao conteúdo de alguns campos da struct serv_addr.

 

A função ficou assim:

void create_socket(sockin *serv_addr, int portno, int *sockfd){
   *sockfd = socket(AF_INET, SOCK_STREAM, 0);
   if(*sockfd < 0)
     error("ERROR opening socket");

   memset(&serv_addr, 0, sizeof(serv_addr));
   *serv_addr.sin_family = AF_INET;
   *serv_addr.sin_addr.s_addr = INADDR_ANY;
   *serv_addr.sin_port = htons(portno);

   if(bind(*sockfd, (struct sockaddr *) serv_addr, sizeof(serv_addr)) < 0)
      error("ERROR on binding");
}

Sei que o problema está na estrutura serv_addr porque o debugger diz que esta variável está a apontar para NULL.

Como não quero andar simplesmente a epxerimentar como funcionar, sem perceber, queria que me explicassem como aceder à variável serv_addr que está na função main e que foi passada por referência para a função aqui mostrada assim:

 

create_socket(&serv_addr, portno, &sockfd1);

Eu até já experimentei na função acima fazer:

serv_addr->sin_family = AF_INET;
serv_addr->sin_addr.s_addr = INADDR_ANY;
serv_addr->sin_port = htons(portno);

mas continua a não dar e queria perceber!

O gdb diz que o serv_addr = 0x0...

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

6 minutes ago, HappyHippyHippo said:

diz la exactamente onde o compilador se queixa ...

diz a verdade qual a linha real da queixa ...

não será : memset(&serv_addr, 0, sizeof(serv_addr));

serv_addr já é um endereço de memória, para quê o & adicional ?

Não é o compilador, é o debugger, gdb.

Starting program: /home/PsySc0rpi0n/programming/c/server_m 50000
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".

Program received signal SIGSEGV, Segmentation fault.
0x0000000000400a6d in create_socket (serv_addr=0x0, portno=50000, sockfd=0x7fffffffe53c)
    at server_m.c:28
28         serv_addr->sin_family = AF_INET;
(gdb) quit
A debugging session is active.

        Inferior 1 [process 25537] will be killed.

Quit anyway? (y or n) y

O code original acho que setava assim, mas deixa cá experimentar e já digo alguma coisa!

 

Edited;

Se retirar o '&' do memset, queixa-se:

server_m.c: In function ‘create_socket’:
server_m.c:27:31: warning: argument to ‘sizeof’ in ‘memset’ call is the same expression as the destination; did you mean to dereference it? [-Wsizeof-pointer-memaccess]
    memset(serv_addr, 0, sizeof(serv_addr));
                               ^
Edited by PsySc0rpi0n

Kurt Cobain - Grunge misses you

Nissan GT-R - beast killer

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.