Reuse a TcpClient in c# - c#

We have a device that accepts ascii messages over a wireless network, and then responds with a value and I have successfully implemented this in a Windows Forms 2010 solution in c#.
I wrote this as a test solution to prove the technology and the actual calls to the device will be made on a Motorola MC55 handheld device.
I have now written an additional test solution in Visual Studio 2008 and installed this onto a device, but the connection to the TcpClient takes around 30 seconds every time its called on the mobile device, where as on the windows solution it's almost instant.
This is far too slow, so I have started looking at reusing the TcpClient, but not had any success and wondered if anyone else has had similar issues and to ask how they got around it, or if anyone can offer any advice on how to reuse a TcpClient so I don't have to create a new one every time I want to make my call.
The code for the connection is shown below...
public static string GetValueFromDevice(string deviceIPAddress, int devicePort, string messageSentToDevice)
{
string returnValue = "";
try
{
TcpClient client = new TcpClient(deviceIPAddress, devicePort);
byte[] inData = System.Text.Encoding.ASCII.GetBytes(messageSentToDevice);
NetworkStream stream = client.GetStream();
stream.Write(inData, 0, inData.Length);
byte[] outData = new Byte[256];
int bytes = stream.Read(outData, 0, outData.Length);
returnValue = System.Text.Encoding.ASCII.GetString(outData, 0, bytes);
stream.Close();
client.Close();
}
catch (Exception ex)
{
returnValue = ex.Message;
}
return returnValue;
}

You can leave the TcpClient open as long as you like. Keep the client and stream variables as part of the class (instead of in the function), and don't call Close() until you're done.

You can persist and re-use the client and stream and place the code into a separate thread.
But, I do not believe the client needs about 30 seconds to initialize. I see that slow init for TCP client when having an ActiveSync connection, but if you have a wireless only connection, it should init immediately.
So also check your network setup. After first VS deploy and debug session using Active Sync, Visual Studio is able to re-use the determined wireless IP address and runs subsequent deploy/debug sessions via the wireless TCP/IP (if ActiveSync on PC is set to allow Data connections during AS connections).

Related

Replicate PuTTY's raw connection with sockets

