Solved

Send a struct over the network from C# app

Posted on 2004-09-02
16
366 Views
Last Modified: 2008-01-16
I have this struct, defined in my C++ program like so:

struct WO
{
     int MJID;  
     int Action;
     char szAisle[4];
     char szSection[4];
     char szSerial[16];
     char szOrder[16];
 };

I defined it in C# like this:

[StructLayout(LayoutKind.Explicit,CharSet=CharSet.Ansi)]
      public struct WO
      {
            [FieldOffset(0)] public int MJID;
            [FieldOffset(4)] public int Action;
 
            [FieldOffset(8)] public byte szAisle0;
            [FieldOffset(9)] public byte szAisle1;
            [FieldOffset(10)] public byte szAisle2;
            [FieldOffset(11)] public byte szAisle3;

            [FieldOffset(12)] public byte szSection0;
            [FieldOffset(13)] public byte szSection1;
            [FieldOffset(14)] public byte szSection2;
            [FieldOffset(15)] public byte szSection3;

            [FieldOffset(16)] public byte szSerial0;
            [FieldOffset(17)] public byte szSerial1;
            [FieldOffset(18)] public byte szSerial2;
            [FieldOffset(19)] public byte szSerial3;
            [FieldOffset(20)] public byte szSerial4;
            [FieldOffset(21)] public byte szSerial5;
            [FieldOffset(22)] public byte szSerial6;
            [FieldOffset(23)] public byte szSerial7;
            [FieldOffset(24)] public byte szSerial8;
            [FieldOffset(25)] public byte szSerial9;
            [FieldOffset(26)] public byte szSerial10;
            [FieldOffset(27)] public byte szSerial11;
            [FieldOffset(28)] public byte szSerial12;
            [FieldOffset(29)] public byte szSerial13;
            [FieldOffset(30)] public byte szSerial14;
            [FieldOffset(31)] public byte szSerial15;

            [FieldOffset(32)] public byte szOrder0;
            [FieldOffset(33)] public byte szOrder1;
            [FieldOffset(34)] public byte szOrder2;
            [FieldOffset(35)] public byte szOrder3;
            [FieldOffset(36)] public byte szOrder4;
            [FieldOffset(37)] public byte szOrder5;
            [FieldOffset(38)] public byte szOrder6;
            [FieldOffset(39)] public byte szOrder7;
            [FieldOffset(40)] public byte szOrder8;
            [FieldOffset(41)] public byte szOrder9;
            [FieldOffset(42)] public byte szOrder10;
            [FieldOffset(43)] public byte szOrder11;
            [FieldOffset(44)] public byte szOrder12;
            [FieldOffset(45)] public byte szOrder13;
            [FieldOffset(46)] public byte szOrder14;
            [FieldOffset(47)] public byte szOrder15;
       };

How do I send this struct from C# as array of bytes???
I tried everything I could think of, including MemoryStream,
but what I'm getting in C++ receiving app is just zeros.

Please help.
0
Comment
Question by:jd9288
  • 8
  • 8
16 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 11963734
You need to turn off structure packing on the C++ side:

#pragma pack ( push, WO)
// disable structure packing
#pragma pack ( 1)

struct WO
{
    int MJID;  
    int Action;
     char szAisle[4];
    char szSection[4];
    char szSerial[16];
    char szOrder[16];
};

// set back to default
#pragma pack ( pop, WO)
0
 

Author Comment

by:jd9288
ID: 11963906
That maybe helpfull, but later, right now it didn't change anything,
I'm sure I'm not creating that byte array on the C# side correctly.
Here's what I do:

                        MemoryStream ms = new MemoryStream();
                        BinaryWriter writer = new BinaryWriter( ms );
                        writer.Write( m_iMJID );
                        writer.Write( cboAction.SelectedIndex == 0 ? (int) eWO_ACTION.evWO_SHIP : (int) eWO_ACTION.evWO_PUT );
                        writer.Write( cboAisle.Text.PadRight(4, '\0') );
                        writer.Write( cboSection.Text.PadRight(4, '\0') );
                        writer.Write( cboSerial.Text.PadRight(16, '\0') );
                        writer.Write( cboOrder.Text.PadRight(16, '\0') );
                        byte[] b = new byte[ms.Length];
                        ms.ToArray().CopyTo(b,0);
0
 

Author Comment

by:jd9288
ID: 11965479
I changed my struct to a class in C#, and everything is fine converting it
to a byte array.
But on the C++ side, I receive all zeros if there's even one zero in the byte array I'm sending from C#.
For example, if szAisle if 3 chars instead of 4, I'll receive the same value for szAisle
in C++, but szSection, szSerial  and szOrder will be all zeros.
What does that mean?
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 11965521
It probably means that you read text data. How do you 'receive' on the C++ side?
0
 

Author Comment

by:jd9288
ID: 11965678
I receive unsigned char* rec, that contains added header, Header_type.
And then I tried:

WO *wo =  (WO *) &rec[sizeof(Header_type)];

and:

WO *wo = new WO();
memcpy(wo, &rec[sizeof(Header_type)], sizeof(WO));

