Solved

Send a struct over the network from C# app

Posted on 2004-09-02
16
371 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

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

Suggested Solutions

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
This article will show you some of the more useful Standard Template Library (STL) algorithms through the use of working examples.  You will learn about how these algorithms fit into the STL architecture, how they work with STL containers, and why t…
The goal of the tutorial is to teach the user how to use functions in C++. The video will cover how to define functions, how to call functions and how to create functions prototypes. Microsoft Visual C++ 2010 Express will be used as a text editor an…
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

756 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