Как исправить ошибку «Отказано в соединении» при обмене данными по протоколу TCP между двумя устройствами - PullRequest
0 голосов
/ 01 мая 2019

Так что в настоящее время я пытаюсь общаться по TCP от черного запущенного Debian на Mac. Я хочу общаться с beaglebone на Mac и отправлять текстовые сообщения между ними. Мой код настроен так, что у меня есть основное соединение, где я передаю видео через порт 1000, используя соединение UDP, и это само по себе работает нормально, но я настроил базовое соединение TCP для отправки текста через порт 10001 в отдельном pthread, и при соединении между двумя устройствами это дает мне вывод

ERROR connecting -1 Connection refused 111

Где, если я распечатаю значения, это говорит

Port: 10001, name: 192.168.1.37

Что особенно интересно для меня, так это то, что я знаю, что IP-адрес правильный, потому что я могу транслировать видео, используя IP-адрес и порт 10000.

Общая настройка: у меня есть микроконтроллер beaglebone (в основном, Raspberry Pi), подключенный к маршрутизатору, и мой Mac подключен через Ethernet к тому же маршрутизатору. Я использую библиотеку "sys / socket.h"

Код TCPClient (сторона macbook)

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

class TCPClient {

private:
    int sockfd;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char buffer[512];

    void createSocket() {

        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        if (sockfd < 0) {
            printf("ERROR opening socket\n");
            exit(0);
        }
    }

    void createConnection() {

        memcpy((char *)server->h_addr_list[0],
               (char *)&serv_addr.sin_addr.s_addr,
               server->h_length);

        int er = connect(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr));
        if (er < 0) {
            printf("ERROR connecting %i %s\n", er, strerror(errno));
            exit(0);
        }
    }

public:
    TCPClient(int port, char* name) {

        memset((char *) &serv_addr, 0, sizeof(serv_addr));

        printf("Port: %i, name: %s\n", port, name);

        serv_addr.sin_port = htons(port);

        server = gethostbyname(name);
        if (server == NULL) {
            fprintf(stderr,"ERROR, no such host\n");
            exit(0);
        }

        serv_addr.sin_family = AF_INET;

        createSocket();

        createConnection();

    }

    ~TCPClient() {
        close(sockfd);
    }

    void transmitData(char data[]) {

        int n = write(sockfd, data, strlen(data));
        if (n < 0) {
            printf("ERROR writing to socket\n");
            exit(0);
        }
    }

    char* receiveData() {
        memset(buffer, 0, sizeof(buffer));

        int n = read(sockfd, buffer, sizeof(buffer));
        if (n < 0) {
            printf("ERROR reading from socket\n");
            exit(0);
        }

        return buffer;
    }

};

Код TCPServer (микроконтроллер)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

class TCPServer {

private:
    // struct for data
    int sockfd, newsockfd;
    socklen_t clilen;
    char buffer[512];
    struct sockaddr_in serv_addr, cli_addr;

public:
    TCPServer(int port) {

        // clear address structure
        memset((char *) &serv_addr, 0, sizeof(serv_addr));

        // setup the host_addr structure for use in bind call
        // server byte order
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(port);
        // automatically be filled with current host's IP address
        serv_addr.sin_addr.s_addr = INADDR_ANY;

        // Create socket
        // socket(int domain, int type, int protocol)
        // i.e. IPV_4, TCP, default
        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        if (sockfd < 0) {
            printf("ERROR opening socket\n");
            exit(0);
        }

        // Create bind
        if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
            printf("ERROR on binding\n");
            exit(0);
        }

        // start listening
        // This listen() call tells the socket to listen to the incoming connections.
        // The listen() function places all incoming connection into a backlog queue
        // until `() call accepts the connection.
        // Here, we set the maximum size for the backlog queue to 5.
        listen(sockfd, 5);

        // The accept() call actually accepts an incoming connection
        clilen = sizeof(cli_addr);

        // This accept() function will write the connecting client's address info
        // into the the address structure and the size of that structure is clilen.
        // The accept() returns a new socket file descriptor for the accepted connection.
        // So, the original socket file descriptor can continue to be used
        // for accepting new connections while the new socker file descriptor is used for
        // communicating with the connected client.
        newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
        printf("Ending accept function\n");

        if (newsockfd < 0) {
            printf("ERROR on accept");
            exit(0);
        }

        printf("server: got connection from %s port %d\n",
               inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));

    }

    ~TCPServer() {
        close(newsockfd);
        close(sockfd);
    }

    void createSocket() {
        // create a socket
        // socket(int domain, int type, int protocol)
        // i.e. IPV_4, TCP, default
        sockfd = socket(AF_INET, SOCK_STREAM, 0);

        if (sockfd < 0) {
            printf("ERROR opening socket\n");
            exit(0);
        }

    }

    void transmitData(char data[]) {
        // This send() function sends the 13 bytes of the string to the new socket
        send(newsockfd, data, strlen(data), 0);

    }

    char* receiveData() {

        memset(buffer, 0, sizeof(buffer));

        int n = read(newsockfd, buffer, sizeof(buffer));
        if (n < 0) {
            printf("ERROR reading from socket\n");
            exit(0);
        }

        return buffer;

    }

};

