Send a struct over the network from C# app

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.
jd9288Asked:
Who is Participating?
 
jkrConnect With a Mentor Commented:
It probably means that you read text data. How do you 'receive' on the C++ side?
0
 
jkrCommented:
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
 
jd9288Author Commented:
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
Cloud Class® Course: Certified Penetration Testing

This CPTE Certified Penetration Testing Engineer course covers everything you need to know about becoming a Certified Penetration Testing Engineer. Career Path: Professional roles include Ethical Hackers, Security Consultants, System Administrators, and Chief Security Officers.

 
jd9288Author Commented:
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
 
jd9288Author Commented:
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
 
jkrCommented:
And how do you fill 'rec'?
0
 
jd9288Author Commented:
Winsock,
recv (sock, buffer, MSG_CHUNK, 0);
I works well for all other stuff.
0
 
jkrCommented:
Could you post the code?
0
 
jd9288Author Commented:
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
 
jkrCommented:
Well, not *all* the code, just the part that does the 'recv()' :o)
0
 
jd9288Author Commented:
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
 
jkrCommented:
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
 
jd9288Author Commented:
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
 
jkrCommented:
>> 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
 
jd9288Author Commented:
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
 
jkrCommented:
You're most welcome :o)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.