Click to See Complete Forum and Search --> : Winsock (Socket Programming) Can Anyone Help?


softweng
May 25th, 2001, 12:03 PM
I am trying to create a Class that can be used to communicate with a device using Modbus TCP protcol.
Basically you just send a command out on the TCP/IP connection in a certain format.
I have a C++ example and an OCX written by someone else that can do this. I don't know that
much about C++ but it is pretty simple to do. You build a command string and send it out and wait for a response. The C++ and OCX work fine.
I have a packet sniffer and looked at the data inside the packet and it is formated correctly (Using the C++ OCX).
when I try to send the command string in the same format the winsock control formats it to hex and then the command is wrong. If I sniff the packet
from my class the data is not correct. Is there a way to stuff the command string right into the
TCP/IP packet without it reformatting the data?
the command looks like this "00000000000601040000000A" it is in hex. It should look like this in the packet:
"00 00 00 00 00 06 01 04 00 00 00 0A"
But when I send the command it puts it into the packet like this:
"30 30 30 30 30 30 30 30 30 30 30 36 30 31 30 34 30 30 30 30 30 30 30 41"
I cannot figure out how to do this. If anyone has any Ideas or knows something about Socket Programming
I would appreciate some help. I am a VB programmer that does not know much about C++ and how it passes data to a TCP socket. I have
included here the C++ sample I found if anyone can tell me how to do the same in VB it would be a life saver.
Thanks for any help you can provide!!!!!!!

Here's the C++ code Sample. I have the whole OCX project in C++ too if it would help.

// test1.cpp - Win32 console app to read registers
// ============================================================
// test1.cpp 5/23/97

// example Win32 C++ program to read registers from PLC via gateway

// compile with BC45 or BC50
// default settings for Win32 console app
// empty DEF file

#include <winsock.h>
#include <stdio.h>
#include <conio.h>


int main(int argc, char **argv)
{
if (argc<5)
* {
*** printf("usage: test1 ip_adrs unit reg_no num_regs\n"
*** "eg test1 198.202.138.72 5 0 10\n");
*** return 1;
* }
* char *ip_adrs = argv[1];
* unsigned short unit = atoi(argv[2]);
* unsigned short reg_no = atoi(argv[3]);
* unsigned short num_regs = atoi(argv[4]);
* printf("ip_adrs = %s unit = %d reg_no = %d num_regs = %d\n",
* ip_adrs, unit, reg_no, num_regs);

* // initialize WinSock
* static WSADATA wd;
* if (WSAStartup(0x0101, &wd))
* {
*** printf("cannot initialize WinSock\n");
*** return 1;
* }

* // set up socket
* SOCKET s;
* s = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
* struct sockaddr_in server;
* server.sin_family = AF_INET;
* server.sin_port = htons(502); // ASA standard port
* server.sin_addr.s_addr = inet_addr(ip_adrs);
* int i;
* i = connect(s, (sockaddr *)&server, sizeof(sockaddr_in));
* if (i<0)
* {
*** printf("connect - error %d\n",WSAGetLastError());
*** closesocket(s);
*** WSACleanup();
*** return 1;
* }
* fd_set fds;
* FD_ZERO(&fds);
* timeval tv;
* tv.tv_sec = 5;
* tv.tv_usec = 0;

* // wait for permission to send
* FD_SET(s, &fds);
* i = select(32, NULL, &fds, NULL, &tv); // write
* if (i<=0)
* {
*** printf("select - error %d\n",WSAGetLastError());
*** closesocket(s);
*** WSACleanup();
*** return 1;
* }

* // build request of form 0 0 0 0 0 6 ui 3 rr rr nn nn
* unsigned char obuf[261];
* unsigned char ibuf[261];
* for (i=0;i<5;i++) obuf[i] = 0;
* obuf[5] = 6;
* obuf[6] = unit;
* obuf[7] = 3;
* obuf[8] = reg_no >> 8;
* obuf[9] = reg_no & 0xff;
* obuf[10] = num_regs >> 8;
* obuf[11] = num_regs & 0xff;

* // send request
* i = send(s, obuf, 12, 0);
* if (i<12)
* {
*** printf("failed to send all 12 chars\n");
* }

* // wait for response
* FD_SET(s, &fds);
* i = select(32, &fds, NULL, NULL, &tv); //read
* if (i<=0)
* {
*** printf("no TCP response received\n");
*** closesocket(s);
*** WSACleanup();
*** return 1;
* }

* // read response
* i = recv(s, ibuf, 261, 0);
* if (i<9)
* {
*** if (i==0)
*** {
***** printf("unexpected close of connection at remote end\n");
*** }
*** else
*** {
***** printf("response was too short - %d chars\n", i);
*** }
* }
* else if (ibuf[7] & 0x80)
* {
*** printf("MODBUS exception response - type %d\n", ibuf[8]);
* }
* else if (i != (9+2*num_regs))
* {
*** printf("incorrect response size is %d expected %d\n",i,(9+2*num_regs));
* }
* else
* {
*** for (i=0;i<num_regs;i++)
*** {
***** unsigned short w = (ibuf[9+i+i]<<8) + ibuf[10+i+i];
***** printf("word %d = %d\n", i, w);
*** }
* }

* // close down
* closesocket(s);
* WSACleanup();
* return 0;
}



Kris
Software Engineer
Phoenix,AZ

jgonzale
May 25th, 2001, 03:35 PM
It looks like you're stuffing a VB ASCII string (of hex characters) into your packet. For example, you want 5 sets of 00's followed by a 06 in hex (00 00 00 00 00 06). But, your sniffed data is displaying 5 sets of 30's followed by 36. This is because an ascii value of 0 is decimal 48 and 30h(hex). ASCII 6 is 36h.

You want the actual real values in your TCP/IP packet and not a string of hex values. So, I would not convert the numbers to hex strings, and if you are using strings you need to convert them to BYTE data type or some other way of getting just the value. I'm still new to VB so I'm not sure what the command is, Val() CByte() ??

Hope this helps.

John

coolbiz
May 25th, 2001, 07:31 PM
You parsing the command string incorrectly.

the command looks like this "00000000000601040000000A" it is in hex. It should look like this in the packet:
"00 00 00 00 00 06 01 04 00 00 00 0A"
But when I send the command it puts it into the packet like this:
"30 30 30 30 30 30 30 30 30 30 30 36 30 31 30 34 30 30 30 30 30 30 30 41"

The command string is already in hex and it seems like your converting it again to hex for each char in the string. Since a HEX is represented as 2 chars, so you actually have 12 bytes of of data. If you want to parse that information into a string then you can use the ASC() function by passing in each of the 2 chars.

So to convert the sample above:
dim szBuffer as String
szBuffer = chr$(00) & chr$(00) & chr$(00) & chr$(00) & chr$(00) & chr$(06)
szBuffer = szBuffer & chr$(01) & chr$(04) & chr$(00) & chr$(00) & chr$(00) & chr$(0A)

Try it out and hopefully it works.
-Cool Bizs

coolbiz
May 26th, 2001, 06:59 AM
Sorry. There were typos in my prev reply. The correct syntax:

So to convert the sample above:
dim szBuffer as String
szBuffer = chr$(&H00) & chr$(&H00) & chr$(&H00) & chr$(&H00) & chr$(&H00) & chr$(&H06)
szBuffer = szBuffer & chr$(&H01) & chr$(&H04) & chr$(&H00) & chr$(&H00) & chr$(&H00) & chr$(&H0A)

-Cool Bizs