2012-02-27 4 views
5

Sto cercando un modo per ottenere il mio server per stampare il suo numero di porta TCP e l'indirizzo IP, ma come ho ora sto producendo l'IP sbagliato, io sono ottenendo un output di 0.0.33.32. Qualsiasi aiuto è apprezzato!Hai bisogno di aiuto per ottenere il numero di porta TCP e l'indirizzo IP in 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

Mostra la definizione di 'get_in_addr()'. Questo è quasi certamente un problema di ordine di byte di rete. – trojanfoe

+0

Puoi descrivere il problema con maggiori dettagli? Quale messaggio è sbagliato ("ha il numero di porta TCP ..."?), Cosa stampa esattamente, cosa ti aspettavi di vedere esattamente? 0.0.33.32 potrebbe uscire se si tenta di guardare il testo ("!") Come indirizzo IP. – ugoren

+0

Sono abbastanza sicuro che la porta # sia corretta ma l'IP sta sbagliando – Ryan

risposta

5

Il problema è nella tua inet_ntop chiamata:

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

Qui si utilizza il puntatore p dopo aver chiamato

freeaddrinfo(servinfo); 

È necessario copiare lo struct sockaddr e socklen_t che hai ricevuto dal getaddrinfo in alcune variabili o memorizzare la struttura addrinfo per ulteriore utilizzo. Altrimenti causerai un comportamento indefinito, come ora stai vivendo. Ricorda, Valgrind è tuo amico.

+0

Grazie, ho dimenticato di aver fatto un puntatore! A proposito, cos'è Valgrind? – Ryan

+1

@Ryan Valgrind è un analizzatore di memoria (può fare molte altre cose). Fondamentalmente ti dirà quando stai cercando di leggere o scrivere in posizioni di memoria non valide, ad es. memoria non assegnata o liberata. Trova di più su di esso qui: (link) [http://valgrind.org/] – kpaleniu

6

Quello che potrebbe essere necessario utilizzare è la funzione 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

L'applicazione tenta di essere consapevole di IPv6. Quindi 'struct sockaddr_in' sarà troppo corto per quello ... Al contrario,' struct sockaddr_storage' è pensato per essere abbastanza grande per tutti gli scopi. – glglgl

+1

@glglgl Buon punto, risposta aggiornata di conseguenza. –

2

Ebbene, le altre risposte (getsockname) è probabilmente già quello che ti serve.

Vorrei solo mettere in evidenza una delle migliori fonti disponibili per la programmazione di rete comprensione:

Beej's guide to network programming

  • è ragionevolmente breve, si lavora attraverso di essa entro 1 ora
  • lavori per entrambi, windows e linux (e unix, ecc ...)
  • spiega i concetti alla base dei dettagli necessari (nessun problema dove non necessario)