Application blocking when the target server is offline - c#

The problem exists when the target server is offline, the application freezes for 2-3 sec, until the call is made again, where the process repeats. When the server is online, the application works correctly, is there any way to solve it?
private async Task<bool> StartConnect2()
{
while (TaskIsRun)
{
txtConnectResult.Text += Connect2("127.0.0.1", "3333", SendRequest) + "\n";
await Task.Delay(1000);
}
return false;
}
public static string Connect2(string IP, string Port, string SendData)
{
try
{
TcpClient client = new(IP, int.Parse(Port));
byte[] data = Encoding.ASCII.GetBytes(SendData);
NetworkStream stream = client.GetStream();
stream.Write(data, 0, data.Length);
data = new byte[256];
string responseData = string.Empty;
int bytes = stream.Read(data, 0, data.Length);
responseData = Encoding.ASCII.GetString(data, 0, bytes);
stream.Close();
client.Close();
return responseData;
}
catch (ArgumentNullException e)
{
return $"ArgumentNullException: {e.Message}\n";
}
catch (SocketException e)
{
return $"SocketException: {e.Message}\n";
}
}

Related

Socket disconnect after read the textfile. How to maintain the connection?

Here is my code:
A listener to wait for connection from client:
static void Main(string[] args)
{
IPAddress ipAddr = IPAddress.Parse(args[1]);
TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2]));
listener.Start();
Console.WriteLine("Waiting for a connection.");
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client accepted.");
while (true)
{
NetworkStream stream = client.GetStream();
StreamReader sr = new StreamReader(client.GetStream());
StreamWriter sw = new StreamWriter(client.GetStream());
try
{
if (stream.DataAvailable)
{
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
int recv = 0;
foreach (byte b in buffer)
{
if (b != 0)
{
recv++;
}
}
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine("request received: " + request);
if (request != null)
{
string response = null;
response = apiQueryAndReponse(request, args[0]);
if (response != null)
{
byte[] byData = Encoding.ASCII.GetBytes(response);
stream.Write(byData, 0, byData.Length);
stream.Flush();
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
Console.WriteLine(e.Message.ToString());
//sw.WriteLine(e.ToString());
}
}
}
Get and return the response:
private static string apiQueryAndReponse(string rec, String stagingfilepath)
{
String response = null;
if (rec.Contains("GetTesterInfo"))
{
response = getLatestStatusOK("GetTesterInfo", stagingfilepath);
if (response != null)
{
Console.WriteLine("Response: " + response + "," + fileline + "\n");
fileline++;
}
}
return response;
}
Read the text file and get the response:
private static String getLatestStatusOK(String key, String filedir)
{
using (var fs = new FileStream(filedir, FileMode.Open, FileAccess.Read))
{
using (var sr = new StreamReader(fs, Encoding.UTF8))
{
while ((stagingfiledata = sr.ReadLine()) != null)
{
try
{
if (stagingfiledata.Contains(key))
{
String[] data = stagingfiledata.Split(",");
response = data[2];
}
}
catch (Exception exp)
{
Console.WriteLine("err message:" + exp.Message);
}
}
}
}
return response;
}
What I trying to do here: I will read a text file and get response to reply to client. But the socket will disconnect after access the text file.(I have tried connect with client without call the text file access function). I want to maintain connection and read text file when it necessary.
There are a number of issues with this code.
Your primary issue: you are creating a new StreamReader and StreamWriter on each loop, and they dispose the underlying stream when they are garbage-collected.
You aren't even using those readers and writers, you may as well remove them
You are missing using in a number of places.
The number of bytes received is returned from the Read function, you do not have to guesstimate by checking for \0.
static void Main(string[] args)
{
IPAddress ipAddr = IPAddress.Parse(args[1]);
TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2]));
listener.Start();
Console.WriteLine("Waiting for a connection.");
using TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Client accepted.");
using NetworkStream stream = client.GetStream();
while (true)
{
try
{
byte[] buffer = new byte[1024];
int recv = stream.Read(buffer, 0, buffer.Length);
string request = Encoding.UTF8.GetString(buffer, 0, recv);
Console.WriteLine("request received: " + request);
if (request != null)
{
string response = null;
response = apiQueryAndReponse(request, args[0]);
if (response != null)
{
byte[] byData = Encoding.UTF8.GetBytes(response);
stream.Write(byData, 0, byData.Length);
stream.Flush();
}
}
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
Console.WriteLine(e.Message.ToString());
//sw.WriteLine(e.ToString());
}
}
}
There are other serious flaws with your design:
TCP does not guarantee that a single write will become a single read on the other end of the wire. Chunks of data may be split or combined. It's a stream, not a messaging protocol.
So you need a framing mechanism. The easiest one to use is to first pass the size of your data, then read that amount of bytes.
You are also not able to handle multiple clients. You need to hand off each one to a Task.
Corrollary to that, you should use async functions to improve performance and responsiveness.
You should also have a cancellation token which you can use if someone presses CTRL+C.
You probably shouldn't try to handle an exception and then continue. If an exception happens, log it and close the connection.
static CancellationTokenSource _cancellation = new();
static async Task Main(string[] args)
{
Console.CancelKeyPress += (sender, e) => _cancellation.Cancel();
IPAddress ipAddr = IPAddress.Parse(args[1]);
TcpListener listener = new TcpListener(ipAddr, Int32.Parse(args[2]));
listener.Start();
try
{
Console.WriteLine("Waiting for a connection.");
TcpClient client = await listener.AcceptTcpClientAsync(_cancellation.Token);
Console.WriteLine("Client accepted.");
Task.Run(() => HandleClient(client), _cancellation.Token);
}
catch (OperationCanceledException)
{ //
}
finally
{
listener.Stop();
}
}
private async Task HandleClient(TcpClient client)
{
using var _ = client;
await using NetworkStream stream = client.GetStream();
var lengthBuf = new byte[4];
try
{
while (true)
{
await stream.ReadExactlyAsync(lengthBuf, 0, 4, _cancellation.Token);
var length = BitConverter.ToInt32(lengthBuf, 0);
if(length > SomeMaxLengthHere || length <= 0)
throw new Exception("Too long");
byte[] buffer = new byte[length];
await stream.ReadExactly(buffer, 0, length, _cancellation.Token);
string request = Encoding.UTF8.GetString(buffer, 0, length);
Console.WriteLine("request received: " + request);
if (request != null)
{
string response = apiQueryAndReponse(request, args[0]);
if (response != null)
{
byte[] byData = Encoding.UTF8.GetBytes(response);
await stream.WriteAsync(byData, 0, byData.Length, _cancellation.Token);
await stream.FlushAsync(_cancellation.Token);
}
}
}
}
catch (OperationCanceledException)
{ //
}
catch (Exception e)
{
Console.WriteLine("Something went wrong.");
Console.WriteLine(e.Message.ToString());
//sw.WriteLine(e.ToString());
}
}

