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
Solved

Send a struct over the network from C# app

Posted on 2004-09-02
16
369 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
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

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.

 
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

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

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

Errors will happen. It is a fact of life for the programmer. How and when errors are detected have a great impact on quality and cost of a product. It is better to detect errors at compile time, when possible and practical. Errors that make their wa…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
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 goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…

828 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