I am working with a heat cell with which i can only communicate through Ethernet. When trying to connect to it using sockets, I am stuck on waiting for the Receive() method to end.
I've checked the connection using PuTTY in raw mode and it worked just fine, I was able to send and receive messages.
This led me to believe that I needed to use some kind of raw communication as well, hence why I tried to use SharpPCap and the like. Using this, I am able to read from the cell (although I am faced with a few issues that aren't related to this post).
However, since I'm not very experienced with networking, I was wondering if there was a way to obtain the same results as when I used PuTTY's raw mode but using only Sockets ?
I've come accross this question that was left unanswered, apart from the fact that the author was advised not to use SocketType.Raw.
Below is the example from MSDN documentation that I adapted for my tests. It is supposed to send a request and then listen for the answer.
static void Main(string[] args)
{
System.Net.IPAddress host = System.Net.IPAddress.Parse("10.0.0.3");
int port = 2049;
Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
socket.Connect(host, port);
if (socket.Connected)
{
string request = "99997¶1¶1\\r";
var byteSent = Encoding.Default.GetBytes(request);
var byteReceived = new byte[256];
socket.Send(byteSent, byteSent.Length, 0);
int bytes = 0;
do
{
bytes = socket.Receive(byteReceived, byteReceived.Length, 0); // this is the line I'm being stuck on
} while (bytes > 0);
Console.WriteLine($"Result : {Encoding.Default.GetString(byteReceived)}");
Console.ReadLine();
}
else
{
Console.WriteLine("Connection Failed");
Console.ReadLine();
}
}
UPDATE
I used WireShark to take a look at what was being sent from my application. Turns out the 'CR' and 'LF' werent sent correctly. But correcting this didn't solve my problem.
I can see the server's answer to my request on WireShark, but still I can't read anything using socket.Receive(). Could it be possible that the server is faster to answer than my machine is to start listening ? I tried setting up the socket.ReceiveTimeout property and put my send/receive instructions in a loop, but still nothing returning from the Receive() statement.
The socket is in blocking mode by default (cf Socket.Blocking). That mean that, for your case, blocking until 256 byte has been read (Without timeout by default Socket.ReceiveTimeout).
You may want to set the Blocking mode to false, or set a Receive timeout in order to not block indefinitly.
Alternatively, you may want also to use async method to avoid blocking the main thread.

StreamSocket : datareader.LoadAsync waits infinte even when data is avaialbe

I have the following code in my Windows phone 8 app.
//connection code, done during app start
socket = new StreamSocket();
await socket.ConnectAsync(serverHostName, serviceName);
dataReader = new DataReader(socket.InputStream);
dataReader.InputStreamOptions = InputStreamOptions.Partial;
dataWriter = new DataWriter(socket.OutputStream);
After the connection is established, I have another thread which checks for incoming network packets
await dataReader.LoadAsync(2048);
dataReader.ReadBytes(buffer);
----------
Workflow is as follows
Phone connects to server using socket.ConnectAsync
Server responds with initial message (Phone receives this properly in dataReader.LoadAsync function)
Phone now sends the 'business specific' request
Server now replies with 'business specific' response (Problem lies here. Phone doesn't receive the reply from server at some of the times).
There is no scenario difference between working state' and 'non working state'.
So I tried to debug this. I put a breakpoint for dataReader.LoadAsync and saw that execution waits infinitely at the call.
To make sure that the server is sending data properly, I ran the app in Windows phone emulator and ran the WireShark network analyzer in the PC. I could see that packets are being received for the IP Address of the phone.
Anyone has any hints on why the dataReader.LoadAsync function call doesn't return at all, when there is data ready to be read in the socket?
I faced the same problem. It is especially bad for Bluetooth RFCOMM SPP serial port devices, because the underlying Rfcomm-object does not provide capabilities for setting ReadTimeout values.
Edit: The InputStreamOptions.Partial option seems to be working UWP Win10 platform, but it is only useful when you are already know much data you are expecting. Otherwise it will wait indefinitely on the last call.
I almost gave up, when I found in references below these lines to solve the problem by using a CancellationTokenSource
//connect your Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService
// see the Bluetooth chat example
[...]
StreamSocket streamSocket = new StreamSocket();
await streamSocket.ConnectAsync(...); //connect to Bluetooth device
DataReader dataReader = new DataReader(inputStream); // to read from the stream
try
{
var timeoutSource = new CancellationTokenSource(1000); // 1000 ms
uint numberBytesToRead = 256;
var data = await dataReader.LoadAsync(numberBytesToRead).AsTask(timeoutSource.Token);
}
catch (TaskCanceledException)
{
// we will get here, and everything looks fine, but the problem is:
// The underlying streamSocket is also closed!
// we can not re-use the streamSocket. Any more calls to LoadAsync results in exceptions (something about the object being not assigned...)
// we need to do a full await streamSocket.ConnectAsync(...) again, but that takes ~3 seconds.
}
So this method is only a brute-force, last-resort attempt at a time-out.
The method from #mayu works very good (serialDevice.ReadTimeout), but only on devices of class Windows.Devices.SerialCommunication.Serial​Device, but not on
Windows.Devices.Bluetooth.Rfcomm.RfcommDeviceService. I don't know how the situation is for TCP/IP sockets.
In short, is there any usable time-out for RFCOMM SPP Bluetooth connections?
Or any method to know ahead of time if .LoadAsync(1) will block, because no new data is available?
This fellow over at MSDN has the exact same problem, but MS don't know an answer either: https://social.msdn.microsoft.com/Forums/vstudio/en-US/71ea17d4-ca16-43c2-ab43-02d5301def3f/chow-to-set-timeout-on-streamsocketreadasync?forum=wpdevelop
References:
In UWP StreamSocket, can I read data with timeout and leave the connection open if timeout elapses
https://social.msdn.microsoft.com/Forums/en-US/8a5c4fdc-28d6-4a22-8df6-bc519efeaa4d/how-to-control-the-timeout-for-reading-from-streamsocket?forum=winappswithcsharp
DataReader of SocketStream for UWP App
"According to documentation when using InputStreamOptions.Partial, you should use UnconsummedBufferLength instead of an hardcoded value"
That sample seems to be broken.
"await reader.LoadAsync(reader.UnconsumedBufferLength);" is equivalent to
await reader.LoadAsync(0); and then it's not possible to read any data, since you have no buffer to read from.
I'm testing this now and it seems like "reader.InputStreamOptions = Partial;" has no effect at all. My only workaround is to lower the read timeout.
According to documentation when using InputStreamOptions.Partial, you should use UnconsummedBufferLength instead of an hardcoded value :
DataReader reader = new DataReader(clientSocket.InputStream);
// Set inputstream options so that we don't have to know the data size
reader.InputStreamOptions = Partial;
await reader.LoadAsync(reader.UnconsumedBufferLength);
Sample is there
I had a similar problem using Windows Remote Arduino library and SerialUSB stream. I had to change this library and call LoadAsync(1) instead of original LoadAsync(100). Now the code is working fine.
see: https://github.com/ms-iot/remote-wiring/issues/111
For serial devices you need to set
device.ReadTimeout = TimeSpan.FromMilliseconds(100);
for the LoadAsync to return before the buffer is full.
The only way I found to get round not knowing the size of the data before reading was to read one byte at a time until I got a timeout. Feels horrid, but works. Is there a better way yet?
private async Task ReadData(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
DataReaderObject.InputStreamOptions = InputStreamOptions.Partial;
uint data = 0;
uint bufferLength = DataReaderObject.UnconsumedBufferLength;
var timeoutSource = new CancellationTokenSource(100); // 100 ms
try
{
while (true)
{
data = await DataReaderObject.LoadAsync(1).AsTask(timeoutSource.Token);
if (data > 0)
{
String temp = DataReaderObject.ReadString(data);
TemperatureValue.Text += temp.Trim();
}
}
}
catch (Exception)
{
;
}
}

Unable To Accept TcpClient a Second Time C#

I am new to both C# and to client-server programming. Right now, for class, I'm attempting to create an FTP client without using any pre-established FTP libraries. I feel like I have the project down for the most part, however I'm running into a problem when I make more than one call that requires use of the data port (list, retr, etc.) Here is a sample of the code that is breaking:
writer.WriteLine(portcmd);
writer.Flush();
GetServerMessage(stream);
writer.WriteLine("list ");
writer.Flush();
tmpserver = new TcpListener(IPAddress.Any, 3128);
tmpserver.Start();
tmpclient = tmpserver.AcceptTcpClient();
Console.WriteLine("gothere");
if (!tmpclient.Connected)
{
tmpserver.Start();
}
StreamReader tmpreader = new StreamReader(tmpclient.GetStream());
GetServerMessage(stream);
while (tmpreader.Peek() != -1)
{
Console.WriteLine(tmpreader.ReadLine());
}
tmpclient.Close();
tmpserver.Stop();
GetServerMessage(stream);
Getservermessage is a method that takes a network stream and prints out everything available within a .5 second timeout, stream is the NetworkStream for the current connection to the FTP server, and writer is that same network stream wrapped in a StreamReader for ease of writing ASCII characters to the server. In case you are wondering why I use a stream reader to read from the data connection, it is because the server closes the connection after it transmits the data so I could easily get an eof notification. My GetServerMessage method was for some reason breaking when I used the closed network stream.
This code is sending the port command to the FTP server to inform it that I will be requiring a data connection (first 2 lines) Then sending the list command, establishing the data connection to the server, getting the desired information, and then terminating the data connection (the rest of the code).
This code will execute without flaw the first time I run it but if I try it again, it hangs on the 'tmpclient = tmpserver.AcceptTcpClient();' line. It never reaches the "gothere" print statement. I believe this is because I am receiving the client from the same machine on the same port but I'm not sure. I tried adding a Boolean value to make sure the AcceptTcpClient() only ran once but then I got a runtime error and visual studio informed me that I may have 'released resources before I was done with them' I predicted this would be a problem but how can I tell if the server reestablishes the connection after it has closed it once?
At the end of the given code I stop tmpserver and close tmpclient. I originally did this because I knew the FTP server would close the connection when it was finished transmitting and thought it was the proper thing to do. I find if I comment out these lines, the code will execute more than once but the streams appear to be empty... I'm not sure if this information is helpful but I figured I'd mention it.
I apologize if I am unclear at all but my lack of knowledge with the subject makes it difficult to articulate my problem. If there is any confusion over what the problem is I'd be happy to attempt to clear it up.
To be able to accept another client you should execute tmpclient = tmpserver.AcceptTcpClient(); and waiting for the first client to finish its works(before accepting second client) may not be a good idea
Here is a sample server code that waits for the connections and echoes strings sent from each client. You can test it with telnet localhost 3128
Thread t = new Thread(Server);
t.IsBackground = true;
t.Start();
-
void Server()
{
TcpListener listener = new TcpListener(IPAddress.Any, 3128);
listener.Start();
while (true)
{
var client = listener.AcceptTcpClient();
new Thread(() =>
{
using (client)
{
var reader = new StreamReader(client.GetStream());
var writer = new StreamWriter(client.GetStream());
while (true)
{
string line = reader.ReadLine();
if (line == "QUIT") break;
writer.WriteLine("From Thread[" + Thread.CurrentThread.ManagedThreadId + "] > " + line);
writer.Flush();
}
}
}).Start();
}
}
OK, it's like this. To do a server in a simple manner, you need to thread off the code that handles the client socket. When the accept returns, create and start a thread, passing it the 'tmpclient' and then loop around to the accept call again so that any new client can connnct up. In the newly-spawned server<> client thread, read and write to the passed socket in a loop to communicate with the client.
Once you close your tcp client stream, you can no longer read from the stream you pulled from it.
var stream = tcpClient.GetStream();
...
tcpclient.Close();
...
stream.Read .. fail
The client would have to request another connection,
OR
You should keep your tcp client sockets open.
More complex servers will keep some metadata (state) cached about the client so when sockets unexpectedly close - and the client quickly tries to reconnect, the server can continue processing the smoothly.

TcpClient creation seem to be very slow. Can I cache those?

I have program where client peers communicate with each other via TCP-IP. When one client does something he will signal other clients one by one that this happened. Here is a code I use to send data across:
public static string SendDirect(string data, string hostName, int portNumber)
{
string responseData;
try
{
var client = new TcpClient(hostName, portNumber);
Stream s = client.GetStream();
var sw = new StreamWriter(s) { AutoFlush = true };
sw.WriteLine(data);
s.Close();
client.Close();
s.Dispose();
sw.Dispose();
responseData = "OK";
}
catch (SocketException ex)
{
responseData = ex.Message;
}
return responseData;
}
Line
var client = new TcpClient(hostName,
portNumber);
can be very slow at times for some machines. For example, in my home network it takes like 2 or 3 seconds. Can you see how it's real bad with 15 clients.
I was wondering how expensive or if even possible to not Close client every time and keep 30-40 of them open at all times? I assume some mechanism to check to make sure they alive and to make sure they all closed properly need to be coded but I wonder if idea itself is correct..
Thanks!
Nothing should keep or limit you from creating more than one client/connection at a time. Actually initiating and closing tons of connections might trigger different security stuff (trying to fend of a possible DDOS attack or whatever). You might as well speed up the process resolving host names before and caching those. It doesn't necessarily have to be the object creation that slows you down actually.
The OS might throttle the number of pending connections per second (think 10 per second under Windows) but other than that there shouldn't be any issues. You shouldn't open/close connections for single commands anyway in my opinion. You should think about keeping both open, the TcpClient as well as the StreamWriter. Just ensure you flush once you're done writing your packet. To improve performance you should think about manual flushing, especially if there's is more than one command/packet to be sent to each client as each packet will take the minimum TCP window size (usually something around 1492-1500 bytes).

Help creating/debugging a C# license server for my applications

I have a number of C# software applications that are add-ins for a peice of software that has a .net API.
for software licensing purposes I'm required to have a license server. I've got this, at the moment this is what it does:
when a tool is run, it contacts the license server with its computer name and username
the server recieves this request, logs the request, and checks to see if the number of requests from that machien and or user have exceeded the preconfigured maximum (2 different licensing types)
it does this using an encrypted file which lists the time, machine name, username etc
if its ok, it returns OKAY response to the computer and the tool then runs
if it doesnt return anything or if it returns a not OK response the tool will not run (the software only runs for a short time, but is regulary ran, as opposed to opening for a long time)
This works great, except I'm having a problem that the server randomly crashes, and users can't get onto it.
This is the first client-server app I've done and I'm a bit in the dark (and feel like I'm re-inventing something which is commonly used), is there any good guides for creating something like that? My apps is very simple, I have a service running on the server looping listening on a TCP port, waiting for something to be sent.
public void StartListening()
{
Listening = true;
// Set the TcpListener on port 41616.
Int32 port = 41616;
IPAddress localAddr = IPAddress.Any;
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
Listen();
}
public void Listen()
{
try
{
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while (Listening)
{
TcpClient client = server.AcceptTcpClient();
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
string returnData;
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = null;// DO STUFF BASED ON DATA
// set returnData to be the response (ie OKAY)
msg = System.Text.Encoding.ASCII.GetBytes(returnData);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", returnData);
// Shutdown and end connection
client.Close();
}
}
catch (Exception ex)
{
//LOG ERROR
}
finally
{
Listening = false;
server.Stop();
}
}
I have a feeling the server is hanging somewhere on the decryption /encryption of the license log, as the server runs fine for a while then just stops, and if i re-create the license log it works. But thats not the point of this post (though any tips on why I'm getting this error:
Error occured: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host. at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at BWSSLicenseServer.LicenseServer.Listen()
woudl be great)
My question is - how do I debug this easily in .NET? is there any good guides out there to help me? or is there any free framework for this? Should I be doing this code a totally different way (WCF, Web Service or something like that?)
ended up using CryptoLicensing as suggested in the comments
It may be something to do with the object expiring. Try adding this to your server class:
public override object InitializeLifetimeService()
{
return null;
}

Categories

Resources