Pocket PC Networking >> Asynchronous Networking through Socket: deadlock?

by UnViZW4gVmFuIEhhdmVybWFldA » Tue, 10 May 2005 22:52:11 GMT

Dear Group,

My name is Ruben Van Havermaet. I am trying to finish a project in C#
involving pda's and a desktop server. I am using Microsoft Visual .NET 2003
and a pda with Windows Mobile 2003 Second Edition Version 4.21.1088 (Build
14260.2.0.5)

Here comes the problem:


Given Class ClientCommunicator (which sends notifications to listeners on
events of connected, data sent, data received, etc)

In my case there is one listening class RunningWaiter, which catches
these notifications. When the "data is received"-notification is
caught, the data sent with it is parsed and new notifications are sent
upward to other listeners. (these notifications are in fact the
different commands that a server can send and that the pda can respond
to.)

For these notifications there are two listeners: the class MainForm
(which owns the GUI) and a class MenuKaart.

So we have something like:

ClientCommunicator <-> RunningWaiter <-> {MainForm | MenuKaart}


My problem is, while dealing with these last notifications, when the
user touches the main GUI, the program hangs.

Thanks in advance,
Ruben.

PS Here is the Code:

// CLASS CLIENTCOMMUNICATOR

namespace PocketWaiter.Communication
{

public enum NotifyCommand
{
Connected,
Disconnected,
SentData,
ReceivedData,
Error
}

public delegate void NetNotifEventHandler(object o, NetNotifEventArgs a);

public class NetNotifEventArgs : EventArgs
{
public string _data;
public NotifyCommand _cmd;

public NetNotifEventArgs(NotifyCommand c, string d)
{
_data = d;
_cmd = c;
}
}


/// <summary>
/// Summary description for ClientCommunicator.
/// </summary>
public class ClientCommunicator
{

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * MEMBER VARIABLES
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// Notification Event
public event NetNotifEventHandler NetNotif;

// Socket that exchanges information with the server
Socket _socket;

bool _disconnecting = false;

// Received data in buffer
private ServerCommandBuffer _buffer;
public string Buffer
{
get
{
return _buffer.nextCommand();
}
}

// Represents a packet that is sent to the server
public class SocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] dataBuffer = new byte[Global.Const.MaxBufferLength];

// Get the data in string format. The size parameter determines the
// number of relevant bytes.
public string StringData(int size)
{
return ASCIIEncoding.ASCII.GetString(dataBuffer,0,size);
}
}

// async callbacks
AsyncCallback _connectCallback;
AsyncCallback _sendCallback;
AsyncCallback _receiveCallback;



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * PROPERTIES
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

/// <summary>
/// Returns true if the socket is connected to the server. The property
/// Socket.Connected does not always indicate if the socket is currently
/// connected. This polls the socket to determine the latest connection
state.
/// </summary>
public bool Connected
{
get
{
// return right away if no socket was created
if (_socket == null)
return false;
// the socket is not connected if the Connected property is false
if (!_socket.Connected)
return false;

// there is no guarantee that the socket is connected even if the
// Connected property is true
try
{
// poll for error to see if socket is connected
return !_socket.Poll(1,SelectMode.SelectError);
}
catch
{
return false;
}
}
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * CONSTRUCTORS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

public ClientCommunicator()
{
// hookup async callback methods
_connectCallback = new AsyncCallback(connectCallback);
_sendCallback = new AsyncCallback(sendCallback);
_receiveCallback = new AsyncCallback(receiveCallback);

_buffer = new ServerCommandBuffer();
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * PUBLIC MEMBER FUNCTIONS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

/// <summary>
/// Connect to the specified address and port number.
/// </summary>
public void connect(string address, int port)
{
try
{
// make sure the existing connection is closed
disconnect();

// Connect to the server
IPAddress ipAddress = IPAddress.Parse(address);
IPEndPoint endPoint = new IPEndPoint(ipAddress, port);
_socket = new Socket( AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);

_socket.BeginConnect(endPoint, _connectCallback, null);
}
catch (Exception ex)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,"CONNECT: " +
ex.Message));
}
}


