Problem with socket communication for client (On handheld) / server (on PC) application

Hi all,

I have tried posting this message in a couple of different places, and have not gotten much of a response. It is really important that this is resolved for a client of ours, and I've rarely come across a problem I've had to post on a forum to resolve, so please help if you can.

I have a client application running on a windows ce .net device, and a
server application running on a PC. I have been experiencing problems
with the tcp connection dropping (ObjectDisposedException for the
NetworkStream) and so I have tried to cut the applications down to
their minimal details, so that I can post them and ask for your opinion
on the problem.

The client sends commands to the server, and the server sends a
response. The tcp connection is opened at the start of the
communication, and is kept open between commands - i.e. a new
connection is not opened each time a command is to be sent.

I have now configured the client, when the button on the main form is
clicked, to send a command (just a longish string) to the server. When
the server receives a command, it sends the response (just another
arbitrary string in this example). I have used a loop on the client
side to send the same command up to 500 times. At about iteration 70, I
get an ObjectDisposedException, and the server reports that the
connection was closed on the client side.

Now an error occurring every 70 times may not seem that often, but in
the real application, I am scanning a barcode, and on the basis of
that, running stored procedures on the server, and the amount of data
going back and forth is more than in this example. I am getting an
error every second scan or so, which is definitely not acceptable. I
am assuming that if I can solve the problem in this simple example
application, then the (hopefully exact same) problem in my actual
application will also be solved.

The exceptions happen both when the client handheld is connected to the
PC via activesync, and the local lan ip is used to connect to the
server, OR if the client handheld is connected via a wireless lan
access point when NOT connected via activesync. Sometimes an
IOException occurs instead of the ObjectDisposedException. But an
exception occurs without fail, after some iteration of the loop.

The same happens when using the emulator.

An important point is if I make a PC client application, using the same
code as the handheld client application, is successfully sends and
receives the 500 commands and responses, whereas the handheld and
emulator only make it to about 70. The code is below, I'd appreciate
any help, I have no idea why this is happening!

I thought that maybe it would have something to do with a memory problem, but I'm not sure if this is the case. I have tried running GC.Collect() after each iteration, but this just makes the exception happen immediately.

Thanks,

Jonathan

CLIENT

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace WinPDA
{
/// <summary>
/// Summary description for Form1.
/// </summary>
public class FormUserSignIn : System.Windows.Forms.Form
{
private System.Windows.Forms.Label lblReceivedData;
private System.Windows.Forms.Button cmdSendData2;
private System.Windows.Forms.Timer timer1;
private System.Windows.Forms.Button cmdSendData;

public FormUserSignIn()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
base.Dispose( disposing );
}
#region Windows Form Designer generated code
#endregion

/// <summary>
/// The main entry point for the application.
/// </summary>

static void Main()
{
Application.Run(new FormUserSignIn());
}

NetworkStream ApplicationStream = null;

public void FormUserSignIn_Load(object sender, System.EventArgs e)
{
GlobalData.refFormUserSignIn = this;


}


private void cmdSendData_Click(object sender, System.EventArgs e)
{
// Connect to server
ApplicationStream = EstablishConnection();

byte[] bytesToSend = new byte[256];
int iBufferLength = 8096;
byte[] buffer = new byte[iBufferLength];

string strResult = "";
bool bReceivedResponse = false;
int numBytesRead = 0;
int i = 0, j = 0;

for (j = 0; j < 500; j++)
{
// Send command
bytesToSend = ASCIIEncoding.ASCII.GetBytes("This a test command: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb ccccccccccccccccccccccccccccccccccccccccccccccc ddddddddddddddddddddddddddddddddddddddddddd eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee\0");

try
{
ApplicationStream.Write(bytesToSend, 0, bytesToSend.Length);
}
catch (ObjectDisposedException)
{
MessageBox.Show("ObjectDisposedException occurred writing to stream");
return;
}
catch (Exception)
{
MessageBox.Show("Exception occurred writing to stream");
return;
}

// Get result
strResult = "";
bReceivedResponse = false;
numBytesRead = 0;

do
{
//for (i = 0; i < iBufferLength; i++)
//{
// bufferIdea = Convert.ToByte(' ');
//}

try
{
numBytesRead = ApplicationStream.Read(buffer, 0, iBufferLength);
}
catch (IOException)
{
MessageBox.Show("IOException occurred reading from stream");
return;
}
catch (ObjectDisposedException)
{
MessageBox.Show("ObjectDisposedException occurred reading from stream");
return;
}

if (numBytesRead > 0)
{
// Convert and add to input string
strResult += ASCIIEncoding.ASCII.GetString(buffer, 0, numBytesRead);

if (strResult.IndexOf("\0") != -1)
{
// Finished reading response successfully
strResult = strResult.Substring(0, strResult.Length - 1);
bReceivedResponse = true;
break;
}
}
}
while (numBytesRead > 0);

Cursor.Current = Cursors.Default;
if (bReceivedResponse)
{
lblReceivedData.Text = strResult;
}
else
{
lblReceivedData.Text = "No data";
}

// Pause
//ApplicationStream.Flush();
//System.Threading.Thread.Sleep(50);
}
}

public NetworkStream EstablishConnection()
{
TcpClient client = new TcpClient();
IPEndPoint ipendpoint = new IPEndPoint(IPAddress.Parse(Utilities.GetAppSetting("ServerIPAddress")), GlobalData.SERVER_PORT);

try
{
client.Connect(ipendpoint);
}
catch (Exception)
{
// Connection failed
client.Close();
return null;
}

// Connection successful
return client.GetStream();
}
}
}


