簡體   English   中英

如何在兩台設備之間與 TCP 通信時修復錯誤“連接被拒絕”

[英]How to fix error 'Connection Refused' when communicating with TCP between two devices

所以我目前正在嘗試通過 TCP 從運行 debian 的 beaglebone black 到 mac 進行通信。 我想從 beaglebone 通信到 mac 並在兩者之間發送短信。 我的代碼設置方式是我有一個主連接,我使用 UDP 連接在端口 1000 上流式傳輸視頻,這本身就可以正常工作,但我已經設置了一個基本的 TCP 連接來通過端口發送文本10001 在一個單獨的 pthread 中,當在兩個設備之間連接時,它給了我輸出

ERROR connecting -1 Connection refused 111

如果我打印出它所說的值

Port: 10001, name: 192.168.1.37

對我來說特別有趣的是,我知道 IP 地址是正確的,因為我可以使用 IP 地址和端口 10000 流式傳輸視頻。

總體設置是我有一個 beaglebone 微控制器(基本上是樹莓派)連接到路由器,我的 mac 通過以太網連接到同一路由器。 我正在使用庫“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;

}

這是微控制器/beaglebone 上的部分

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 但我不知道如何使用它來將數據包發送到另一台服務器,我開始認為它只是用於偵聽數據包,在這種情況下它不是很有幫助。

任何指導將不勝感激,謝謝!

所以我有點想通了這個問題,這在很大程度上要歸功於@user4581301

我最終嘗試重建我能做到的最簡單的版本,我發現我基於很多代碼的原始來源是問題所在(我找不到鏈接,但它只是一個教程)。 它可以獨立地在任何一台機器上工作,但如果你試圖在兩台機器之間發送數據,它就無法工作(可能與 beaglebone 上的 debian os 和我的筆記本電腦上的 mac os 之間的不同庫有關,或者只是其中的一些功能貶值)。

我最終從這個站點 ( http://man7.org/linux/man-pages/man3/getaddrinfo.3.html ) 重建了 TCP 連接,它使用了更新的技術並且能夠跨平台工作而不會出現問題。 所以我想我不完全確定問題是什么,但是如果您在跨平台通信時遇到問題,我建議您查看 man7 鏈接。

感謝大家的幫助!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM