Solved

Send a struct over the network from C# app

Posted on 2004-09-02
16
373 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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
 

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

Enroll in May's Course of the Month

May’s Course of the Month is now available! Experts Exchange’s Premium Members and Team Accounts have access to a complimentary course each month as part of their membership—an extra way to increase training and boost professional development.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

  Included as part of the C++ Standard Template Library (STL) is a collection of generic containers. Each of these containers serves a different purpose and has different pros and cons. It is often difficult to decide which container to use and …
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.

751 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