/// <summary>
/// Disconnect from the server.
/// </summary>
public void disconnect()
{
// return right away if no socket was created
if (_socket == null)
return;

// set this flag so we don't raise any error notification
// event when disconnecting
_disconnecting = true;

try // shutdown the socket
{
_socket.Shutdown(SocketShutdown.Both);
}
catch {}

try // close socket; terminates any pending async operations
{
_socket.Close();
}
catch {}

_socket = null;
_disconnecting = false;

OnNetNotif(new NetNotifEventArgs(NotifyCommand.Disconnected, null));
}



/// <summary>
/// Send data to the server.
/// </summary>
public void send(string data)
{
try
{
SocketPacket s = new SocketPacket();
s.thisSocket = _socket;

// Convert the message to a byte array
s.dataBuffer = System.Text.Encoding.ASCII.GetBytes(data);

// Send the data asychronously
s.thisSocket.BeginSend(s.dataBuffer, 0, data.Length,
SocketFlags.None, _sendCallback, s);
}
catch (SocketException se)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,
"SEND: " + se.Message + "(" + se.ErrorCode + ")"));
}
catch (Exception ex)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,
"SEND: " + ex.Message));
}
}


/// <summary>
/// This function sends the data synchronously
/// </summary>
public void sendNow(string data)
{
try
{
NetworkStream networkStream = new NetworkStream(_socket);

System.IO.StreamWriter streamWriter = new
System.IO.StreamWriter(networkStream);

streamWriter.WriteLine(data);
streamWriter.Flush();
}
catch (SocketException se)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,
"SENDNOW: " + se.Message + "(" + se.ErrorCode + ")"));
}
catch (Exception ex)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,
"SENDNOW: " + ex.Message));
}
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * PRIVATE MEMBER FUNCTIONS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

/// <summary>
/// Read data from server.
/// </summary>
public void waitReceive()
{
if (_socket.Connected)
{
try
{
SocketPacket sPacket = new SocketPacket();
sPacket.thisSocket = _socket;

_asyncStatus = _socket.BeginReceive (sPacket.dataBuffer,
0, sPacket.dataBuffer.Length,
SocketFlags.None,
_receiveCallback,
sPacket);
}
catch(SocketException se)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,"WAITRECEIVE: " +
se.Message));
}
}
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * NOTIFY EVENTS - which are send a level up
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

/// <summary>
/// Raise Notification event
/// </summary>
protected virtual void OnNetNotif(NetNotifEventArgs args)
{
// if there was an error: disconnect the socket
if (args._cmd == NotifyCommand.Error)
{
disconnect();
}

// don't raise notificaton events when disconnecting
if ((this.NetNotif != null) && !_disconnecting)
NetNotif(this, args);
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * CALLBACKS - which you get back from a level down
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

private void connectCallback(IAsyncResult ar)
{
try
{
_socket.EndConnect(ar);

// Send hostname
string hostname = Dns.GetHostName();
byte[] hostBuffer = System.Text.Encoding.ASCII.GetBytes(hostname);
_socket.Send(hostBuffer,0,hostBuffer.Length,SocketFlags.None);

// Pass remote ip address with notification event.
string ip = ((IPEndPoint)this._socket.RemoteEndPoint).Address.ToString();
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Connected, ip));

// Start listening for server's messages asynchronously
waitReceive();
}
catch (Exception ex)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,"CLB_CONNECT: " +
ex.Message));
}
}

private void sendCallback(IAsyncResult ar)
{
SocketPacket s = null;
try
{
s = (SocketPacket)ar.AsyncState;

// End the asynchronous send
int size = _socket.EndSend(ar);

// Raise a sent event
OnNetNotif(new
NetNotifEventArgs(NotifyCommand.SentData,s.StringData(size)));
}
catch (SocketException se)
{
OnNetNotif(
new NetNotifEventArgs(NotifyCommand.Error,
"CLB_SENT_DATA: " + se.Message + "(" + se.ErrorCode + ")"));
}
catch(Exception se)
{
OnNetNotif(
new NetNotifEventArgs(NotifyCommand.Error,
"CLB_SENT_DATA: " + se.Message));
}
}