SERVER

using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;
using System.IO;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;

namespace WinPDAServer
{
//-----------------------------------------
// Get a file name from the client.
// Open the file and send the contents from
// the server to the client
//-----------------------------------------
public class Server : IDisposable
{
private FormMain mainForm;
private Socket socketForClient;
private TcpListener tcpListener;
private static ArrayList clientList = new ArrayList();



public Server(FormMain mainForm)
{
this.mainForm = mainForm;
}



public void Run()
{
tcpListener = new TcpListener(IPAddress.Parse("0.0.0.0"), 6767);
//tcpListener = new TcpListener(Dns.Resolve("localhost").AddressList[0], 6767);
tcpListener.Start();

mainForm.AddStatus("Server started. Waiting for connection on port 6767.");

// Wait for clients
while (true)
{
// For each client connection, pass the client to a new thread and
// return immediately to listening for the next client
try
{
socketForClient = tcpListener.AcceptSocket();
}
catch (SocketException)
{

}

if (socketForClient.Connected)
{
ClientHandler handler = new ClientHandler(socketForClient, mainForm);
clientList.Add(handler);

mainForm.AddStatus("");
mainForm.AddStatus("Client connected");
handler.StartRead();
}
}
}



/// <summary>
/// Clean up before object is destroyed
/// </summary>
public void Dispose()
{
if (socketForClient != null)
{
socketForClient.Close();
}

if (tcpListener != null)
{
tcpListener.Stop();
}
}



/// <summary>
/// Nested ClientHandler class. Each instance handles one client
/// </summary>
public class ClientHandler : IDisposable
{
private const int BufferSize = 1024;
private byte[] buffer;
private Socket socket;
private NetworkStream networkStream;
private AsyncCallback readCommandCallback;
private FormMain mainForm;

private string dateTimeConnected;
private string dateConnected;
private string strRead;


public ClientHandler(Socket socketForClient, FormMain mainForm)
{
this.mainForm = mainForm;
this.socket = socketForClient;
networkStream = new NetworkStream(socketForClient);
buffer = new byte[BufferSize];

// Set callbacks
readCommandCallback = new AsyncCallback(this.OnReadCommandComplete);

dateTimeConnected = DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
dateConnected = DateTime.Now.ToString("yyyy-MM-dd");
}



public void StartRead()
{
strRead = "";
networkStream.BeginRead(buffer, 0, buffer.Length, readCommandCallback, null);
}



private void OnReadCommandComplete(IAsyncResult ar)
{
int bytesRead = 0;

try
{
bytesRead = networkStream.EndRead(ar);
}
catch (Exception)
{
mainForm.AddStatus("Client disconnected");
mainForm.AddStatus("");
networkStream.Close();
socket.Close();
clientList.Remove(this);
}

if (bytesRead > 0)
{
strRead += Encoding.ASCII.GetString(buffer, 0, bytesRead);

if (strRead.IndexOf("\0") != -1)
{
// Have read entire string, so save it and read the file contents
string strCommandString = strRead.Substring(0, strRead.Length - 1);
mainForm.AddStatus("Received command: " + strCommandString + "...");

string strResponse = "This is a test command response: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz\0";
networkStream.Write(ASCIIEncoding.ASCII.GetBytes(strResponse), 0, strResponse.Length);

// Response has been sent, so wait for next command
strRead = "";
networkStream.BeginRead(buffer, 0, buffer.Length, readCommandCallback, null);
}
else
{
// Have not read whole string, so read rest of it
networkStream.BeginRead(buffer, 0, buffer.Length, readCommandCallback, null);
return;
}
}
else
{
mainForm.AddStatus("Client disconnected");
mainForm.AddStatus("");
networkStream.Close();
socket.Close();
clientList.Remove(this);
}
}



/// <summary>
/// Release resources before object is destroyed
/// </summary>
public void Dispose()
{
if (networkStream != null) networkStream.Close();
if (socket != null) socket.Close();
networkStream = null;
socket = null;

// Remove client from array list
clientList.Remove(this);
}

}

}
}



Answer this question

Problem with socket communication for client (On handheld) / server (on PC) application

  • Derek Baird

    Amazing!

    Thanks Alex.

  • Witold

    I have a problem working in similar environment. I have a client running on windows mobile smartphone and the server running on desktop. The client tries to talk to server via activesync, over usb .The idea of this program is to measure TCP/IP bandwidth.

    The client calls winsock method connect () , and this fails. The failure code obtained by using WSAGetLastError() is : WSAEADDRNOTAVAIL (10049 ) - Cannot assign requested address. Now the server IP ad Port are correct. Could anyone suggest a way to debug this further or propose a solution


  • jms04081974

    Have you considered making your TcpClient a member of the form class rather than a local variable

  • Problem with socket communication for client (On handheld) / server (on PC) application