⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mbserver.cpp

📁 MODBUS TCP(C++)Example ModbusTCP server - source and WIN32 executable有可执行文件
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// mbserver.c V2.1 1/18/01
// example multi-session Modbus/TCP server supporting class 0 commands

// This program should work under UNIX (as C or C++) or Win32 (as C or C++)

// the symbol WIN32 will be defined if compiling for Windows. Assume if it is not
// set that we are compiling for some form of UNIX

// V2.0 1/14/00 added 10 second idle timeout option
// V2.1 1/18/01 timeout was not being reset on successful traffic
// V2.2 7/27/01 defaults for EXE set to sessions = 100, listen() backlog set to same, timeout on

#ifndef WIN32

// various flavors of UNIX may spread their include files in different ways
// the set below is correct for Redhat Linux 5.1 and 6.1 and Ultrix V4.3A

#include <stdio.h> // printf
#include <errno.h> // errno
#include <unistd.h> // close
#include <sys/time.h> // timeval
#include <sys/socket.h> // socket bind listen accept recv send
#include <sys/ioctl.h> // FIONBIO
#include <netinet/in.h> // sockaddr_in sockaddr INADDR_ANY

typedef int SOCKET;
const int INVALID_SOCKET=(~(int)0);

// the following fake out the Winsock-specific routines

typedef struct WSAData { int w;} WSADATA;
int WSAStartup(int v, WSADATA *pw) { return 0;}
int WSACleanup() {}
int WSAGetLastError() { return (errno);}
int closesocket(SOCKET s) { close(s); }
int ioctlsocket(SOCKET s, long cmd, unsigned long *valp) { ioctl(s, cmd, valp); }
#define WSAEWOULDBLOCK EWOULDBLOCK

#else // must be WIN32

#include <winsock.h>
#include <stdio.h> // printf
#include <time.h> // time, difftime

#endif



///////////////////////////////////////////////////////////////////////
// configuration settings
///////////////////////////////////////////////////////////////////////

#define numSockets 100	/* number of concurrent server sessions */
#define num4xRegs 10000	/* number of words in the 'register table' maintained by this server */
#define IDLE_TIMEOUT 1	/* set if the session idle timeout to be enforced */

///////////////////////////////////////////////////////////////////////
// data structure definitions
///////////////////////////////////////////////////////////////////////

// maintain a data structure per session,into which can be stored partial msgs

struct fragMsg 
{
    int fragLen;                // length of request assembled so far
    unsigned char fragBuf[261]; // request so far assembled
};

///////////////////////////////////////////////////////////////////////
// global data definition
///////////////////////////////////////////////////////////////////////

struct fragMsg frag[numSockets];
time_t openTime[numSockets];

// make a 'state table' to read and write into

unsigned short reg4x[num4xRegs];

///////////////////////////////////////////////////////////////////////
// utility routines
///////////////////////////////////////////////////////////////////////


// extract a 16-bit word from an incoming Modbus message

unsigned short getWord(unsigned char b[], unsigned i) 
{
    return (((unsigned short)(b[i])) << 8) | b[i+1];
}

// write a 16-bit word to an outgoing Modbus message

void putWord(unsigned char b[], unsigned i, unsigned short w) 
{
    b[i] = (unsigned char)(w >> 8);
    b[i+1] = (unsigned char)(w & 0xff);
}

///////////////////////////////////////////////////////////////////////
// process legitimate Modbus/TCP requests
///////////////////////////////////////////////////////////////////////

int processMsg(unsigned char b[],   // message buffer, starting with prefix
               unsigned len)        // length of incoming messsage
                                    // returns length of response
{

    // if you wish to make your processing dependent upon unit identifier
    // use b[6]. Many PLC devices will ignore this field, and most clients
    // default value to zero. However gateways or specialized programs can
    // use the unit number to indicate what type of precessing is desired

    unsigned i;

    // handle the function codes 3 and 16

    switch(b[7]) 
    {
        case 3:     // read registers
                    // request   03 rr rr nn nn
                    // response  03 bb da ta ......
        {
            unsigned regNo = getWord(b, 8);
            unsigned regCount = getWord(b, 10);
            if (len != 12) 
            {
                // exception 3 - bad structure to message
                b[7] |= 0x80;
                b[8] = 3;
                b[5] = 3; // length
                break;
            }
            if (regCount < 1 || regCount > 125 || 
				regNo >= num4xRegs || (regCount + regNo) > num4xRegs) 
            {
                // exception 2 - bad register number or length
                b[7] |= 0x80;
                b[8] = 2;
                b[5] = 3; // length
                break;
            }
            // OK so prepare the 'OK response'
            b[8] = 2 * regCount;
            b[5] = b[8] + 3;
            for (i=0;i<regCount;i++) 
            {
                putWord(b, 9+i+i, reg4x[i + regNo]);
            }
        }
        break;

        case 16:    // write registers
                    // request 
        {
            unsigned regNo = getWord(b, 8);
            unsigned regCount = getWord(b, 10);
            if (len != 13 + regCount + regCount || 
            b[12] != regCount + regCount) 
            {
                // exception 3 - bad structure to message
                b[7] |= 0x80;
                b[8] = 3;
                b[5] = 3; // length
                break;
            }
            if (regCount < 1 || regCount > 100 || 
				regNo >= num4xRegs || (regCount + regNo) > num4xRegs) 
            {
                // exception 2 - bad register number or length
                b[7] |= 0x80;
                b[8] = 2;
                b[5] = 3; // length
                break;
            }
            // OK so process the data
            for (i=0;i<regCount;i++) 
            {
                reg4x[i + regNo] = getWord(b, 13+i+i);
            }
            // and the OK response is a copy of the request to byte 11
            b[5] = 6;
        }
        break;

        default:
        // generate exception 1 - unknown function code
        b[7] |= 0x80;
        b[8] = 1;
        b[5] = 3; // length
        break;
    }

    // return the total size of the MB/TCP response
    // notice that bytes 0-4 and 6 will be identical to those of the request

    return 6+b[5];
}

///////////////////////////////////////////////////////////////////////
// main entry point for the program
///////////////////////////////////////////////////////////////////////

int main(int argc, char **argv) // arguments ignored for now
{
    int i;
    SOCKET csa[numSockets];
    SOCKET s;
    struct sockaddr_in server;
    static WSADATA wd;

    unsigned long nbiotrue = 1;

    printf("mbserver V2.2 7/27/01 Reference Class 0 Modbus/TCP Server\n"
			"sessions = %u, registers = %u, idle timeout = %s\n", 
			numSockets, num4xRegs, IDLE_TIMEOUT?"true":"false");

    // initialize WinSock
    if (WSAStartup(0x0101, &wd))
    {
        printf("cannot initialize WinSock\n");
        return 1;
    }
    // set up an array of socket descriptors, initially set to INVALID_SOCKET (not in use)
    // and initialize the fragment buffer

    for (i=0;i<numSockets;i++) 
    {
        csa[i] = INVALID_SOCKET;
        frag[i].fragLen = 0;
    }

    // set up listen socket

    s = socket(PF_INET, SOCK_STREAM, 0);
    server.sin_family = AF_INET;
    server.sin_port = htons(502); // ASA standard port
    server.sin_addr.s_addr = INADDR_ANY;

    i = bind(s, (struct sockaddr *)&server, sizeof(struct sockaddr_in));
    if (i<0)
    {
        printf("bind - error %d\n",WSAGetLastError());
        closesocket(s);
        WSACleanup();
        return 1;
    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -