Reliable Desktop Communication - Sockets or Webservice

R

Rob

I have built a little wireless restaurant point of sale system that
has been in real use for the last 3 months ( written in c# ). There
are about 5 ppc's submiting orders to a desktop pc. My first attempt
at communications was written using sockets. The ppc would create a
new socket for each request. One would be to send the order. Then it
would create a new socket every few seconds and poll the desktop
server ( also written in c# ) to see if the order was ready. Things
didn't work that bad. I had a few issues with dynamic ip addresses
and hibernating and sometimes things didn't connect correctly but for
the most part there were not any issues. I recently noticed 2
alternatives. 1. is having the desktop serve out webservices and 2.
is a new messaging artical on msdn
http://www.msdn.microsoft.com/library/default.asp?url=/library/en-us/dncscol/html/csharp09182003.asp.
I noticed that #2, the messaging example, creates and maintains 1
connection to pass messages. Both of these alternatives seem to be
more robust than my current method. Are webservices from the desktop
going to be more reliable and easier for me since I don't care about
latency? Or is the messaging example a better option?

I have one last question that is a bit off subject and related to the
ip address on the desktop. Since I have control over the desktop, is
it advisable to give it a static ip so I don't run into issues with
the pocket pc's finding the server? I know nothing about networking
so this is probably a very stupid and basic question.

Thanks for any help,
Rob
 
S

Sinan

We have used web services in a similar project (but it was for stock
management type of thing), it works pretty well depending on the
complexity of the data you are sending and receiving. For simple
structures, or primitive types as parameters performance is pretty
good, but when exchanging DataSets it is extremely slow. As an example
a procedure that returns a data set that has three tables, total of 20
columns, and around 20 rows it takes about 8-9 seconds to get the data
set, our device had ARMV4 200MHz processor on it. And still you have
to poll the server, because it doesn't support a way to push data to
clients. I don't like polling, it is too much network traffic and
loss of CPU cycles, it might be okay on desktops but it becomes
significant on handhelds.

I read the MS article, since CF doesn't support serialization it has
to be done manually, and this document describes the classic way of
manually doing it. Two classic problems with this classic example is
version compatibility issues, and maintenance, whenever you add a
field or change type of a field, you need to apply this change to both
reader and writer. I don't think it would be too hard to implement a
simple solution with it but the bulk of the code will not be reusable.
In other words you have to manually serialize and deserialize all your
data for every new class. Also there is always connectivity issues
that you have to carefully code for, and the bugs in the whole
solution are relatively hard to detect, and fix.

If you are interested in an existing implementation, the company I'm
working for part-time is developing a robust/reusable solution for
pushing data from desktops/servers to WinCE/ppc clients. It really
simplifies implementation, but it is in beta stage yet, and it will be
in beta for at least another month. If you like to try, I can send you
a copy of it. But as I said it is only half of what you want to do,
this version only works from desktops to PPCs, but other solution,
accessing from PPCs to desktops is already implemented through
WebServices.

Sinan
 
R

Rob

Thank you for the reply. I think I am leaning towards using web
services instead of sockets because my messages aren't large and I
don't care about a few seconds delay. Are you hosting your
webservices without iis? If so, did you do it like this?

ChannelServices.RegisterChannel(new HttpChannel(9000));
RemotingConfiguration.ApplicationName =
"WSOrderProcessingRemotingService";
RemotingConfiguration.RegisterWellKnownServiceType(typeof(OrderProcessingService),
"RemServiceUri.soap",
WellKnownObjectMode.SingleCall);

public class OrderProcessingService : MarshalByRefObject
{
public OrderProcessingService()
{
//
// TODO: Add constructor logic here
//

}

public int AddOrder(String itemStr)
{
XmlSerializer mySerializer =
new XmlSerializer(typeof(ItemValue[]));
ItemValue[] items = (ItemValue[])
mySerializer.Deserialize(new StringReader(itemStr));

Form1 form = Form1.Form;
CarryoutOrderValue order = new CarryoutOrderValue();
order.itemViews = items;
order.name = "Kiosk";

return form.AddKioskOrder(order);
}

}

Does this solution scale well? Will multiple users be able to call
this service simultaneously without issues?

If so, this seems like a great simple solution to my problem.

Rob
 
S

Sinan

This more looks like Remoting than web services, and looks like it
using SOAP, as the transport protocol. Although web services is using
SOAP as the underlying protocol, there might be some differences
between the mappings of the client and the server. Give it a try if
you like but, using IIS it is a lot simpler. First of all on the
server you can declare some types or pass arbitrary arrays as
parameters.

Your AddOrder method would look like in the web service that is hosted
in IIS;

public int AddOrder(ItemValue[] value)
{
Form1 form = Form1.Form;
CarryoutOrderValue order = new CarryoutOrderValue();
order.itemViews = items;
order.name = "Kiosk";
return form.AddKioskOrder(order);
}

But since ItemValue is not a primitive type, when you add a references
to the WebReferences of the client project, Visual Studio will create
a proxy for this service and it will also create a place holder for
ItemValue class that has all of actual ItemValue class's public
properties and fields declared as fields in it. Client application has
to copy its ItemValue class into the ItemValue class that is declared
in the proxy. It is not very nice but that is the way it works. The
proxy that is generated by Visual Studio looks like;

namespace <yourserveraddress>.WebReference // you can change this name
in the wizard.
{
public class ItemValue
{
public <first field>;
public <second field>;
public <others>;
}

public int Add(ItemValue[] values)
{
// some code that marshalls the parameters and unmarshalls
returned values.
}
}

When you construct this proxy you can set its Url to the servers url
and call this method, but obviously you need to pass instances of
ItemValue classes that is declared in this namespace.

I don't have any experience in web services, the way you are planning
to use so I can't tell if it looks good or not.

Sinan
Thank you for the reply. I think I am leaning towards using web
services instead of sockets because my messages aren't large and I
don't care about a few seconds delay. Are you hosting your
webservices without iis? If so, did you do it like this?

ChannelServices.RegisterChannel(new HttpChannel(9000));
RemotingConfiguration.ApplicationName =
"WSOrderProcessingRemotingService";
RemotingConfiguration.RegisterWellKnownServiceType(typeof(OrderProcessingService),
"RemServiceUri.soap",
WellKnownObjectMode.SingleCall);

public class OrderProcessingService : MarshalByRefObject
{
public OrderProcessingService()
{
//
// TODO: Add constructor logic here
//

}

public int AddOrder(String itemStr)
{
XmlSerializer mySerializer =
new XmlSerializer(typeof(ItemValue[]));
ItemValue[] items = (ItemValue[])
mySerializer.Deserialize(new StringReader(itemStr));

Form1 form = Form1.Form;
CarryoutOrderValue order = new CarryoutOrderValue();
order.itemViews = items;
order.name = "Kiosk";

return form.AddKioskOrder(order);
}

}

Does this solution scale well? Will multiple users be able to call
this service simultaneously without issues?

If so, this seems like a great simple solution to my problem.

Rob

We have used web services in a similar project (but it was for stock
management type of thing), it works pretty well depending on the
complexity of the data you are sending and receiving. For simple
structures, or primitive types as parameters performance is pretty
good, but when exchanging DataSets it is extremely slow. As an example
a procedure that returns a data set that has three tables, total of 20
columns, and around 20 rows it takes about 8-9 seconds to get the data
set, our device had ARMV4 200MHz processor on it. And still you have
to poll the server, because it doesn't support a way to push data to
clients. I don't like polling, it is too much network traffic and
loss of CPU cycles, it might be okay on desktops but it becomes
significant on handhelds.

I read the MS article, since CF doesn't support serialization it has
to be done manually, and this document describes the classic way of
manually doing it. Two classic problems with this classic example is
version compatibility issues, and maintenance, whenever you add a
field or change type of a field, you need to apply this change to both
reader and writer. I don't think it would be too hard to implement a
simple solution with it but the bulk of the code will not be reusable.
In other words you have to manually serialize and deserialize all your
data for every new class. Also there is always connectivity issues
that you have to carefully code for, and the bugs in the whole
solution are relatively hard to detect, and fix.

If you are interested in an existing implementation, the company I'm
working for part-time is developing a robust/reusable solution for
pushing data from desktops/servers to WinCE/ppc clients. It really
simplifies implementation, but it is in beta stage yet, and it will be
in beta for at least another month. If you like to try, I can send you
a copy of it. But as I said it is only half of what you want to do,
this version only works from desktops to PPCs, but other solution,
accessing from PPCs to desktops is already implemented through
WebServices.

Sinan
 
R

Rob

Hey Sinan,

When I set it up the way I am doing it, I am able to add the web
reference to the client just like any other webservice. It creates a
proxy just like you describe and there haven't been any problems
sending with just one client. My only problem is that I don't know
how it is going to behave when there are multiple clients connecting
at the same time and also polling every so many seconds. I guess I
will just have to give it a try. My issue with using iis is that I
may not always have it.

Thanks,
Rob

This more looks like Remoting than web services, and looks like it
using SOAP, as the transport protocol. Although web services is using
SOAP as the underlying protocol, there might be some differences
between the mappings of the client and the server. Give it a try if
you like but, using IIS it is a lot simpler. First of all on the
server you can declare some types or pass arbitrary arrays as
parameters.

Your AddOrder method would look like in the web service that is hosted
in IIS;

public int AddOrder(ItemValue[] value)
{
Form1 form = Form1.Form;
CarryoutOrderValue order = new CarryoutOrderValue();
order.itemViews = items;
order.name = "Kiosk";
return form.AddKioskOrder(order);
}

But since ItemValue is not a primitive type, when you add a references
to the WebReferences of the client project, Visual Studio will create
a proxy for this service and it will also create a place holder for
ItemValue class that has all of actual ItemValue class's public
properties and fields declared as fields in it. Client application has
to copy its ItemValue class into the ItemValue class that is declared
in the proxy. It is not very nice but that is the way it works. The
proxy that is generated by Visual Studio looks like;

namespace <yourserveraddress>.WebReference // you can change this name
in the wizard.
{
public class ItemValue
{
public <first field>;
public <second field>;
public <others>;
}

public int Add(ItemValue[] values)
{
// some code that marshalls the parameters and unmarshalls
returned values.
}
}

When you construct this proxy you can set its Url to the servers url
and call this method, but obviously you need to pass instances of
ItemValue classes that is declared in this namespace.

I don't have any experience in web services, the way you are planning
to use so I can't tell if it looks good or not.

Sinan
Thank you for the reply. I think I am leaning towards using web
services instead of sockets because my messages aren't large and I
don't care about a few seconds delay. Are you hosting your
webservices without iis? If so, did you do it like this?

ChannelServices.RegisterChannel(new HttpChannel(9000));
RemotingConfiguration.ApplicationName =
"WSOrderProcessingRemotingService";
RemotingConfiguration.RegisterWellKnownServiceType(typeof(OrderProcessingService),
"RemServiceUri.soap",
WellKnownObjectMode.SingleCall);

public class OrderProcessingService : MarshalByRefObject
{
public OrderProcessingService()
{
//
// TODO: Add constructor logic here
//

}

public int AddOrder(String itemStr)
{
XmlSerializer mySerializer =
new XmlSerializer(typeof(ItemValue[]));
ItemValue[] items = (ItemValue[])
mySerializer.Deserialize(new StringReader(itemStr));

Form1 form = Form1.Form;
CarryoutOrderValue order = new CarryoutOrderValue();
order.itemViews = items;
order.name = "Kiosk";

return form.AddKioskOrder(order);
}
}

Does this solution scale well? Will multiple users be able to call
this service simultaneously without issues?

If so, this seems like a great simple solution to my problem.

Rob
 
S

Sinan

In IIS it is creating a new instance of the server class for each
connection. And there is no way of storing session state on the server
for the client other then using SoapHeaders. You can setup the web
methods to exchange a SoapHeader for each call, and actually that is
the way we are keeping the session id of each client, we are using
this id to associate the client with the information we are storing in
the database for it. With remoting you have better control on lifetime
management, but I don't know how well it works with a none remoting
client. If you are sharing the server object between clients, then
there will be concurrency issues that you have to take care of, i.e.
you may not be able to use same database connection for two clients at
the same time, but if you are pooling them then you'll be fine. Other
then concurrency problems so far with IIS it worked pretty good upto
100 concurrent clients.

Anyway good luck.
Sinan
 
R

Rob

Yesterday I rewrote all of my socket communications with the above
code ( remoting with soap ). It was so simple! Because my server
runs in a windows forms client, it was easiest to just start up a
remoting server. I ran some initial tests with multiple threads
accessing the services and it works great! My old socket code was
bulky and difficult to manage. Now I only have a few lines for each
message. I love it. It is a little bit slower but I don't really
care if it takes a couple seconds longer for the message to arrive.

Rob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top