2012-02-27 26 views
5

Estoy tratando de encontrar la manera de hacer que mi servidor imprima su número de puerto TCP y dirección IP pero la forma en que lo tengo ahora produce una dirección IP incorrecta, estoy obteniendo una salida de 0.0.33.32. ¡Cualquier ayuda es apreciada!Necesito ayuda para obtener el número de puerto TCP y la dirección IP en C

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <errno.h> 
#include <string.h> 
#include <sys/types.h> 
#include <sys/socket.h> 
#include <netinet/in.h> 
#include <netdb.h> 
#include <arpa/inet.h> 
#include <sys/wait.h> 
#include <signal.h> 
#include <time.h> 

#define PORT "21467" // the port users will be connecting to 

#define BACKLOG 10 // how many pending connections queue will hold 

void sigchld_handler(int s) 
{ 
while(waitpid(-1, NULL, WNOHANG) > 0); 
} 

// get sockaddr, IPv4 or IPv6: 
void *get_in_addr(struct sockaddr *sa) 
{ 
if (sa->sa_family == AF_INET) { 
    return &(((struct sockaddr_in*)sa)->sin_addr); 
} 

return &(((struct sockaddr_in6*)sa)->sin6_addr); 
} 

int main(void) 
{ 
int sockfd, new_fd; // listen on sock_fd, new connection on new_fd 
struct addrinfo hints, *servinfo, *p; 
struct sockaddr_storage their_addr; // connector's address information 
socklen_t sin_size; 
struct sigaction sa; 
int yes=1; 
char s[INET6_ADDRSTRLEN]; 
int rv; 

memset(&hints, 0, sizeof hints); 
hints.ai_family = AF_UNSPEC; 
hints.ai_socktype = SOCK_STREAM; 
hints.ai_flags = AI_PASSIVE; // use my IP 

char hname[100]; 
gethostname(hname, sizeof hname); 

if ((rv = getaddrinfo(hname, PORT, &hints, &servinfo)) != 0) { 
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv)); 
    return 1; 
} 
// loop through all the results and bind to the first we can 
for(p = servinfo; p != NULL; p = p->ai_next) { 
    if ((sockfd = socket(p->ai_family, p->ai_socktype, 
      p->ai_protocol)) == -1) { 
     perror("server: socket"); 
     continue; 
    } 

    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, 
      sizeof(int)) == -1) { 
     perror("setsockopt"); 
     exit(1); 
    } 

    if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) { 
     close(sockfd); 
     perror("server: bind"); 
     continue; 
    } 

    break; 
} 

if (p == NULL) { 
    fprintf(stderr, "server: failed to bind\n"); 
    return 2; 
} 




freeaddrinfo(servinfo); // all done with this structure 

if (listen(sockfd, BACKLOG) == -1) { 
    perror("listen"); 
    exit(1); 
} 

sa.sa_handler = sigchld_handler; // reap all dead processes 
sigemptyset(&sa.sa_mask); 
sa.sa_flags = SA_RESTART; 
if (sigaction(SIGCHLD, &sa, NULL) == -1) { 
    perror("sigaction"); 
    exit(1); 
} 


char host[100]; 
char service[20]; 

getnameinfo(p->ai_addr, p->ai_addrlen, host, sizeof host, service, sizeof service, 0); 
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), 
     host, sizeof host); 

printf("server: has TCP port number %s and IP address %s\n", service, host); 

printf("server: waiting for connections...\n"); 

int numbytes; 
char buf[100]; 

