문제

I am trying to wrap my head around how sockets work after deciding to try to talk to some equipment at work. The basic details are that the equipment uses the ModBus RTU protocol over UDP. The data sheet says that the equipment listens on port 2001 and replies back to port 2000. After trying to find some example code I found a modbus library and managed to get it to work with some simulators where send and receive seem to be on the same port. However, I can't seem to get it to work with my equipment. I think the problem has to do with ports. I have looked all over and can't seem to turn up anything useful (maybe I just don't have a good enough understanding). Here is the code I'm working with, does anyone have any pointers.

//------------------------------------------------------------------------------
// Copyright (C) 2010, Raditex AB
// All rights reserved.
//
// FreeSCADA
// http://www.FreeSCADA.com
// freescada@freescada.com
//
//------------------------------------------------------------------------------

#include "modbus.h"
#include "modbus-udp.h"

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

//------------------------------------------------------------------------------
//
//
//------------------------------------------------------------------------------
int
modbus_udp_close(modbus_udp_handle_t *handle)
{
    if (handle == NULL)
        return -1;

    close(handle->sock);

    return 0;
}

//------------------------------------------------------------------------------
//
//
//------------------------------------------------------------------------------
int
modbus_udp_init(char *host, int port, modbus_udp_handle_t *handle, int delay)
{
    struct timeval timeout;

    if (handle == NULL)
        return -1;

    if ((handle->sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    {
        snprintf(modbus_error_str, sizeof(modbus_error_str), "%s: couldn't get socket: %s",
                 __PRETTY_FUNCTION__, strerror(errno));
        return -1;
    }

    timeout.tv_sec  = delay;
    timeout.tv_usec = 0;

    if (setsockopt(handle->sock, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(struct timeval)) == -1)
    {
        snprintf(modbus_error_str, sizeof(modbus_error_str), "%s: couldn't set receive timeout: %s.",
                 __PRETTY_FUNCTION__, strerror(errno));
        return -1;
    }

    /*
     if ((flags = fcntl(handle->sock, F_GETFL, 0)) == -1)
     {
     snprintf(modbus_error_str, sizeof(modbus_error_str),
     "%s: couldn't get fd option non-blocking: F_GETFL.", __PRETTY_FUNCTION__);
     return NULL;
     }

     if (fcntl(io->sock, F_SETFL, flags|O_NONBLOCK) == -1)
     {
     snprintf(modbus_error_str, sizeof(modbus_error_str),
     "%s: couldn't set option non-blocking: F_SETFL.", __PRETTY_FUNCTION__);
     return NULL;
     }
     */

    handle->saddr.sin_family = AF_INET;

    if ((handle->addr = gethostbyname(host)) == NULL)
    {
        snprintf(modbus_error_str, sizeof(modbus_error_str), "%s: couldn't get host: %s: %s",
                 __PRETTY_FUNCTION__, strerror(errno), host);
        return -1;
    }


    bcopy((char *) handle->addr->h_addr,
          (char *)&handle->saddr.sin_addr,
          handle->addr->h_length);

    handle->saddr.sin_port = htons(port);

    return 0;
}


//------------------------------------------------------------------------------
//
//
//------------------------------------------------------------------------------
int
modbus_udp_send(modbus_udp_handle_t *handle, modbus_packet_t *pkt)
{
    char buff[256];
    int len;

    if (pkt == NULL)
        return -1;

    len = modbus_packet_pack(pkt, buff, sizeof(buff));

    if (sendto(handle->sock, buff, len, 0, (struct sockaddr *)&handle->saddr, sizeof(handle->saddr)) != len)
    {
        snprintf(modbus_error_str, sizeof(modbus_error_str),
                 "%s: failed to send modbus UDP packet", __PRETTY_FUNCTION__);
        return -1;
    }

    return 0;
}

//------------------------------------------------------------------------------
//
//
//------------------------------------------------------------------------------
int
modbus_udp_recv(modbus_udp_handle_t *handle, modbus_packet_t *pkt)
{
    socklen_t fromlen;
    struct sockaddr_in caller;
    char buff[256];
    int len;

    // read UDP data
    fromlen = sizeof (caller);
    if ((len = recvfrom(handle->sock, buff, sizeof(buff), 0, (struct sockaddr *)&caller, &fromlen)) > 0)
    {
        return modbus_packet_parse(pkt, buff, len);
    }

    return -1;
}
도움이 되었습니까?

해결책

The data sheet says that the equipment listens on port 2001 and replies back to port 2000.

That means you need to create a socket and bind() it to a local IP on port 2000, and then sendto() the equipment's IP on port 2001. The code you showed is not calling bind() at all, so there is no local port for recvfrom() to receive data on.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top