private void receiveCallback(IAsyncResult ar)
{
SocketPacket s = (SocketPacket)ar.AsyncState;

if (s.thisSocket.Connected)
{
try
{
// Mark received and get the size of the packet
int size = s.thisSocket.EndReceive(ar);

// The serversocket is disconnected
if (size < 1)
{
disconnect();
return;
}

// Save the byte array into a string
string data = s.StringData(size);

// Add data to the receivedBuffer
_buffer.addCommand(data);

// Notify any listeners that some data was received
OnNetNotif(new NetNotifEventArgs(NotifyCommand.ReceivedData, data));

// Wait for new data
waitReceive();
}
catch (SocketException se)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,
"CLB_RECEIVE: " + se.Message + "(" + se.ErrorCode + ")"));
}
catch (Exception ex)
{
OnNetNotif(new NetNotifEventArgs(NotifyCommand.Error,
"CLB_RECEIVE: " + ex.Message));
}
}
}

} // End Class ClientCommunicator

} // Close Namespace Communication



// CLASS MENUKAART
namespace PocketWaiter.Menu
{

/// <summary>
/// Summary description for MenuKaart.
/// </summary>
public class MenuKaart
{

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * MEMBER VARIABLES
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// The Running Waiter to listen to
RunningWaiter _runningWaiter;

// The list of groups inside this MenuKaart
Groups _groups;

// The list of articles inside this MenuKaart
// Articles _articles



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * CONSTRUCTOR
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

public MenuKaart(RunningWaiter runningWaiter)
{
_runningWaiter = runningWaiter;
_runningWaiter.ServerCommandNotif += new
ServerCommandNotifEventHandler(onServerCommandNotif);

_groups = new Groups(Global.Const.AutoWriteMenu);
//_articles = new Articles(Global.Const.AutoWriteMenu);
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * PUBLIC MEMBER FUNCTIONS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// TODO: as above we should consider what functionality this MenuKaart
// class should implement.
public Group getGroupByID(short id)
{
return _groups.getGroup(id);
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * CALLBACK-RELATED - which you get back from a level down
// * (RunningWaiter in this case)
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

private void onServerCommandNotif(
object sender, ServerCommandNotifEventArgs args)
{
try
{
lock (this)
{
switch (args._cmd.ID)
{
case ServerCommandID.CreateGroup:
processCreateGroup(
((CreateGroupServerCommand)args._cmd).Group);
break;

case ServerCommandID.DeleteGroup:
processDeleteGroup(
((DeleteGroupServerCommand)args._cmd).GroupID);
break;

case ServerCommandID.DeleteAllGroups:
processDeleteAllGroups();
break;
}
}
}
catch {}
}


// This function specifies the course of action when the RunningWaiter
// notifies that a group needs to be created or updated.
private void processCreateGroup(Group grp)
{
bool added = _groups.addGroup(grp);

if (added)
Logger.log(this, "Added Group " + grp.ID + ".");
else
Logger.log(this, "Updated Group (NYI) " + grp.ID + ".");
}


// This function specifies the course of action when the RunningWaiter
// signals a DeleteGroup command
private void processDeleteGroup(short id)
{
bool removed = _groups.removeGroup(id);

if (removed)
Logger.log(this, "Removed Group " + id + ".");
else
Logger.log(this, "NotFound Group " + id + ".");
}


// This function defines the actions to be taken when the RunningWaiter
// signals a DeleteAllGroups command
private void processDeleteAllGroups()
{
_groups.clearGroups();

Logger.log(this, "Removed all Groups.");
}
}
}



// CLASS MAINFORM
namespace PocketWaiter
{
/// <summary>
/// TODO: Summary description for MainForm.
/// </summary>
public class MainForm : System.Windows.Forms.Form, ILogArea
{

// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * MEMBER VARIABLES
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// The communication object
ClientCommunicator _client = new ClientCommunicator();

// The Running Waiter, responsible for processing requests made
// by the server and the client program.
RunningWaiter _runningWaiter;

// The Menu
MenuKaart _menu;

// Handle commands from the server
EventHandler _processServerCommandNotif;

// Hold RunningWaiter command arguments
ServerCommand _serverCommand;

// Windows Components
private System.Windows.Forms.TextBox _mainTxtOutput;
private System.Windows.Forms.MainMenu _mainMenu;
private System.Windows.Forms.MenuItem _menuItemSetup;
private ConnectButton _btnConnect;
private System.Windows.Forms.Button _btnFollowTable;
private System.Windows.Forms.Button _btnOrder;
private System.Windows.Forms.Button _btnShowTable;
private System.Windows.Forms.Button _btnLeeg1;
private System.Windows.Forms.Button _btnMessage;
private System.Windows.Forms.Button _btnMoveTable;
private System.Windows.Forms.MenuItem _menuItemExit;


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * CONSTRUCTOR, MAIN, WINDOWS FORM DESIGNER GENERATED *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
public MainForm()
{
_runningWaiter = new RunningWaiter(_client);
_menu = new MenuKaart(_runningWaiter);

this._btnConnect = new ConnectButton(_client);
this._btnConnect.Location = new System.Drawing.Point(192, 184);
this._btnConnect.Size = new System.Drawing.Size(40, 80);
this.Controls.Add(this._btnConnect);

// Install callback for servercommands
_runningWaiter.ServerCommandNotif +=
new ServerCommandNotifEventHandler(onServerCommandNotif);
_processServerCommandNotif = new EventHandler(processServerCommandNotif);

InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}

#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this._menuItemSetup = new System.Windows.Forms.MenuItem();
this._menuItemExit = new System.Windows.Forms.MenuItem();
this._mainMenu = new System.Windows.Forms.MainMenu();
this._mainTxtOutput = new System.Windows.Forms.TextBox();
this._btnFollowTable = new System.Windows.Forms.Button();
this._btnOrder = new System.Windows.Forms.Button();
this._btnShowTable = new System.Windows.Forms.Button();
this._btnLeeg1 = new System.Windows.Forms.Button();
this._btnMessage = new System.Windows.Forms.Button();
this._btnMoveTable = new System.Windows.Forms.Button();
//
// _menuItemSetup
//
this._menuItemSetup.Text = "Setup";
this._menuItemSetup.Click += new
System.EventHandler(this.menuItemSetup_Click);
//
// _menuItemExit
//
this._menuItemExit.Text = "Exit";
this._menuItemExit.Click += new
System.EventHandler(this.menuItemExit_Click);
//
// _mainMenu
//
this._mainMenu.MenuItems.Add(this._menuItemSetup);
this._mainMenu.MenuItems.Add(this._menuItemExit);
//
// _mainTxtOutput
//
this._mainTxtOutput.AcceptsReturn = true;
this._mainTxtOutput.AcceptsTab = true;
this._mainTxtOutput.Font = new System.Drawing.Font("Microsoft Sans
Serif", 9F, System.Drawing.FontStyle.Regular);
this._mainTxtOutput.Location = new System.Drawing.Point(8, 88);
this._mainTxtOutput.Multiline = true;
this._mainTxtOutput.ReadOnly = true;
this._mainTxtOutput.ScrollBars = System.Windows.Forms.ScrollBars.Both;
this._mainTxtOutput.Size = new System.Drawing.Size(176, 176);
this._mainTxtOutput.Text = "PocketWaiter v0.1\r\n";
//
// _btnFollowTable
//
this._btnFollowTable.Font = new System.Drawing.Font("Microsoft Sans
Serif", 14.25F, System.Drawing.FontStyle.Regular);
this._btnFollowTable.Location = new System.Drawing.Point(128, 32);
this._btnFollowTable.Size = new System.Drawing.Size(104, 24);
this._btnFollowTable.Text = "Tafel Mag\r\nVolgen";
this._btnFollowTable.Click += new
System.EventHandler(this._btnFollowTable_Click);
//
// _btnOrder
//
this._btnOrder.Font = new System.Drawing.Font("Microsoft Sans Serif",
14.25F, System.Drawing.FontStyle.Regular);
this._btnOrder.Location = new System.Drawing.Point(8, 8);
this._btnOrder.Size = new System.Drawing.Size(104, 24);
this._btnOrder.Text = "Begin\r\nBestelling";
this._btnOrder.Click += new System.EventHandler(this._btnOrder_Click);
//
// _btnShowTable
//
this._btnShowTable.Font = new System.Drawing.Font("Microsoft Sans Serif",
14.25F, System.Drawing.FontStyle.Regular);
this._btnShowTable.Location = new System.Drawing.Point(8, 56);
this._btnShowTable.Size = new System.Drawing.Size(104, 24);
this._btnShowTable.Text = "Save";
this._btnShowTable.Click += new
System.EventHandler(this._btnShowTable_Click);
//
// _btnLeeg1
//
this._btnLeeg1.Font = new System.Drawing.Font("Microsoft Sans Serif",
14.25F, System.Drawing.FontStyle.Regular);
this._btnLeeg1.Location = new System.Drawing.Point(128, 56);
this._btnLeeg1.Size = new System.Drawing.Size(104, 24);
this._btnLeeg1.Text = "Groups";
this._btnLeeg1.Click += new System.EventHandler(this._btnLeeg1_Click);
//
// _btnMessage
//
this._btnMessage.Font = new System.Drawing.Font("Microsoft Sans Serif",
14.25F, System.Drawing.FontStyle.Regular);
this._btnMessage.Location = new System.Drawing.Point(128, 8);
this._btnMessage.Size = new System.Drawing.Size(104, 24);
this._btnMessage.Text = "Stuur\r\nBericht";
this._btnMessage.Click += new System.EventHandler(this._btnMessage_Click);
//
// _btnMoveTable
//
this._btnMoveTable.Font = new System.Drawing.Font("Microsoft Sans Serif",
14.25F, System.Drawing.FontStyle.Regular);
this._btnMoveTable.Location = new System.Drawing.Point(8, 32);
this._btnMoveTable.Size = new System.Drawing.Size(104, 24);
this._btnMoveTable.Text = "Verplaats\r\nTafel";
this._btnMoveTable.Click += new
System.EventHandler(this._btnMoveTable_Click);
//
// MainForm
//
this.Controls.Add(this._btnMoveTable);
this.Controls.Add(this._btnMessage);
this.Controls.Add(this._btnLeeg1);
this.Controls.Add(this._btnShowTable);
this.Controls.Add(this._btnOrder);
this.Controls.Add(this._btnFollowTable);
this.Controls.Add(this._mainTxtOutput);
this.Menu = this._mainMenu;
this.Text = "PocketWaiter";
this.Closing += new
System.ComponentModel.CancelEventHandler(this.MainForm_Closing);
this.Load += new System.EventHandler(this.MainForm_Load);
this.MouseDown += new MouseEventHandler(MainForm_MouseDown);

}
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
Application.Run(new MainForm());
}


// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * EVENTS *
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

private void MainForm_Load(object sender, System.EventArgs e)
{
// Register MainForm as a logArea
Logger.register(this);
}

private void MainForm_Closing(object sender,
System.ComponentModel.CancelEventArgs e)
{
this.quit();
}


// * BUTTONS * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
private void _btnOrder_Click(object sender, System.EventArgs e)
{
}

private void _btnMoveTable_Click(object sender, System.EventArgs e)
{
MoveTableForm form = new MoveTableForm();
form.ShowDialog();

_runningWaiter.moveTable(form.FromTable, form.ToTable);
}

private void _btnShowTable_Click(object sender, System.EventArgs e)
{
}

private void _btnMessage_Click(object sender, System.EventArgs e)
{
NumericInputForm form =
new NumericInputForm(false, "Enter GroupID:", false);
form.ShowDialog();

if (form.InputGiven)
{
Group grp = _menu.getGroupByID((short)form.NumberInput);

if (grp != null)
_runningWaiter.sendString(grp.ToString());
else
_runningWaiter.sendString("GROUPID does not exist");
}
}

private void _btnFollowTable_Click(object sender, System.EventArgs e)
{
}

private void _btnLeeg1_Click(object sender, System.EventArgs e)
{
_menu.showGroups();
}


// * MENU ITEMS * * * * * * * * * * * * * * * * * * * * * * * * * * *
private void menuItemSetup_Click(
object sender, System.EventArgs e)
{
showSetupForm();
}

private void menuItemExit_Click(object sender, System.EventArgs e)
{
this.quit();
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * PRIVATE MEMBER FUNCTIONS
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

// This function makes MainForm implement the ILogArea interface
public void log(Object o, string msg)
{
if ((_mainTxtOutput.Text.Length + msg.Length)
> _mainTxtOutput.MaxLength)
_mainTxtOutput.Text = "";

_mainTxtOutput.Text = Thread.CurrentThread.GetHashCode()+ ">" + msg +
"\r\n" + _mainTxtOutput.Text;
}

// QUIT the program
private void quit()
{
disconnectFromServer();
Application.Exit();
}

// Disconnect from server
private void disconnectFromServer()
{
if (_client.Connected)
{
Logger.log(this,"Disconnecting");
_client.disconnect();
}
}


// Show Test form
private void showSetupForm()
{
//SetupForm form = new SetupForm();

//form.ShowDialog();
}

// This function shows a numerical input form, requesting the user
// to enter the waiterNumber.
private void showWaiterNumberForm()
{
NumericInputForm form = new
NumericInputForm(false, "Waiter Number?", false);
form.ShowDialog();

Logger.log(this, "WAITER NUMBER = " + form.NumberInput.ToString());
_runningWaiter.sendWaiterNumber(form.NumberInput);
}

// This function shows a numerical input form, requesting the user
// to enter the waiter password.
private void showWaiterPassForm()
{
NumericInputForm form =
new NumericInputForm(true, "Waiter Password?", false);
form.ShowDialog();

Logger.log(this, "WAITER PASS = " + form.NumberInput.ToString());
_runningWaiter.sendWaiterPassword(form.NumberInput);
}



// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
// * CALLBACK-RELATED - which you get back from a level down
// * and how to respond!
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

private void onServerCommandNotif(object sender,
ServerCommandNotifEventArgs args)
{
try
{
// The .NET Compact Framework does not support Control.Invoke
// with which you can pass arguments to the delegate. So save
// arguments to class fields and then invoke the delegate.
lock (this)
{
_serverCommand = args._cmd;

Invoke(_processServerCommandNotif);
}
}
catch (Exception ex)
{
Logger.log(this, "MAINFORM ERROR: " + ex.Message);
}
}

private void processServerCommandNotif(Object sender, EventArgs args)
{
switch(_serverCommand.ID)
{
case ServerCommandID.GetWaiterNumber:
showWaiterNumberForm();
break;
case ServerCommandID.GetWaiterPassword:
showWaiterPassForm();
break;
case ServerCommandID.SetWaiterName:
break;
}
}

private void MainForm_MouseDown(object sender, MouseEventArgs e)
{
Logger.log(this, "TESTING MOUSEDOWN");
}
}
}



Pocket PC Networking >> Asynchronous Networking through Socket: deadlock?

by Stelrad Doulton » Thu, 02 Jun 2005 01:01:06 GMT


noticed you are on the Compact Framework. What service pack are you on??

"Ruben Van Havermaet" <Ruben Van XXXX@XXXXX.COM > wrote
in message news: XXXX@XXXXX.COM ...





Pocket PC Networking >> Asynchronous Networking through Socket: deadlock?

by Kerstin Pirrung » Thu, 02 Jun 2005 17:59:03 GMT

don't know if that is of any help to you, but I 've just dealt with a
similar deadlock problem on the very same PDA Build.

Data transfer actually is an asyncronous operation, and the "data is
received"-notification responding to a socket "OK" came a little too
early. My application tried to access said data, and this resulted in a
deadlock. On older PDAs it did work just fine, but obviously the newer
ones are a little too fast for the network.

Kerstin

"Stelrad Doulton" < XXXX@XXXXX.COM > wrote in
news: XXXX@XXXXX.COM :




Similar Threads

1. Socket and NAT-Router, Asynchronous socket error

2. Sockets causing deadlock

Has anyone seen something like this, and/or found a solution?
I have an application that uses many sockets, at least 30, each having its 
own thread to handle processing. They all try to connect at once. Normally, 
there are no problems. What I have found, however, is that if the connection 
fails, I get a deadlock situation resulting from multiple sockets in various 
threads calling connect() and closesocket() at the same time. If I put a 
critical section around these calls it fixes the problem, but it isn't 
feasible solution because the connects need to happen simultaneously, not 
serially. The sockets are bound to separate ports, so there are no reused 
socket issues. I don't even do any sends or receives in my test program, 
just connection attempts.

Here is the basic algorithm for each thread:

Loop:
    Create a new socket
    Make it nonblocking.
    Call connect()
    (Wait for the failed attempt)
    Call shutdown()
    Call closesocket()

More info:
I see the worst problem on Windows 2000. Here, I get a complete deadlock - 
all threads are suspended in system calls, usually either a sockets call 
(i.e. connect()) or a SleepEx() call.
On Windows XP, I don't get suspended threads, but the most sockets threads 
hang. The UI thread is usually ok.
The development platform is MSVC++ 6.0.

I have done everything I can think of. Does anyone have any ideas? 


3. Voice and Webcam through asynchronous sockets

4. asynchronous socket I/O call which returns immediately without WSA_IO_PENDING

Does the issuing asynchronous call such as WSARecv or WSASend set the signal 
even if the call returns immediately just after the completion? That's to 
say, for example, does overlapped function call of WSARecv returns zero 
instead of WSA_IO_PENDING via GetLastError also sets the signal which can be 
sensed by WaitForSingleObject or GetQueuedCompletionStatus? I've been 
writing bulletproof code regardless of this behavior so I don't know the 
answer yet. :)

Please reply. Thanks in advance.

Hyun-jik Bae 


5. Asynchronous UDP Sockets ~ No Read events!

6. Asynchronous sockets

Hi gurus

I am porting a PC application to CE-5, and noticed that WSAAsyncSelect 
ofcause isnt provided.
I need to use SOCK_STREAM on TCP, and I dont know the size of the incomming 
message.

Can anyone please confirm that the following approack sounds correct ?

1)
I need to create a new thread for receiving data
2)
As I dont know the size of the message, I basicly need to receive 1 BYTE at 
a time

something like

;-----------------------
; execute thread

BYTE bData;

do {
    if ( recv( Socket, &bData, 1, 0 ) == 1 ) {
        // manually add bData to my internal buffer structure etc etc

    }
} while ( FOREVER );
;-----------------------


Thanks for any thoughts on this

Lars


 


7. Article: Using epoll() For Asynchronous Network Programming

8. Asynchronous vs Synchronous network communication

Hi,
I am a tad confused about if there are any benefits from using
asynchronous vs synchronous network communication.
As my example, I have been writing a dns lookup stack with a network
communication class switchable between asynchronous and synchronous.
When I use asynchronous udp communication I find that if I want to
process a large amount of dns lookups I have one dns provider with
many state objects passing through (and a high object churn rate).  If
I use synchronous udp communication I don't need state objects, but
have many providers each in a thread (although these providers are
static and so there is low churn).
It seems to me that both methods amount to the same result other than
the fact that using asynchronous communication results in a higher
object churn rate (leading to higher memory usage).
Can anybody clarify whether there really is an advantage in using one
over the other?

My second question is a bit of a throwaway.  Using whatever network
communication, what kind of techniques exist to throttle something
like this based on available bandwidth?

Thanks,
Noel