2012-02-27 181 views
5

我試圖找到一種方法來讓我的服務器打印它的TCP端口號和IP地址,但我現在是如何產生錯誤的IP,我是得到0.0.33.32的輸出。任何幫助表示讚賞!需要幫助獲取TCP端口號和IP地址在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

顯示'get_in_addr()'的定義。這幾乎肯定是網絡字節順序問題。 – trojanfoe 2012-02-27 07:38:37

+0

你能更詳細地描述問題嗎?哪條消息是錯誤的(「有TCP端口號......」),它究竟打印了什麼,你期望看到什麼?如果您嘗試將文本(「!」)視爲IP地址,則可能會出現0.0.33.32。 – ugoren 2012-02-27 08:13:17

+0

我很確定端口#是正確的,但IP出現錯誤 – Ryan 2012-02-27 08:27:11

回答

5

的問題是在你的inet_ntop電話:

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

在這裏使用的是指針p調用

freeaddrinfo(servinfo); 

後,您需要複製結構sockaddrsocklen_tgetaddrinfo了在一些變量中,或者存儲struct addrinfo以供進一步使用。否則,你會導致未定義的行爲,就像你現在正在經歷的那樣。請記住,Valgrind是你的朋友。

+0

謝謝,我忘了我已經做了一個指針!順便說一句,Valgrind是什麼? – Ryan 2012-02-28 00:23:13

+1

@Ryan Valgrind是一個內存分析器(它可以做很多其他的事情)。基本上它會告訴你什麼時候你試圖讀取或寫入無效的內存位置,即。未分配或釋放內存。在這裏查找更多信息:(link)[http://valgrind.org/] – kpaleniu 2012-02-28 08:48:00

6

什麼,你可能需要使用的是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

該應用程序試圖識別IPv6。所以'struct sockaddr_in'對於那個來說太短了......相比之下,'struct sockaddr_storage'意圖足夠大以滿足所有目的。 – glglgl 2012-02-27 08:32:24

+1

@glglgl好點,相應地更新了答案。 – 2012-02-27 08:46:38

2

好了,其他的答案(getsockname)可能已經在你所需要的。

我只是想強調的要理解網絡編程可用的最佳來源之一:

Beej's guide to network programming

  • 它的合理的短,你通過它1小時
  • 作品中工作這兩個,Windows和Linux(和Unix等...)
  • 解釋在必要的細節背後的概念(沒有大驚小怪,如果沒有必要)
相關問題