А вот код, который я использовал для создания соединения; это часть, которая работает на моем настольном компьютере (получает соединение и отображает выходной код)

void* sensor_com(void* conn_data_void) {
    struct conn *conn_data = (struct conn*)conn_data_void;

    printf("printing from pthread\n");
    printf("port: %d \n", (*conn_data).port);

    TCPServer *sensor_com = new TCPServer(conn_data->port);

    char *buf = (char*) malloc(sizeof(char)*256);

    while(1) {

        // receive data from ROV and translate json
        char *buffer = (*sensor_com).receiveData();
        std::string json(buffer);

        picojson::value v;

        std::string err = picojson::parse(v, json);
        if (! err.empty()) {
        std:cerr << err << std::endl;
        }

        // check if the type of the value is "object"
        if (! v.is<picojson::object>()) {
            std::cerr << "JSON is not an object" << std::endl;
            exit(2);
        }

        std::map<std::string, string> data;

        // obtain a const reference to the map, and print the contents
        const picojson::value::object& obj = v.get<picojson::object>();
        for (picojson::value::object::const_iterator i = obj.begin();
             i != obj.end();
             ++i) {
            data[i->first] = i->second.to_str();
        }

        cout << "accel_x of rov: " << data["accel_x"] << endl;
        cout << "accel_y of rov: " << data["accel_y"] << endl;
        cout << "accel_z of rov: " << data["accel_z"] << endl;
        cout << "gyro_x of rov: " << data["gyro_x"] << endl;
        cout << "gyro_y of rov: " << data["gyro_y"] << endl;
        cout << "gyro_z of rov: " << data["gyro_z"] << endl;

    }

    free(buf);

    return NULL;

}

А это часть на микроконтроллере / биглебоне

void * sensor_com (void * conn_data_void) {

struct conn *conn_data = (struct conn*)conn_data_void;
unsigned int port = (*conn_data).port;

printf("printing from pthread\n");
printf("port: %d \n", port);

// create TCP connection includeing socket and connection call
TCPClient *sensor_com = new TCPClient(conn_data->port, conn_data->host);

char* val;

// Data from MPU6050
struct sensor_data movement;

if (RUNNING_ON_BEAGLEBONE) {
    initialize_i2c();
}

// send data to master forever
while (1) {

    if (RUNNING_ON_BEAGLEBONE) {
        // collect data from I2C_interface
        get_data(&movement);
    } else {
        // get data here
        movement.accel_x = 10;
        movement.accel_y = 10;
        movement.accel_z = 10;
        movement.gyro_x = 10;
        movement.gyro_y = 10;
        movement.gyro_z = 10;
    }
    // Create json for data to be stored
    string data = "{";

    // Add accelleration data
    data += "\"accel_x\": \"" + std::to_string(movement.accel_x) + "\",";
    data += "\"accel_y\": \"" + std::to_string(movement.accel_y) + "\",";
    data += "\"accel_z\": \"" + std::to_string(movement.accel_z) + "\",";

    // Add gyroscopic dataa
    data += "\"gyro_x\": \"" + std::to_string(movement.gyro_x) + "\",";
    data += "\"gyro_y\": \"" + std::to_string(movement.gyro_y) + "\",";
    data += "\"gyro_z\": \"" + std::to_string(movement.gyro_z) + "\"}";

    // convert to char array
    char *charData = new char [data.length()+1];
    strcpy(charData, data.c_str());

    (*sensor_com).transmitData(charData);

    // delay for readability
    sleep(2);

}

free(val);

return NULL;

}

Я прошу прощения за стену кода, хотя, честно говоря, я думаю, что проблема связана с промежуточной связью, поэтому я не знаю, будет ли это полезно. Код работает нормально, когда он находится на одной машине (проблема заключается только в обмене данными между машинами). Я также пытался использовать tcpdump, но я не могу понять, как использовать его для отправки пакетов на другой сервер, я начинаю думать, что это просто для прослушивания пакетов, в этом случае это не очень полезно.

Любое руководство будет с благодарностью, спасибо!

1 Ответ

0 голосов
/ 03 мая 2019

Так что я как-то разобрался в проблеме, во многом благодаря @ user4581301

Я закончил тем, что пытался пересобрать самую простую версию, какую только мог, и обнаружил, что исходный код, на котором я основывался, очень многомоего кода от была проблема (я не могу найти ссылку, но это был просто учебник).Он работал на любой машине независимо, но если вы попытались передать данные между двумя машинами, это не сработало (возможно, что-то, связанное с различными библиотеками между операционной системой Debian на beaglebone и Mac OS на моем ноутбуке, или просто некоторые функции былиустарела).

В итоге я перестроил TCP-соединение с этого сайта (http://man7.org/linux/man-pages/man3/getaddrinfo.3.html), которое использовало более новые методы и могло работать на разных платформах без проблем. Поэтому я не совсем уверен, чтопроблема в том, что если у вас возникли проблемы с кросс-платформенным взаимодействием, я бы рекомендовал взглянуть на ссылку man7.

Спасибо всем за помощь!

...