C# - Get error result by sending images via NetworkStream

I currently need to send big data (such as images) from a client(C#) to a server (C#). There is no problem with sending and receiving the string data via NetworkStream. But when sending large data (images) will get an error result (loss data or image crash). Any idea?
client image output before sending (test_send.jpg)
output after the server received(test_received.jpg)
Server
static void Main(string[] args)
{
int Port = 20000;
TcpListener? server = null;
try
{
server = new TcpListener(IPAddress.Any, Port);
server.Start();
var client = server.AcceptTcpClient();
var stream = client.GetStream();
// get image
var ms = new MemoryStream();
int total = 0;
int read = -1;
do
{
if (!stream.CanRead)
{
continue;
}
Console.WriteLine("get");
byte[] data = new byte[client.ReceiveBufferSize];
read = stream.Read(data, 0, client.ReceiveBufferSize);
ms.Write(data, 0, data.Length);
total += read;
} while (read > 0);
Console.WriteLine("get image finish");
Console.WriteLine($"total is {total}"); // 8590651
byte[] image = ms.ToArray();
// image.Length is different every time, I don't know why
Console.WriteLine($"the byte array size is {image.Length}");
File.WriteAllBytes("/Users/tim/Downloads/test_received.jpg", image);
Console.WriteLine("saved");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
finally
{
server?.Stop();
}
}
Client
private static void SendData(byte[] image)
{
Console.WriteLine($"image byte size is {image.Length}"); // 8590651
File.WriteAllBytes("/Users/tim/Downloads/test_send.jpg", image); // test
// TCP
var tcpClient = new TcpClient();
try
{
tcpClient.Connect("127.0.0.1", 20000);
}
catch (Exception e)
{
Console.Error.WriteLine($"TCP connect error, {e.Message}");
return;
}
try
{
var stream = tcpClient.GetStream();
if (stream.CanWrite)
{
stream.Write(image, 0, image.Length);
}
}
catch (Exception e)
{
Console.Error.WriteLine($"send error, {e.Message}");
}
tcpClient.Close();
}
Your mistake is in this line
ms.Write(data, 0, data.Length);
It should be
ms.Write(data, 0, read);
To be honest, it's far easier to just use CopyTo.
var ms = new MemoryStream();
stream.CopyTo(ms);
You should also consider transitioning to a fully async flow, and you are also missing using everywhere.
static async Task Main(string[] args)
{
int Port = 20000;
TcpListener? server = null;
try
{
server = new TcpListener(IPAddress.Any, Port);
server.Start();
using var client = await server.AcceptTcpClientAsync();
using var stream = client.GetStream();
// get image
var ms = new MemoryStream();
await stream.CopyToAsync(ms);
Console.WriteLine("get image finish");
Console.WriteLine($"total is {total}"); // 8590651
byte[] image = ms.ToArray();
// image.Length is different every time, I don't know why
Console.WriteLine($"the byte array size is {image.Length}");
await File.WriteAllBytesAsync("/Users/tim/Downloads/test_received.jpg", image);
Console.WriteLine("saved");
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
finally
{
if(server?.Active)
server?.Stop();
}
}
private static async Task SendData(byte[] image)
{
Console.WriteLine($"image byte size is {image.Length}"); // 8590651
await File.WriteAllBytesAsync("/Users/tim/Downloads/test_send.jpg", image); // test
// TCP
using var tcpClient = new TcpClient();
try
{
await tcpClient.ConnectAsync("127.0.0.1", 20000);
}
catch (Exception e)
{
Console.Error.WriteLine($"TCP connect error, {e.Message}");
return;
}
try
{
using var stream = tcpClient.GetStream();
await stream.WriteAsync(image, 0, image.Length);
}
catch (Exception e)
{
Console.Error.WriteLine($"send error, {e.Message}");
}
}
Consider also passing the NetworkStream directly to a FileStream.

Unable to read data from tcp server

I have created a simple C# client application. Once it connects to the server it should read the messages sent from the server. It also has the ability to send messages to server too. However I am unable to figure out to correct way to read the data.
I am spawning a thread once it connects to the server. The thread runs in infinite loop and have two interfaces each for reading and writing. Connect() method is called from a ButtonClick event.
My code snippet is as below:
namespace WpfApp1
{
public class TCPClientClass
{
private StreamWriter SwSender;
NetworkStream Sender;
NetworkStream Receiver;
//private StreamReader SrReciever;
private Thread thrMessaging;
TcpClient tcp;
bool connected = false;
public bool Connected { get { return connected; } set { connected = value; } }
//public bool Connect(IPAddress IP, int nPortNo)
public async Task Connect(IPAddress IP, int nPortNo)
{
tcp = new TcpClient();
try
{
//tcp.Connect(strIPAddress.Parse("192.168.137.1"), 2000);
// tcp.Connect(IP , nPortNo);
await tcp.ConnectAsync(IP, nPortNo);
thrMessaging = new Thread(new ThreadStart(ThreadFunction));
thrMessaging.Start();
Connected = true;
}
catch
{
MessageBox.Show("Unable to connect to server");
//return false;
}
//return true;
}
public void Disconnect()
{
Sender?.Close();
Receiver?.Close();
tcp?.Close();
//tcp?.Client.Disconnect(false);
thrMessaging.Abort();
Connected = false;
}
private void ThreadFunction()
{
while (thrMessaging.IsAlive)
DoTasks();
}
private void DoTasks()
{
if (Connected)
{
var a = ReadMessages();
SendMessages();
}
}
private /*void*/async Task ReadMessages()
{
byte[] data = new byte[4096];
//Int32 bytesRead = 0;
//Task<int> bytesReadTask;
String responseData = String.Empty;
Receiver = tcp.GetStream();
try
{
//bytesReadTask = Receiver.ReadAsync(data, 0, data.Length);
//responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytesReadTask.Result);
var response = await Receiver.ReadAsync(data, 0, data.Length);
MessageBox.Show("Server response was " + response);
Thread.Sleep(1000);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
private void SendMessages()
{
try
{
string strSendData = "Hello from GUI";
Byte[] data = System.Text.Encoding.ASCII.GetBytes(strSendData);
Sender = tcp.GetStream();
Sender.Write(data, 0, data.Length);
Sender.Flush();
Thread.Sleep(1000);
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
}
you should change
var response = await Receiver.ReadAsync(data, 0, data.Length);
MessageBox.Show("Server response was " + response);
to
var response = await Receiver.ReadAsync(data, 0, data.Length);
string result = System.Text.Encoding.Default.GetString(data);
MessageBox.Show("Server response was " + result);
if you´re still having problems..my server Code:
public class tcpServer
{
public void method()
{
TcpListener server = new TcpListener(IPAddress.Any, 9999);
server.Start();
TcpClient client = server.AcceptTcpClient();
NetworkStream ns = client.GetStream();
byte[] hello = new byte[100];
hello = Encoding.Default.GetBytes("hello world");
while (client.Connected)
{
ns.Write(hello, 0, hello.Length);
}
}
}

Continuously read data from a server in C#.net

I have my system connected with some server. I am reading data from the server.
But i want to read data continuously from the server.
Here is my code:
TcpClient client = new TcpClient("169.254.74.65", 7998);
NetworkStream stream = client.GetStream();
Byte[] data = new Byte[1024];
String responseData = String.Empty;
Int32 bytes = stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
stream.Close();
client.Close();
Can someone tell me the logic where to place the while loop to be able to listen continuously?
Just added loop without changing your code:
TcpClient client = new TcpClient("169.254.74.65", 7998);
NetworkStream stream = client.GetStream();
Byte[] data = new Byte[1024];
String responseData = String.Empty;
Int32 bytes;
while(true) {
bytes = stream.Read(data, 0, data.Length);
if (bytes > 0) {
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
}
}
stream.Close();
client.Close();
This way it will request data from server in main thread infinitely.
Additional improvements might be:
change loop condition to indicate when you want to stop reading;
add sleep when no data is available to avoid wasting processor time;
add error handling;
rewrite your code using asynchronous methods.
To receive data continuously you actually need to put in some loop.
for example:
private void StartProcessing(Socket serverSocket)
{
var clientSocket = serverSocket.Accept();
StartReceiveing(clientSocket);
}
private void StartReceiveing(Socket clientSocket)
{
const int maxBufferSize = 1024;
try
{
while (true)
{
var buffer = new byte[maxBufferSize];
var bytesRead = clientSocket.Receive(buffer);
if (ClientIsConnected(clientSocket))
{
var actualData = new byte[bytesRead];
Array.Copy(buffer, actualData, bytesRead);
OnDataReceived(actualData);
}
else
{
OnDisconnected(clientSocket);
}
}
}
catch (SocketException ex)
{
Console.WriteLine(ex.Message);
}
}
private void OnDisconnected(Socket issuedSocket)
{
if (issuedSocket != null)
{
issuedSocket.Shutdown(SocketShutdown.Both);
issuedSocket.Close();
StartProcessing(listener);
}
}
private void OnDataReceived(byte[] data)
{
//do cool things
}
private static bool ClientIsConnected(Socket socket)
{
return !(socket.Poll(1000, SelectMode.SelectRead) && socket.Available == 0);
}

Client-Server application do nothing when trying to get response from server C#/

I'm writing client-server application. Client sending command and server recieves it and do some manipulations. It works well. But when i'm trying to send response from server to client and recieve it on client side nothing happens. Even server do nothing. Program hangs and only Shift+F5 helps to finish it.
Server code:
class TNPClient
{
TNPBaseInterraction tnp_base;
private void SendError(TcpClient Client, int Code)
{
byte[] buf = Encoding.ASCII.GetBytes(Code.ToString());
Client.GetStream().Write(buf, 0, buf.Length);
Client.Close();
}
private void SendResponse(TcpClient Client, string response)
{
byte[] buf = Encoding.ASCII.GetBytes(response);
Client.GetStream().Write(buf, 0, buf.Length);
Client.Close();
}
void ParseMonitorRequest(TcpClient Client, string req)
{
MessageBox.Show("inside parser");
int term_id = Convert.ToInt32(req.Substring(2));
switch (req[1])
{
case '0':
List<MonitorStruct> monitors = tnp_base.GetMonitors(term_id);
foreach (MonitorStruct mon in monitors)
{
}
break;
case '1':
break;
case '2':
break;
case '3':
break;
case '4':
MessageBox.Show("inside 4");
List<TerminalStruct> terminals = tnp_base.GetTerminals();
foreach (TerminalStruct term in terminals)
{
MessageBox.Show("sending response");
MessageBox.Show(string.Format("ID: {0} Address: {1} Comment: {2}", term.TerminalID, term.Address, term.Comment));
//SendResponse(Client, string.Format("ID: {0} Address: {1} Comment: {2}", term.TerminalID, term.Address, term.Comment));
}
break;
}
}
void ParseTerminalRequest(TcpClient Client, string req)
{
}
public TNPClient(TcpClient Client)
{
try
{
tnp_base = new TNPBaseInterraction("127.0.0.1", "tnp", "tnp_user", "tnp123", "3406");
string Request = "";
byte[] buf = new byte[1024];
int Count = 0;
while ((Count = Client.GetStream().Read(buf, 0, buf.Length)) > 0)
{
Request += Encoding.ASCII.GetString(buf, 0, Count);
}
if (Request[0].Equals('0'))
{
ParseMonitorRequest(Client, Request);
}
else
{
ParseTerminalRequest(Client, Request);
}
}
catch (Exception ex)
{
MessageBox.Show("Exception: " + ex.Message);
}
}
}
class TNPServer
{
TcpListener Listener;
int Port = 5252;
public TNPServer(int ServerPort)
{
int MaxThreadsCount = Environment.ProcessorCount * 4;
ThreadPool.SetMaxThreads(MaxThreadsCount, MaxThreadsCount);
ThreadPool.SetMinThreads(2, 2);
Port = ServerPort;
}
public void StartServer()
{
Listener = new TcpListener(IPAddress.Any, Port);
Listener.Start();
while (true)
{
ThreadPool.UnsafeQueueUserWorkItem(new WaitCallback(ClientThread), Listener.AcceptTcpClient());
}
}
static void ClientThread(Object StateInfo)
{
new TNPClient((TcpClient)StateInfo);
}
~TNPServer()
{
if (Listener != null)
{
Listener.Stop();
}
}
}
Client side code (this code gives problem):
try
{
TcpClient client = new TcpClient("127.0.0.1", 5365);
if (client.Connected) MessageBox.Show("Connected");
byte[] buf = Encoding.ASCII.GetBytes(tbSendText.Text);
NetworkStream stream = client.GetStream();
stream.Write(buf, 0, buf.Length);
// System.Threading.Thread.Sleep(5000);
//client.ReceiveTimeout = Convert.ToInt32(TimeSpan.FromSeconds(1).TotalMilliseconds);
byte[] buffer = new byte[256];
int Count = 0;
string response = string.Empty;
// while ((Count = client.GetStream().Read(buffer, 0, buffer.Length)) > 0)
//{
Count = stream.Read(buffer, 0, buffer.Length);
response = Encoding.ASCII.GetString(buffer, 0, Count);
//}
stream.Close();
client.Close();
MessageBox.Show(response);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
All messages on server side are shown then i'm not trying to get response on client side. When i'm trying to get response no messages are shown, but connection is established.
In server side, the read loop is blocked forever. You need to read only up to to the length of the text & then parse the request. You can write the length of the text from client side & then write the content.

Categories

Resources