2017-08-03 9 views
1

私はソケットプログラミングを学ぼうとしていて、このウェブサイトに来ました:http://beej.us/guide/bgnet/output/html/multipage/index.html本当に良いです。私は理解することができましたが、テストプログラムを書いた後、私は3時間後に解決できない問題に終わった。非常に限られた時間なので、専門家にここで助けてもらうと思ったソケットgetaddrinfoの理解の助けが必要

#include <stdio.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <unistd.h> 
#include <netdb.h> 
#include <strings.h> 
#include <arpa/inet.h> 

const char kSuccess = 0; 

// Utility function to get socket address 
void* getSocketAddress(const struct sockaddr *sa) 
{ 
    if (sa->sa_family == AF_INET) { 
     return &(((struct sockaddr_in *)sa)->sin_addr); 
    } 

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

// Utility function to get socket address string 
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr) 
{ 
    inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN); 
} 

int createAndConnectSocket(const struct addrinfo *addrList) 
{ 
    int socketFileDesc = -1; // Invalid descriptor 

    const struct addrinfo *addrIt; 

    /* 
    * STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can 
    */ 

    for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next) 
    { 
     /* 
     * STEP 2.2: Crete the socket file descriptor for our IP address 
     */ 

     socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol); 

     if (socketFileDesc == -1) { 
      fprintf(stderr, "Failed to create socket with error: %d\n", errno); 
      perror("socket"); // Get error desc 
      continue;   // Try next address 
     } 

     /* 
     * STEP 2.3: Set socket behaviour by making ip address to be re-used if used already 
     */ 

     int yes=1; 

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

     char ipAdd[INET6_ADDRSTRLEN]; 
     getSocketAddressString(addrIt->ai_addr, ipAdd); 
     ((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490"); 

     printf("IP is %s::%d\n", ipAdd,((struct sockaddr_in *)addrIt->ai_addr)->sin_port); 

     // Connect to the socket 
     int status; 
     status = connect(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen); 
     if (status != kSuccess) { 
      perror("connect"); 
      close(socketFileDesc); 
      socketFileDesc = -1; 
      continue; 
     } 
    } 

    return socketFileDesc; 
} 

int main(int argc, char* argv[]) 
{ 
    // Check we have data from arguments 
    if (argc < 3 || argc > 3) { 
     perror("Invalid command"); 
     printf("Usage: %s hostname portnumber\n", argv[0]); 
     printf("  %s 192.168.1.2 3490\n", argv[0]); 
    } 

    // Setup server address info 
    struct addrinfo *serverInfo; 
    struct addrinfo hints; 

    int status = -1; 

    memset(&hints, 0, sizeof hints); // Make sure it is empty 

    hints.ai_family  = AF_INET;  // IPv4 
    hints.ai_socktype = SOCK_STREAM; // Use socket stream 

    ((struct sockaddr_in *)&hints.ai_addr)->sin_port = atoi(argv[2]); 

    status = getaddrinfo(argv[1], "3490", &hints, &serverInfo); 
    if (status != kSuccess) { 
     fprintf(stderr, "Failed to get address info %s\n", gai_strerror(status)); 
     exit(1); 
    } 

    printf("Connecting to %s::%s...\n", argv[1], argv[2]); 

    // Create and bind socket 
    int sockfd = createAndConnectSocket(serverInfo); 

    freeaddrinfo(serverInfo); // We are done with serverinfo 

    if (sockfd == -1) { 
     exit(1); 
    } 

    // Send and receive data from server 

    long bytesReceived = -1; 
    long bytesSent = 0; 

    const size_t kMaxBufferSize = 50; 
    char buff[kMaxBufferSize]; 

    const char *msg = "Hi! I am client!"; 
    size_t msgLen = strlen(msg); 

    printf("Connected to server\n"); 

    // Loop to send and receive data 
    while (1) { 

     while (bytesSent < msgLen) { 
      bytesSent = send(sockfd, msg, msgLen, 0); 
      printf("Bytes sent %ld\n", bytesSent); 
     } 

     bytesReceived = recv(sockfd, &buff, kMaxBufferSize - 1, 0); 
     if (bytesReceived > 0) 
     { 
      printf("Data received from server: %s\n", buff); 
     } 
     else if (bytesReceived < 0) { 
      perror("Read error"); 
      break; 
     } 
     else if (bytesReceived == 0) { 
      printf("Connection closed by server\n"); 
      break; 
     } 
    } 

    // Close socket 
    close(sockfd); 

    return 0; 
} 