while(1) { // main accept() loop 
    sin_size = sizeof their_addr; 
    new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size); 
    if (new_fd == -1) { 
     perror("accept"); 
     continue; 
    } 

    inet_ntop(their_addr.ss_family, 
     get_in_addr((struct sockaddr *)&their_addr), 
     s, sizeof s); 

    //getnameinfo(get_in_addr((struct sockaddr *)&their_addr), sizeof get_in_addr((struct sockaddr *)&their_addr), NULL, NULL, service, sizeof service, 0); 

    if ((numbytes = recv(new_fd, buf, 100, 0)) == -1) 
     perror("recv"); 

    /* if ((numbytes = recv(sockfd, buf, 100, 0)) == -1) { 
    perror("recv"); 
    exit(1); 
}*/ 

    struct tm* local; 
    char toClient[50]; 
    printf("server: received '%s'\n",buf); 
    time_t curTime = time(0); 
    local = localtime(&curTime); 
    if(buf[0] == 't' ){ 
     printf("server: received time request\n", s); 
     sprintf(toClient, "Time: %d::%d::%d", local->tm_hour, local->tm_min, local->tm_sec); //Seg faulting 
     printf("Sent the time to the client having IP address %s and port number %s\n", s, service); 
    } 
    else if(buf[0] == 'd'){ 
     printf("server: received date request\n", s); 
     sprintf(toClient, "Date: %d::%d::%d", 1900+local->tm_year, 1+local->tm_mon, local->tm_mday); 
     printf("Sent the date to the client having IP address %s and port number %s\n", s, service); 
    } 
    else{ 

    } 

    if ((numbytes = send(new_fd, toClient, sizeof toClient, 0)) == -1) { 
    perror("send"); 
    exit(1); 
} 
    close(new_fd); 
    break; //Temporary 
} 


close(sockfd); 
return 0; 
} 
+0

Mostrar la definición de 'get_in_addr()'. Esto es casi seguro un problema de orden de bytes de red. – trojanfoe

+0

¿Puedes describir el problema con más detalle? ¿Qué mensaje es incorrecto ("tiene número de puerto TCP ..."?), ¿Qué exactamente imprime, qué esperaba ver exactamente? 0.0.33.32 podría aparecer si intenta ver el texto ("!") Como una dirección IP. – ugoren

+0

Estoy bastante seguro de que el puerto # es correcto pero la IP está saliendo mal – Ryan

Respuesta

5

El problema está en su inet_ntop llamada:

inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr), 
      host, sizeof host); 

Aquí está utilizando puntero p después de llamar

freeaddrinfo(servinfo); 

Debe copiar la estructura sockaddr y socklen_t que obtuvo de getaddrinfo en algunas variables, o almacene la estructura addrinfo para un uso posterior. De lo contrario, provocarás un comportamiento indefinido, como el que estás experimentando ahora. Recuerda, Valgrind es tu amigo.

+0

¡Gracias, olvidé que había hecho p un puntero! Por cierto, ¿qué es Valgrind? – Ryan

+1

@Ryan Valgrind es un analizador de memoria (puede hacer muchas otras cosas). Básicamente, le indicará cuándo intenta leer o escribir en ubicaciones de memoria no válidas, es decir. memoria no asignada o liberada. Encuentre más sobre esto aquí: (enlace) [http://valgrind.org/] – kpaleniu

6

Lo que puede que tenga que utilizar es la función getsockname:

struct sockaddr_storage my_addr; 
socklen_t my_addr_len = sizeof(my_addr); 
if (getsockname(sockfd, (struct sockaddr *) &my_addr, &my_addr_len) != -1) 
{ 
#ifndef NI_MAXHOST 
# define NI_MAXHOST 1025 
#endif 
#ifndef NI_MAXSERV 
# define NI_MAXSERV 32 
#endif 

    char host[NI_MAXHOST]; 
    char serv[NI_MAXSERV]; 

    if (getnameinfo((const struct sockaddr *) &my_addr, my_addr.ss_len, 
        host, sizeof(host), 
        serv, sizeof(serv), 0) == 0) 
    { 
     printf("Host address: %s, host service: %s\n", host, serv); 
    } 
} 
+1

La aplicación intenta ser consciente de IPv6. Entonces 'struct sockaddr_in' será demasiado corto para eso ... Por el contrario,' struct sockaddr_storage' debe ser lo suficientemente grande para todos los propósitos. – glglgl

+1

@glglgl Buen punto, respuesta actualizada en consecuencia. –

2

Bueno, las otras respuestas (getsockname) es probable que ya lo que necesita.

yo sólo quisiera resaltar una de las mejores fuentes disponibles para la programación de redes comprensión:

Beej's guide to network programming

  • está razonablemente corto, que funciona a través de él dentro de 1 hora
  • obras para ambos, windows y linux (y unix etc ...)
  • explican los conceptos detrás de los detalles necesarios (sin problemas donde no es necesario)
Cuestiones relacionadas