Link to home
Start Free TrialLog in
Avatar of sternocera
sternocera

asked on

Developing or adapting a cross-platform tcp/ip protocol for transfering XML

I'm writing a program that needs to transfer accrued sales data from various slave nodes to a master node, over an ethernet LAN. The master application software is written in C++/MFC for Windows and the slaves application software is written in C++/Qtopia for Linux. I think that the most effective way of doing this is by accrueing a single day's sales data into a single XML file, transfering this XML file to the master, have the master parse this and store it in its database and then delete its local copy. The slave keeps its original XML file, should it be needed again.

My questions are:

1. Is my basic approach a sensible way of doing it? Convenience of implementation is important. I'm hoping to use someone else's nice Apache/BSD licenced API.

2. How should I transfer the XML file? Obviously, I favour something efficient, with a low-overhead. I don't like the look of SOAP. Using http as a "transport" protocol probably incurs an unnecessary overhead, and is aesthetically ugly. There has to be a better way. That said, we aren't talking about transfering very large files here, and they'll be transfered at full 100mb ethernet speed, so efficiency isn't an all-important consideration.
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Normally you would use XML to transfer between different applications. If you are responsible for both server and client you may consider to transfering binary structures which is much more efficient and fast.

I would use plain sockets for transfering which has the least overhead.

Regards, Alex
If transfering binary structures between Windows and Linux and back you have to consider alignment issues. Either put the struct members in order (double, float, int, short, char) so that each member begins and ends at a 32bit segment (maybe using fillers) or use preprocessor commands (platform dependent) to have the same alignment.

Avatar of sternocera
sternocera

ASKER

Alex,

Writing to a socket sounds complicated. I have no winsock/berkeley sockets experience. Surely there is a simpler solution, such as a cross-platform API?

If I was to use XML, what method of transfering the file would you recommend?

Thanks,
Sternocera
>>>> Writing to a socket sounds complicated.
Actually it isn't.

Assuming you have a socket connected you would write a struct passed like

   bool writeToSocket(MyStruct& st, SOCKET s)
   {
          if (!send(s, (char*)&st, sizeof(MyStruct))
               return false;
          return true;
   }

Reading is a little more difficult cause it would block if nothing is to read. You either set the socket to non-blocking and handle the error WSAEWOULDBLOCK (or EWOULDBLOCK at Linux).

   bool readFromSocket(MyStruct& st, SOCKET s, int timeout)
   {
         int noblock = timeout > 0? 1 : 0;
         ioctlsocket(s, FIONBIO, &noblock);  // set socket to blocking/no blocking
                                                                 // depending on timeout
         }
         int expired = 0;
         int bytesread = 0;
         while (expired <= timeout && bytesread <= sizeof(MyStruct))
         {
                 int rc = recv(s, ((char*)st) + bytesread, sizeof(MyStruct) - bytesread);
                 if (rc == SOCKET_ERROR)
                 {
                       if (GetLastError() == WSAEWOULDBLOCK)
                       {
                             int timeslice = timeout/10;
                             Sleep(timeslice);
                             expired += timeslice + 1;
                             continue;
                       }
                        // some other error
                        return false;
                 }
                 else if (rc > 0)
                 {
                        bytesread += rc;
                 }
         }
   }

In LINUX the part beginning with GetLastError is a little different:

                       if (errno == EWOULDBLOCK)
                       {
                             int timeslice = timeout/10;
                             sleep(timeslice);
                             expired += timeslice + 1;
                             continue;
                       }

Regards, Alex
Alex,

I'm looking at hessianCPP, but I'm not yet sure if that particular hessian implementation supports TCP transfers.

Writing to a raw socket is simple enough - I've done things like playing with netcat to get a webserver to process a HTTP GET and return html. However, creating a robust, functional protocol, with error handling, merely to transfer a fairly simple data structure seems like repetition of effort. I just know someone, somewhere has already done most of the work for me.

Another API that someone mentioned was JAXRPC, but thats Java only,

Thanks,
Sternocera
It turns out hessiancpp only supports the client side of the Caucho Hessian protocol. Therefore, back to the drawing board on that one.
ASKER CERTIFIED SOLUTION
Avatar of itsmeandnobodyelse
itsmeandnobodyelse
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Alex,

Interesting stuff. I think that whatever I do, I'll create a dedicated daemon to transfer the sales data that is seperate from my main application. It listens for connections. When it gets one, the client can be told the most recent xml file (they're named incremented numbers, as if from a db sequence). The client can also request an arbitrary specified XML file.  As it is part of an embedded application, this is acceptable. This approach is more modular then creating a new thread.

Perhaps you're right - a socket is the way to go. Thank you,
Sternocera
>>>> This approach is more modular then creating a new thread.
You may consider to creating a thread for each client connection or your server would need to both handling new clients and the communication to connected clients, e. g. like that


     while (true)     // run an infinite loop
     {
            if (readSelect(hostsock, 10) == 0)  // little timeout
            {
                   Client* pc = new Client;
                   pc->sock = accept(hostsock, ...);
                   clients.push_back(pc);
            }
            // loop all connected clients  
            for (int i = 0; i < clients.size(); ++i)
            {
                   Client* pc = clients[i];
                   if (readSelect(pc->sock, 10) == 0)  // little timeout
                   {
                          ReadMessage msg = { 0 };
                          int rc = readFromSocket(msg, sizeof(msg), pc->sock);
                          // maybe send an answer
                          // maybe delete client from list
                   }
            }
     }

if doing the second part in a own thread, the code will be more straight -forward.
I meant that it would be more sensible to create this as a seperate daemon, because it operates quite independently of my main application. This way, I can treat it as a seperate entity, which is logical and convenient,
Thanks