9

イーサネット ポートからデータを収集したいデータ収集モジュールがあります。私はステップでそこに着いていますconnect。現在、クライアントからサーバーに送りたいだけです。基本的な C コードを取得するために Beej のガイドを使用しました。しかし、この接続エラーが発生し続けますconnect: Connection refused.

これが私がすることです:

  1. ここに記載されているネットワーク IP は、私が構成したSTATIC IPです。

  2. ポート番号はサーバー側で 50000 に設定され、クライアント側からはポート 50000 でこの IP に接続します。

  3. サーバー側アプリケーションをビルドして実行し、クライアント側アプリケーションを実行して接続を試みます。

returnsクライアント側アプリケーションを起動する前に、サーバー側、サーバー側アプリケーションについて 1 つ疑問がwhile(1);あります。クライアント側から接続できるように、アプリケーションを実行したまま ( ) にする必要がありますか?

ここで何かを忘れていますか?ヘルプ!

ここに、サーバー側とクライアント側の Beej の C コードをわずかに変更して (IP とポート番号が異なります) 貼り付けます。

サーバー.c

/*
** server.c
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>



int main(int argc, char *argv[])
{
    // code for a server waiting for connections
    // namely a stream socket on port 3490, on this host's IP
    // either IPv4 or IPv6.
    int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE; // use my IP address

    if ((rv = getaddrinfo(NULL, "50000", &hints, &servinfo)) != 0)
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        exit(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("socket");
            continue;
        }
        if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1)
        {
            close(sockfd);
            perror("bind");
            continue;
        }
        break; // if we get here, we must have connected successfully
    }

    if (p == NULL) 
    {
        // looped off the end of the list with no successful bind
        fprintf(stderr, "failed to bind socket\n");
        exit(2);
    }

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

}

Client.c

/*
** client.c
*/
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int main(int argc, char *argv[])
{
    // code for a client connecting to a server
    // namely a stream socket to www.example.com on port 80 (http)
    // either IPv4 or IPv6
    int sockfd;
    struct addrinfo hints, *servinfo, *p;
    int rv;
    memset(&hints, 0, sizeof hints);
    hints.ai_family = AF_UNSPEC; // use AF_INET6 to force IPv6
    hints.ai_socktype = SOCK_STREAM;
    if ((rv = getaddrinfo("192.168.2.4", "50000", &hints, &servinfo)) != 0) 
    {
        fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
        exit(1);
    }
    // loop through all the results and connect 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("socket");

        continue;
        }
        if (connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) 
        {
            close(sockfd);
            perror("connect");
            continue;
        }
        break; // if we get here, we must have connected successfully
    }

    if (p == NULL)
    {
        // looped off the end of the list with no connection
        fprintf(stderr, "failed to connect\n");
        exit(2);
    }

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

}
4

4 に答える 4

7

サーバーコードが欠落listen()しておりaccept()、listen() を呼び出してから接続を「待機」し、accept()新しい接続を受け入れるコードを実行します。あなたが使用している例は、それを行う方法を示していませんか? 通常、新しい接続ごとに新しいスレッドもフォークします。

詳細については、 http://www.linuxhowtos.org/C_C++/socket.htmを参照してください。

より完全な実装へのリンクは次のとおりです。 http://www.thegeekstuff.com/2011/12/c-socket-programming/

于 2012-07-16T03:24:25.453 に答える
5

はい、サーバー プログラムを実行し続ける必要があります。サーバー プログラムで、 address を使用してソケットを作成socket()し、アドレスにバインドしたbind()ので、着信接続のリッスンを開始する必要があります。これはlisten()呼び出しで行われます。ソケットが着信接続をリッスンしたら、accept()呼び出しを使用して実際に接続を受け入れ、その特定のクライアントとの通信用のソケットを取得する必要があります。

簡単な例として、 の後にfreeaddrinfo次のコードを追加できます。

listen(sockfd, 8); /* allow up to 8 pending connections, i.e. created but not accepted */
while (1) {
  int clientfd;
  struct sockaddr_in client_addr;
  socklen_t client_addr_len = sizeof(struct sockaddr_in);
  clientfd = accept(sockfd, &client_addr, &client_addr_len);
  /* communicate with client by send()/recv() or write()/read() on clientfd */
  close(clientfd);
}

このコードには、一度に 1 つのクライアントしか処理されないという欠点があります。複数の同時クライアントを処理するには、いくつかの方法があります。 を使用した複数のプロセスfork()、複数のスレッド、またはポーリングです。私の意見では、これらのアプローチはそれぞれ、この質問の範囲外です。

于 2012-07-16T03:32:42.550 に答える
1

Server.c ファイルを見てください: listen() をまったく呼び出していません!
対象のサーバーが指定されたポートでリッスンしない場合、クライアントから SYN パケットを受信すると RST パケットが返されるため、connect() は「接続が拒否されました」を返します。

サーバー側の関数の通常の流れは、 socket -> bind -> listen -> accept です:

getaddrinfo();
socket();
bind();
listen();
/* accept() goes here */ 

https://beej.us/guide/bgnet/html/multi/syscalls.html#listenを参照してください

于 2012-07-16T03:25:49.227 に答える
0

/etc/hosts ファイルにリモート ホストのエントリがないため、「接続が拒否されました」というエラーが発生しました。エントリーは両側に存在する必要があります。クライアント マシンの /etc/hosts には、以下のパターンでサーバー マシンのエントリが存在する必要があります。

<ip address> <hostname with domain> <alias hostname>

これにより、 getaddrinfo() 関数にあったエラーが解決されました。

于 2013-05-22T09:26:51.890 に答える