2012-02-27 40 views
5

Tôi đang cố gắng tìm cách để máy chủ của tôi in Số cổng TCP và địa chỉ IP của nó nhưng cách tôi có ngay bây giờ là tạo IP sai, tôi nhận được kết quả là 0,0.33,32. Bất kỳ trợ giúp được đánh giá cao!Cần trợ giúp để nhận số cổng TCP và địa chỉ IP trong 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

Hiển thị định nghĩa 'get_in_addr()'. Điều này gần như chắc chắn là một vấn đề mạng-byte-trật tự. – trojanfoe

+0

Bạn có thể mô tả sự cố chi tiết hơn không? Thông báo nào sai ("có số cổng TCP ..."?), Chính xác nó in ra gì, chính xác bạn mong đợi điều gì? 0,0.33.32 có thể xuất hiện nếu bạn cố xem văn bản ("!") Làm địa chỉ IP. – ugoren

+0

Tôi khá chắc chắn rằng cổng # là chính xác nhưng IP sắp ra sai – Ryan

Trả lời

5

Vấn đề là ở inet_ntop cuộc gọi của bạn:

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

Tại đây bạn đang sử dụng con trỏ p sau khi gọi

freeaddrinfo(servinfo); 

Bạn cần phải sao chép struct sockaddrsocklen_t bạn nhận được từ getaddrinfo trong một số biến, hoặc lưu trữ cấu trúc addrinfo để sử dụng thêm. Nếu không, bạn sẽ gây ra hành vi không xác định, giống như bạn hiện đang gặp phải. Hãy nhớ rằng, Valgrind là bạn của bạn.

+0

Cảm ơn bạn, tôi quên rằng tôi đã làm p một con trỏ! BTW Valgrind là gì? – Ryan

+1

@Ryan Valgrind là một bộ phân tích bộ nhớ (nó có thể làm được rất nhiều thứ khác). Về cơ bản nó sẽ cho bạn biết khi bạn đang cố gắng đọc từ hoặc ghi vào các vị trí bộ nhớ không hợp lệ, ví dụ. không được cấp phát hoặc giải phóng bộ nhớ. Tìm thêm thông tin tại đây: (link) [http://valgrind.org/] – kpaleniu

6

Những gì bạn có thể cần phải sử dụng là getsockname chức năng:

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

Ứng dụng cố gắng nhận biết IPv6. Vì vậy, 'struct sockaddr_in' sẽ quá ngắn cho điều đó ... Ngược lại,' struct sockaddr_storage' được dự định là đủ lớn cho tất cả các mục đích. – glglgl

+1

@glglgl Điểm tốt, câu trả lời được cập nhật tương ứng. –

2

Vâng, câu trả lời khác (getsockname) có lẽ đã gì bạn cần.

Tôi chỉ muốn nhấn mạnh một trong những nguồn tốt nhất cung cấp cho lập trình hiểu biết mạng:

Beej's guide to network programming

  • nó một cách hợp lý ngắn, bạn làm việc thông qua nó trong vòng 1 giờ
  • công trình cho cả hai, cửa sổ và linux (và unix vv ...)
  • giải thích các khái niệm đằng sau chi tiết cần thiết (không phiền phức nếu không cần thiết)
Các vấn đề liên quan