web-dev-qa-db-fra.com

C, Sockets: erreur de refus de connexion

J'ai un module d'acquisition de données à partir duquel j'aimerais collecter des données à partir du port Ethernet. J'y arrive par étapes , actuellement, j'aimerais simplement connect au serveur à partir d'un client. J'ai utilisé le guide de Beej pour obtenir le code C de base. Mais je continue juste à avoir cette erreur de connexion connect: Connection refused.

C'est ce que je fais:

  1. L'IP réseau mentionné ici est IP STATIQUE que j'ai configuré.

  2. Le numéro de port est défini sur 50000 côté serveur et côté client, je me connecte à cette adresse IP sur le port 50000.

  3. Je construis et exécute l'application côté serveur, puis j'essaie de me connecter à celle-ci en exécutant une application côté client.

Un doute sur l'application côté serveur, côté serveur returns avant de démarrer l'application côté client, dois-je donc la laisser fonctionner (while(1);) afin de pouvoir me connecter à partir du côté client?

Qu'est-ce qui ne va pas, est-ce que j'oublie quelque chose ici? Aidez-moi!

Je colle le code très légèrement modifié (les adresses IP et les numéros de ports sont différents). Code C de Beej pour Côté serveur et côté client ici:

Server.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

}
8
HaggarTheHorrible

Les codes listen() et accept() sont manquants dans votre code serveur pour "attendre" une connexion en appelant listen () puis en exécutant une accept() pour accepter les nouvelles connexions. L'exemple que vous utilisez ne montre-t-il pas comment faire cela? En règle générale, vous créerez également un nouveau thread pour chaque nouvelle connexion.

Voir http://www.linuxhowtos.org/C_C++/socket.htm pour plus d'informations.

Voici un lien vers une implémentation plus complète: http://www.thegeekstuff.com/2011/12/c-socket-programming/

6
HeatfanJohn

Oui, vous devez maintenir le programme du serveur en cours d'exécution. Dans votre programme serveur, vous avez créé le socket à l'aide de socket() et lié à une adresse bind(). Vous devez maintenant commencer à écouter les connexions entrantes. Ceci est fait avec l'appel listen(). Une fois que le socket écoute les connexions entrantes, vous devez utiliser l'appel accept() pour accepter une connexion et obtenir le socket pour la communication avec ce client particulier.

Comme exemple rapide, après la freeaddrinfo, vous pouvez ajouter le code suivant:

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);
}

Ce code présente le défaut selon lequel un seul client à la fois est traité. Il existe plusieurs façons de gérer plusieurs clients simultanés: plusieurs processus utilisant fork(), plusieurs threads ou une interrogation. Chacune de ces approches, à mon avis, sort du cadre de cette question.

3
Geoff Reedy

Veuillez regarder votre fichier Server.c: il n'appelle pas du tout listen ()! 
Si le serveur ciblé n'écoute pas sur le port spécifié, il renverra un paquet RST à la réception du paquet SYN du client, ainsi connect () retournera avec "Connexion refusée".

Le flux normal des fonctions côté serveur est socket -> bind -> listen -> accept: 

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

Veuillez vous référer à https://beej.us/guide/bgnet/html/multi/syscalls.html#listen

1
Xu Hong

J'obtenais l'erreur "connexion refusée" car je n'avais pas l'entrée de l'hôte distant dans le fichier/etc/hosts. L'entrée devrait être présente des deux côtés. Dans les machines clientes/etc/hosts, il devrait y avoir une entrée de la machine serveur et inversement dans le motif ci-dessous.

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

Cela a résolu l'erreur que j'étais dans la fonction getaddrinfo ().

0
Adithya Gokhale