私の問題は、次のとおりです:これは私のクライアントプログラム

/** 
* Program showing how sockets can be used 
*/ 

#include <stdio.h>   // For printf 
#include <strings.h>  // For bzero, memset 
#include <stdlib.h>   // For exit, atoi 
#include <unistd.h>   // For close 

#include <sys/socket.h>  // For socket 
#include <sys/types.h>  // For types 

#include <arpa/inet.h>  // For inet_addr 
#include <netdb.h>   // Import module network database 

#include <errno.h>   // To access the global errno that holds last system call error 
#include <assert.h>   // For asserting 

#define ADDRESSINFO_GET_SUCCESS 0 
const int kSuccess   = 0; 
const char *kMyPort    = "3490"; // Can be either port num or name of the service 
const int kMaxListenConn  = 10;  // How many connections queue will hold 

// Utility function to get socket address, IPv4 or IPv6: 
void* getSocketAddress(const struct sockaddr *sa) 
{ 
    // Cast socketaddr to sockaddr_in to get address and port values from data 

    if (sa->sa_family == PF_INET) { 
     return &(((struct sockaddr_in *)sa)->sin_addr); 
    } 

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

// Utility function to get socket address string 
void getSocketAddressString(const struct sockaddr *sd, char *ipAddr) 
{ 
    inet_ntop(sd->sa_family, getSocketAddress(sd), ipAddr, INET6_ADDRSTRLEN); 
} 

int createAndBindSocket(const struct addrinfo *addrList) 
{ 
    int status = -1;   // Invalid status 
    int socketFileDesc = -1; // Invalid descriptor 

    const struct addrinfo *addrIt; 

    /* 
    * STEP 2.1: Loop through all the addrinfo nodes and bind to the one we can 
    */ 

    for (addrIt = addrList; addrIt != NULL; addrIt = addrIt->ai_next) 
    { 
     char ipAddr[INET6_ADDRSTRLEN]; 
     inet_ntop(addrIt->ai_family, getSocketAddress(addrIt->ai_addr), ipAddr, sizeof ipAddr); 
     printf("IP: %s\n", ipAddr); 

     /* 
     * STEP 2.2: Crete the socket file descriptor for our IP address 
     */ 

     socketFileDesc = socket(addrIt->ai_family, addrIt->ai_socktype, addrIt->ai_protocol); 

     if (socketFileDesc == -1) { 
      fprintf(stderr, "Failed to create socket with error: %d\n", errno); 
      perror("socket"); // Get error desc 
      continue;   // Try next address 
     } 

     /* 
     * STEP 2.3: Set socket behaviour by making ip address to be re-used if used already 
     */ 

     int yes=1; 

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

     printf("Port %d\n",((struct sockaddr_in *)addrIt->ai_addr)->sin_port); 

     /* 
     * STEP 2.4: Bind our socket with ip address and port number to listen 
     */ 

     status = bind(socketFileDesc, addrIt->ai_addr, addrIt->ai_addrlen); 
     if (status != kSuccess) { 
      fprintf(stderr, "Failed to bind socket with error:%d\n", errno); 
      perror("bind"); // Get error desc 

      // Clear socket 
      close(socketFileDesc); 
      socketFileDesc = -1; 

      continue;  // Try next address 
     } 
    } 

    return socketFileDesc; 
} 


int main() 
{ 
    int status = -1; // Status is invalid 

    struct addrinfo hints;   // Holds our hints to get address info 
    struct addrinfo *addrList;  // Contains our address info 

    /* 
    * STEP 1: Setup service details 
    */ 

    // Make sure struct is empty 
    bzero(&hints, sizeof hints); // memset(&hints, 0, sizeof(hints)); 

    hints.ai_family  = AF_UNSPEC; // Don't care IPv4 or v6 
    hints.ai_socktype = SOCK_STREAM; // Use TCP stream sockets 
    hints.ai_flags  = AI_PASSIVE; // Use my local IPs or you igore this and provide IP manually in first arg 


    status = getaddrinfo(NULL, kMyPort, &hints, &addrList); 
    if (status != kSuccess) { 
     fprintf(stderr, "Failed to get address info with error: %s\n", gai_strerror(status)); 
     exit(1); 
    } 

    /* 
    * STEP 2: Create a socket and bind it 
    */ 

    int socketFileDesc; 
    socketFileDesc = createAndBindSocket(addrList); 

    freeaddrinfo(addrList); // Done with list 

    if (socketFileDesc == -1) { 
     exit(1); 
    } 

    /* 
    * STEP 3: Listen to the port for incoming connections 
    */ 

    status = listen(socketFileDesc, kMaxListenConn);  // Second arg is number of incoming connections in queue 
    if (status != kSuccess) { 
     fprintf(stderr, "Failed to listen to the port\n"); 
     perror("listen"); 
     goto exit; 
    } 

    printf("Server is listening at the port %s\n", kMyPort); 

    struct sockaddr_storage inConnAddr;  // Big enough to hold both IPv4 and v6 
    socklen_t inConnAddrLen = sizeof inConnAddr; 

    const size_t kMaxBufferSize = 50; 
    char buff[kMaxBufferSize] = {0}; 

    long bytesReceived = -1; 
    long bytesSent = 0; 
    int clientSockfd; 

    while (1) { 

     /* 
     * STEP 4: Accept incoming connections 
     */ 

     inConnAddrLen = sizeof inConnAddr; 

     clientSockfd = accept(socketFileDesc, (struct sockaddr *)&inConnAddr, &inConnAddrLen); 

     // Got new connection ? 
     if (clientSockfd == -1) { 
      perror("accept"); // Print error description 
      continue;   // Continue to look for new connections 
     } 

     // 
     // Got connection, create child process to handle request 
     // 

     if (!fork()) { 
      close(socketFileDesc); // No need with child 

      char ipAddr[INET6_ADDRSTRLEN]; 
      getSocketAddressString((struct sockaddr *)&inConnAddr, ipAddr); 
      printf("Child process created for hanlding request from %s\n", ipAddr); 

      /* 
      * STEP 5: Receive and Send data to requests 
      */ 

      bytesReceived = recv(clientSockfd, &buff, kMaxBufferSize - 1, 0); 
      if (bytesReceived > 0) 
      { 
       printf("Data from client %s\n", buff); 
       while (bytesSent < bytesReceived) { 
        bytesSent = send(clientSockfd, buff, bytesReceived, 0); 
        printf("Bytes sent %ld\n", bytesSent); 
       } 
      } 

      if (bytesReceived < 0) { 
       perror("recv"); 
      } 
      else if (bytesReceived == 0) { 
       printf("Connection closed by server\n"); 
      } 

      close(clientSockfd); // Close socket 
      exit(0); 
     } 
    } 

exit: 
    /* 
    * STEP 5: Close the socket 
    */ 
    close(socketFileDesc); 


    return 0; 
} 

です:

これは私のサーバープログラムである、私ははgetaddrinfo()の呼び出しでのポートとIPを設定しているにもかかわらずはなく、バインド時や接続時にsockaddr構造体にあるポート番号が違うので間違っています。私はここに何が落ちているのか知っていて、そのために私が接続を拒否したというメッセージが表示されます。 誰でも私のプログラムを見て、なぜ私は接続が拒否されているのか教えてください。誰かが自分のコードの改善を提案できるのであれば、本当に感謝しています。

おかげ

答えて

2

あなたは、あなたがに接続していると思うのポートに接続していません。

((struct sockaddr_in *)addrIt->ai_addr)->sin_port = atoi("3490"); 

sin_portの値は、ネットワークバイトオーダー、つまりビッグエンディアンでなければなりません。代わりに、値3490(atoiを介して)を直接割り当てるので、値はホストバイトオーダーになります。ご使用のプラットフォームは、リトルエンディアンのバイト順序を使用する可能性が最も高いです。

ポート3490(0DA2 16進数)に接続する代わりに、ポート41485(A2 0D 16進数)に接続しています。

関数は、ホストバイトオーダーからネットワークバイトオーダーまでの16ビット値(sin_portは16ビットフィールドなので)を変換します。また、ここでatoiを使用する必要はありません。代わりに数値定数を使用してください。

((struct sockaddr_in *)addrIt->ai_addr)->sin_port = htons(3490); 
+0

ご回答ありがとうございます。私はこれを忘れてしまいましたが、私はそれを修正しましたが、まだ問題があります。今、私は接続の呼び出しで操作がタイムアウトになっています。あなたは何か考えていますか?また、自分のコードを見て、コードの改善をお勧めしますか?ありがとうPS:構造体を取得するためにgetaddrinfo()を使用する代わりに、手動でsockaddr、ファミリおよび他の値を入力すると、接続して正常に動作しますが、getaddrinfo()を使用して構造体を取得して使用すると機能しません。 –

+0

@DineshG同じマシン上のサーバーとクライアントでうまく動作します。ファイアウォール設定を確認してください。 – dbush

関連する問題