TCP-сокет не работает: сервер: ENOTCONN 107; клиент: ECONNREFUSED 111 - PullRequest
0 голосов
/ 18 февраля 2020

Сегодня я написал свою первую программу для сокетов. Я основал его на некоторых примерах из справочных страниц и в Интернете.

server.c:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>

#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#define ALX_NO_PREFIX
#include <libalx/base/compiler/size.h>
#include <libalx/base/errno/error.h>


#define SERVER_PORT "30002"
#define SERVER_IP   "127.0.0.1"


int tcp_server_open (const char *server_port)
{
    struct protoent *tcp;
    int         sd;
    struct addrinfo hint = {0};
    struct addrinfo *addrs;
    int         status;

    tcp = getprotobyname("tcp");
    if (!tcp)
        return  -EINVAL;
    hint.ai_family      = AF_UNSPEC;
    hint.ai_socktype    = SOCK_STREAM;
    hint.ai_protocol    = tcp->p_proto;
    hint.ai_flags       = AI_PASSIVE;
    status  = getaddrinfo(NULL, server_port, &hint, &addrs);
    if (status) {
        perrorx("getaddrinfo() failed");
        return  -labs(status);
    }

    for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) {
        sd  = socket(addr->ai_family, addr->ai_socktype,
                            addr->ai_protocol);
        if (sd < 0) {
            perrorx("socket() failed");
            continue;
        }
        if (!bind(sd, addr->ai_addr, addr->ai_addrlen)) {
            perrorx("binded!");
            break;
        }

        close(sd);
        sd  = -1;
        perrorx("bind() failed");
    }
    freeaddrinfo(addrs);
    perrorx("break");

    if (sd < 0)
        return  -errno;

    perrorx("open!");

    return  sd;
}


int main    (void)
{
    int             sd;
    char                buf[BUFSIZ];
    struct sockaddr_storage cli_addr = {0};
    socklen_t           cli_addr_len;
    ssize_t         n;
    int             s;
    int             status;
    char                host[NI_MAXHOST];
    char                service[NI_MAXSERV];

    status  = EXIT_FAILURE;
    sd  = tcp_server_open(SERVER_PORT);
    if (sd < 0) {
        perrorx("tcp_server_open(ROBOT_PORT);");
        goto out;
    }

    while (true) {
        cli_addr_len    = sizeof(cli_addr);

        n   = recvfrom(sd, buf,  ARRAY_SIZE(buf), 0,
                (struct sockaddr *)&cli_addr, &cli_addr_len);

        if (n < 0) {
            //if (errno != 107)
                perrorx("no msg");
            continue;
        }

        s   = getnameinfo((struct sockaddr *)&cli_addr, cli_addr_len,
                        host, NI_MAXHOST, service,
                        NI_MAXSERV, NI_NUMERICSERV);
        if (!s) {
            printf("Received %zd bytes from %s:%s\n", n, host, service);
        } else {
            perrorx("getnameinfo() failed");
            fprintf(stderr, "getnameinfo(): %s\n", gai_strerror(s));
        }

        printf("%*s\n", (int)ARRAY_SSIZE(buf), buf);

        if (sendto(sd, buf, n, 0, (struct sockaddr *)&cli_addr, cli_addr_len) != n)
            perrorx("sendto() failed");

        printf("%s\n", buf);

        printf("Enter msg:\n");
        fgets(buf, ARRAY_SIZE(buf), stdin);
        n   = write(sd, buf, strlen(buf));
        if (n < 0) {
            perrorx("write() failed");
            goto out;
        }

    }

    status  = EXIT_SUCCESS;
out:
    perrorx("out");
    return  close(sd) || status;
}

client.h:

#include <stdio.h>
#include <stdlib.h>

#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>

#define ALX_NO_PREFIX
#include <libalx/base/compiler/size.h>
#include <libalx/base/errno/error.h>


#define SERVER_PORT "30002"
#define SERVER_IP   "127.0.0.1"


int tcp_client_open (const char *server_ip, const char *server_port)
{
    struct protoent *tcp;
    int         sd;
    //struct addrinfo   hint = {0};
    struct addrinfo *addrs;
    int         status;

    tcp = getprotobyname("tcp");
    if (!tcp) {
        perrorx("getprotobyname() failed");
        return  -EINVAL;
    }
    //hint.ai_family        = AF_INET;
    //hint.ai_socktype  = SOCK_STREAM;
    //hint.ai_protocol  = tcp->p_proto;
    status  = getaddrinfo(server_ip, server_port, /*&hint*/NULL, &addrs);
    if (status) {
        perrorx("getaddrinfo() failed");
        return  -labs(status);
    }

    for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) {
        sd  = socket(addr->ai_family, addr->ai_socktype,
                            addr->ai_protocol);
        if (sd < 0) {
            perrorx("socket() failed");
            break;
        }
        if (!connect(sd, addr->ai_addr, addr->ai_addrlen)) {
            perrorx("connected!");
            break;
        }

        close(sd);
        sd  = -1;
        perrorx("connect() failed");
    }
    freeaddrinfo(addrs);
    perrorx("break");

    if (sd < 0)
        return  -errno;

    perrorx("open!");

    return  sd;
}


int main    (void)
{
    int     sd;
    char        buf[BUFSIZ];
    ssize_t n;
    int     status;

    status  = EXIT_FAILURE;
    sd  = tcp_client_open(SERVER_IP, SERVER_PORT);
    if (sd < 0) {
        perrorx("tcp_client_open() failed");
        goto out;
    }

    printf("Enter msg:\n");
    fgets(buf, ARRAY_SIZE(buf), stdin);
    n   = write(sd, buf, strlen(buf));
    if (n < 0) {
        perrorx("write() failed");
        goto out;
    }

    memset(buf, 0, ARRAY_SIZE(buf));
    n   = read(sd, buf, ARRAY_SIZE(buf));
    if (n < 0) {
        perrorx("read() failed");
        goto out;
    }
    printf("%*s\n", (int)ARRAY_SSIZE(buf), buf);

    status  = EXIT_SUCCESS;
out:
    perrorx("out");
    return  close(sd) || status;
}

void perrorx(const char *msg); обертка вокруг perror, но также печатает имя файла, строки и функции.

Сервер выводит следующее:

./server:
    server.c:50:
    tcp_server_open():
        binded!
    E0 -    Success
./server:
    server.c:59:
    tcp_server_open():
        break
    E0 -    Success
./server:
    server.c:64:
    tcp_server_open():
        open!
    E0 -    Success

, а затем зацикливается в следующем сообщении (если я раскомментирую тест if (errno != 107), он ничего не печатает) (попытка подключиться к серверу не влияет на это):

./server:
    server.c:97:
    main():
        no msg
    E107 -  Transport endpoint is not connected

И я должен убить его с помощью ^ C (конечно, после выхода из клиента ).

Клиент выводит следующее:

./client:
    client.c:56:
    tcp_client_open():
        connect() failed
    E111 -  Connection refused
./client:
    client.c:50:
    tcp_client_open():
        connected!
    E111 -  Connection refused
./client:
    client.c:59:
    tcp_client_open():
        break
    E111 -  Connection refused
./client:
    client.c:64:
    tcp_client_open():
        open!
    E111 -  Connection refused
Enter msg:
asd
./client:
    client.c:95:
    main():
        read() failed
    E111 -  Connection refused
./client:
    client.c:102:
    main():
        out
    E111 -  Connection refused

В чем проблема? Я почти ничего не знаю о сокетах.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...