both with the result I already described.
I'm really stuck on this one...
0
 
LVL 86

Expert Comment

by:jkr
ID: 11965764
And how do you fill 'rec'?
0
 

Author Comment

by:jd9288
ID: 11965809
Winsock,
recv (sock, buffer, MSG_CHUNK, 0);
I works well for all other stuff.
0
 
LVL 86

Expert Comment

by:jkr
ID: 11965865
Could you post the code?
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 

Author Comment

by:jd9288
ID: 11965948
I'd be glad to, trust me, but all the relevant code is here already.
The app is very big, network transmission is done first thru the wireless interface to another app I've written,
that either routes the message to the recepient or broadcasts it via multicast.
I could send you the code for all 3 applications involved in this (1 C#, 2 C++),
but it'll be presumptious of me to think you have time to figure all this out.
It's just not feasible, regardless of how much I need to get this going.
At this point, I'm ready to try any suggestion that you may have,
anything...
0
 
LVL 86

Expert Comment

by:jkr
ID: 11965986
Well, not *all* the code, just the part that does the 'recv()' :o)
0
 

Author Comment

by:jd9288
ID: 11966034
OK, here it is:

      int RecvThreadWork ()
      {
            const int MSG_CHUNK = 2048;

            int            status = 0;
            char      buffer[MSG_CHUNK];
            SOCKET      sock;

            while (true)
            {
                  sock = m_hSocket;

                  if (sock == INVALID_SOCKET)
                  {
                        if (m_hCloseFunc) (m_hCloseFunc) ((LPARAM) this);      //      if a function ptr was given, call the function

                        return 0;
                  }

                  memset (buffer, 0, MSG_CHUNK);

                  status = recv (sock, buffer, MSG_CHUNK, 0);
                  if (status == SOCKET_ERROR)
                  {
                        sprintf (ErrStr, "recv() failed in RecvThread(), Err: %d\n", WSAGetLastError());

                        if (m_hErrorFunc) (m_hErrorFunc) ();      //      if a function ptr was given, call the function

                        Disconnect ();
                        return 0;
                  }

                  if (status > 0)
                  {
                        if (m_hRecvFunc) (m_hRecvFunc) ((LPARAM) this, buffer, status);      //      if a function ptr was given, call the function
                  }
                  else
                  {
                        //socket was gracefully closed, no error
                        Disconnect ();
                        return 0;
                  }
            }

            return 0;
      }
0
 
LVL 86

Expert Comment

by:jkr
ID: 11966096
Here's one thing that puzzles me:

               if (status > 0)
              {
                   if (m_hRecvFunc) (m_hRecvFunc) ((LPARAM) this, buffer, status);     //     if a function ptr was given, call the function
              }

should actually be

               if (status == MSG_CHUNK)
              {
                   if (m_hRecvFunc) (m_hRecvFunc) ((LPARAM) this, buffer, status);     //     if a function ptr was given, call the function
              } else {

                   HandleError ( "Not all the requested data could be received!");
              }

If the sending side stops the transmission when a NULL byte is encountered, just checking for 'status > 0' would explain what you encounter as a problem now.
0
 

Author Comment

by:jd9288
ID: 11966340
Why would the sending side stop the transmission when a NULL byte is encountered?
Here's my C# sending code:

public class threadState
      {
            public string ip;
            public string port;
            public byte[] b;
      }

public void sendStart(object state)
            {
                  IPAddress ip;
                  threadState st = (threadState) state;
      
                  ip=IPAddress.Parse(st.ip);
                  
                  Socket s=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);

                  s.SetSocketOption(SocketOptionLevel.IP,
                              SocketOptionName.IpTimeToLive, 32);

                  s.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
                  

                  IPEndPoint ipep=new IPEndPoint(IPAddress.Parse(st.ip),int.Parse(st.port));

                  s.Connect(ipep);

                  s.Send(st.b,st.b.Length,SocketFlags.None);

                  s.Close();
                       
                  }
0
 
LVL 86

Expert Comment

by:jkr
ID: 11966393
>> Why would the sending side stop the transmission when a NULL byte is encountered?

I don't know C# - but, since you are sending binary data, a test like ' if (status == MSG_CHUNK)' is *mandantory* to ensure the integrity of the data received...
0
 

Author Comment

by:jd9288
ID: 11966844
Well, that wasn't it, but you definitely pointed me into right direction:
I was calculating message size incorrectly in my routing app.
Points are rightfully yours,
thank you very much!
0
 
LVL 86

Expert Comment

by:jkr
ID: 11966869
You're most welcome :o)
0

Featured Post

Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

Join & Write a Comment

Introduction This article is the first in a series of articles about the C/C++ Visual Studio Express debugger.  It provides a quick start guide in using the debugger. Part 2 focuses on additional topics in breakpoints.  Lastly, Part 3 focuses on th…
C++ Properties One feature missing from standard C++ that you will find in many other Object Oriented Programming languages is something called a Property (http://www.experts-exchange.com/Programming/Languages/CPP/A_3912-Object-Properties-in-C.ht…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will learn how to clear a vector as well as how to detect empty vectors in C++.

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now