I have a serious issue with my .NET server application. In production, the application will reach 100% CPU usage and get stuck there until I restart the server. It seems completely random. Sometimes it will happen 10 minutes after I start the server. Sometimes a week after I start the server. There are no logs that indicate what causes it either. But I am guessing I wrote the TCP client/server wrong and there is some edge case that can cause this. I believe this issue didn't start happening until I added this TCP client/server. I say client and server because this class does both and I actually have two different server applications that use it to communicate to each other and they both experience this issue randomly (not at the same time). Also side note user clients from all over the world use this same TCP client/server class: Bridge to connect to the server as well.
Is there anything I can do to try and figure out what's causing this? It's a .NET console app running on a Linux VM on Google Cloud Platform.
If you are knowledgable with .NET TCP classes then perhaps you can find an issue with this code?
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace SBCommon
{
public class Bridge<T> where T : struct, IConvertible
{
public Dictionary<int, BridgeHandler> bridgeHandlers;
public ClientHandler clientHandler;
TcpListener server = null;
public Bridge(int port, Dictionary<int, BridgeHandler> bridgeHandlers)
{
server = new TcpListener(IPAddress.Any, port);
server.Start();
this.bridgeHandlers = bridgeHandlers;
Logging.Info($"bridge listener on address {IPAddress.Any} port {port}");
}
public void StartListener()
{
try
{
Logging.Info($"Starting to listen for TCP connections");
while (true)
{
Logging.Debug("TCP client ready");
TcpClient client = server.AcceptTcpClient();
Logging.Debug("TCP client connected");
Thread t = new Thread(new ParameterizedThreadStart(HandleConnection));
t.Start(client);
}
}
catch (SocketException e)
{
Logging.Error($"SocketException: {e}");
server.Stop();
}
}
public void HandleConnection(object obj)
{
TcpClient client = (TcpClient)obj;
client.ReceiveTimeout = 10000; // adding this to see if it fixes the server crashes
var stream = client.GetStream();
try
{
if (stream.CanRead)
{
byte[] messageLengthBytes = new byte[4];
int v = stream.Read(messageLengthBytes, 0, 4);
if (v != 4)
{
// this is happening and then the server runs at over 100% so adding lots of logging to figure out what's happening
StringBuilder sb = new StringBuilder($"could not read incoming message. Read {v} bytes");
try
{
sb.Append($"\nfrom {(IPEndPoint)client.Client.RemoteEndPoint}");
}
catch (Exception e)
{
sb.Append($"\ncould not get client's IP address because {e}");
}
sb.Append($"\nclient.Available: {client.Available}");
sb.Append($"\nclient.SendBufferSize: {client.SendBufferSize}");
Logging.Error(sb.ToString());
stream.Close();
client.Close();
stream.Dispose();
client.Dispose();
return;
}
int messageLength = BitConverter.ToInt32(messageLengthBytes, 0);
int readPos = 0;
byte[] recievedData = new byte[messageLength];
while (readPos < messageLength)
{
int size = Math.Min(messageLength - readPos, client.ReceiveBufferSize);
v = stream.Read(recievedData, readPos, size);
readPos += v;
}
Bits incoming = new Bits(recievedData);
incoming.InitReadableBuffer();
int packetType = incoming.ReadInt();
Bits outgoing;
if (packetType == int.MaxValue)
{
Logging.Info($"recieved client handler message");
outgoing = clientHandler(incoming, client);
}
else
{
if (bridgeHandlers.ContainsKey(packetType))
{
Logging.Info($"recieved {(T)(object)packetType}");
outgoing = bridgeHandlers[packetType](incoming);
}
else
{
Logging.Error($"recieved unhandled packetType {packetType}!!!!!");
return;
}
}
if (outgoing != null)
{
#region send response
byte[] sendData = new byte[outgoing.Length() + 4];
// first write the length of the message
BitConverter.GetBytes(outgoing.Length()).CopyTo(sendData, 0);
// then write the message
outgoing.ToArray().CopyTo(sendData, 4);
stream.Write(sendData, 0, sendData.Length);
outgoing.Dispose();
#endregion
}
else
{
byte[] sendData = new byte[4];
BitConverter.GetBytes(0).CopyTo(sendData, 0);
stream.Write(sendData, 0, sendData.Length);
}
}
else
{
Logging.Info("Sorry. You cannot read from this NetworkStream.");
}
}
catch (Exception e)
{
Logging.Error($"Exception: {e}");
stream.Close();
client.Close();
stream.Dispose();
client.Dispose();
}
}
public static void SendTCPmessageFireAndForget(IPEndPoint iPEndPoint, Bits bits)
{
Task.Run(() =>
{
SendTCPmessage(iPEndPoint, bits, out _);
bits.Dispose();
});
}
public static async Task<Bits> SendTCPmessageAsync(IPEndPoint iPEndPoint, Bits bits)
{
TcpClient client = new TcpClient();
client.Connect(iPEndPoint);
NetworkStream stream = client.GetStream();
stream.WriteTimeout = 5000;
stream.ReadTimeout = 5000;
// Send the message
byte[] bytes = new byte[bits.Length() + 4];
BitConverter.GetBytes(bits.Length()).CopyTo(bytes, 0); // write length of message
bits.ToArray().CopyTo(bytes, 4);
await stream.WriteAsync(bytes, 0, bytes.Length);
// Read the response
byte[] messageLengthBytes = new byte[4];
int v = await stream.ReadAsync(messageLengthBytes, 0, 4);
if (v != 4) throw new Exception("could not read incoming message");
int messageLength = BitConverter.ToInt32(messageLengthBytes, 0);
if (messageLength > 0)
{
int readPos = 0;
byte[] recievedData = new byte[messageLength];
while (readPos < messageLength)
{
int size = Math.Min(messageLength - readPos, client.ReceiveBufferSize);
v = await stream.ReadAsync(recievedData, readPos, size);
readPos += v;
}
stream.Close();
client.Close();
bits = new Bits(recievedData);
}
else bits = null;
return bits;
}
public static void SendTCPmessage(IPEndPoint iPEndPoint, Bits bits, out Bits responseBits)
{
try
{
TcpClient client = new TcpClient();
client.Connect(iPEndPoint);
NetworkStream stream = client.GetStream();
stream.WriteTimeout = 50000;
stream.ReadTimeout = 50000;
// Send the message
byte[] bytes = new byte[bits.Length() + 4];
BitConverter.GetBytes(bits.Length()).CopyTo(bytes, 0); // write length of message
bits.ToArray().CopyTo(bytes, 4);
stream.Write(bytes, 0, bytes.Length);
// Read the response
byte[] messageLengthBytes = new byte[4];
if (stream.Read(messageLengthBytes, 0, 4) != 4) throw new Exception("could not read incoming message");
int messageLength = BitConverter.ToInt32(messageLengthBytes, 0);
if (messageLength > 0)
{
int readPos = 0;
byte[] recievedData = new byte[messageLength];
while (readPos < messageLength)
{
int size = Math.Min(messageLength - readPos, client.ReceiveBufferSize);
int v = stream.Read(recievedData, readPos, size);
readPos += v;
}
stream.Close();
client.Close();
responseBits = new Bits(recievedData);
}
else responseBits = null;
}
catch (Exception e)
{
Logging.Error($"Exception: {e}");
responseBits = null;
}
}
}
public delegate Bits BridgeHandler(Bits incoming);
public delegate Bits ClientHandler(Bits incoming, TcpClient client);
}
Notes:
Bits is a class I use for serialization.
You can see in StartListener that I start a thread for every incoming connection
I also use while (true) and AcceptTcpClient to accept tcp connections. But maybe I shouldn't be doing it that way?
I read the first 4 bytes as an int from every packet to determine what kind of packet it is.
then I continue to to read the rest of the bytes until I have read all of it.
There is a lot wrong with your existing code, so it's hard to know what exactly is causing the issue.
Mix of async and non-async calls. Convert the whole thing to async and only use those, do not do sync-over-async.
Assuming stream.Read is actually returning the whole value in one call.
Lack of using in many places.
Repetitive code which should be refactored into functions.
Unsure what the use of bits.ToArray is and how efficient it is.
You may want to add CancellationToken to be able to cancel the operations.
Your code should look something like this:
public class Bridge<T> : IDisposable where T : struct, IConvertible
{
public Dictionary<int, BridgeHandler> bridgeHandlers;
public ClientHandler clientHandler;
TcpListener server;
public Bridge(int port, Dictionary<int, BridgeHandler> bridgeHandlers)
{
server = new TcpListener(IPAddress.Any, port);
this.bridgeHandlers = bridgeHandlers;
Logging.Info($"bridge listener on address {IPAddress.Any} port {port}");
}
public async Task StartListener()
{
try
{
Logging.Info($"Starting to listen for TCP connections");
server.Start();
while (true)
{
Logging.Debug("TCP client ready");
TcpClient client = await server.AcceptTcpClientAsync();
Logging.Debug("TCP client connected");
Task.Run(async () => await HandleConnection(client));
}
}
catch (SocketException e)
{
Logging.Error($"SocketException: {e}");
}
finally
{
if (listener.Active)
server.Stop();
}
}
public async Task HandleConnection(TcpClient client)
{
using client;
client.ReceiveTimeout = 10000; // adding this to see if it fixes the server crashes
using var stream = client.GetStream();
try
{
var incoming = await ReadMessageAsync(stream);
incoming.InitReadableBuffer();
int packetType = incoming.ReadInt();
Bits outgoing;
if (packetType == int.MaxValue)
{
Logging.Info($"recieved client handler message");
outgoing = clientHandler(incoming, client);
}
else
{
if (bridgeHandlers.TryGetValue(packetType, handler))
{
Logging.Info($"recieved {(T)(object)packetType}");
outgoing = handler(incoming);
}
else
{
Logging.Error($"recieved unhandled packetType {packetType}!!!!!");
return;
}
}
using (outgoing);
await SendMessageAsync(stream, outgoing);
}
catch (Exception e)
{
Logging.Error($"Exception: {e}");
}
}
public static void SendTCPmessageFireAndForget(IPEndPoint iPEndPoint, Bits bits)
{
Task.Run(async () =>
{
using (bits)
await SendTCPmessageAsync(iPEndPoint, bits);
});
}
public static async Task<Bits> SendTCPmessageAsync(IPEndPoint iPEndPoint, Bits bits)
{
using TcpClient client = new TcpClient();
await client.ConnectAsync(iPEndPoint);
using NetworkStream stream = client.GetStream();
stream.WriteTimeout = 5000;
stream.ReadTimeout = 5000;
await SendMessageAsync(stream, bits);
return await ReadMessageAsync(stream);
}
}
private async Task SendMessageAsync(Stream stream, Bits message)
{
var lengthArray = message == null ? new byte[4] : BitConverter.GetBytes(bits.Length());
await stream.WriteAsync(lengthArray, 0, lengthArray.Length); // write length of message
if (message == null)
return;
var bytes = bits.ToArray();
await stream.WriteAsync(bytes, 0, bytes.Length);
}
private async Task<Bits> ReadMessageAsync(Stream stream)
{
var lengthArray = new byte[4];
await FillBuffer(stream, lengthArray);
int messageLength = BitConverter.ToInt32(lengthArray, 0);
if (messageLength == 0)
return null;
byte[] receivedData = new byte[messageLength];
await FillBuffer(stream, receivedData);
bits = new Bits(receivedData);
return bits;
}
private async Task FillBuffer(Stream stream, byte[] buffer)
{
int totalRead = 0;
int bytesRead = 0;
while (totalRead < buffer.Length)
{
var bytesRead = await stream.ReadAsync(lengthArray, totalRead, buffer.Length - totalRead);
totalRead += bytesRead;
if(bytesRead <= 0)
throw new Exception("Unexpected end of stream");
}
}
Related
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.
i have the following code executed by a listening Thread. What it does: Reading the first Message as the total message length then assemble all packets to a big data array. (Im sending images) It all works as intended.
But after the first image is recieved and the function is done. ("ImageLengthResetted" gets printed) It closes the connection. I think this is due the fact i am running out of the scope from:
using(connectedTcpClient = tcpListener.AcceptTcpClient())
and thats what kills the connection. How can i keep this connection open?
Adding another
while(true)
after i've been connected wont do the trick. As well as executing the while loop completle after the using statments.
private void ListenForIncommingRequests()
{
try
{
// Create listener on localhost port 8052.
localAddr = IPAddress.Parse(IPadrr);
Debug.Log(localAddr);
tcpListener = new TcpListener(localAddr, port);
Debug.Log("Before Init tcplistern");
tcpListener.Start();
Debug.Log("Server is listening");
Byte[] dataRecieved = new Byte[SEND_RECIEVE_COUNT];
while (true)
{
using (connectedTcpClient = tcpListener.AcceptTcpClient())
{
Debug.Log("Accepted TCP Client");
// Get a stream object for reading
using (NetworkStream stream = connectedTcpClient.GetStream())
{
int length;
Debug.Log("Accepted Stream");
// Read incomming stream into byte arrary.
while ((length = stream.Read(dataRecieved, 0, dataRecieved.Length)) != 0)
{
Debug.Log("receiving Loop lengt: " + length);
counterReceived++;
//Get Message length with first message
if (messageLength == 0)
{
messageLength = System.BitConverter.ToInt32(dataRecieved, 0);
data = new byte[messageLength];
messageJunks = messageLength / SEND_RECIEVE_COUNT;
restMessage = messageLength % SEND_RECIEVE_COUNT;
junkCounter = 0;
}
else
{
if (junkCounter < messageJunks)
{
Array.Copy(dataRecieved, 0, data, junkCounter * SEND_RECIEVE_COUNT, SEND_RECIEVE_COUNT);
junkCounter++;
}
else
{
Array.Copy(dataRecieved, 0, data, junkCounter * SEND_RECIEVE_COUNT, restMessage);
//Whole Message recieved, reset Message length
messageLength = 0;
readyToDisplay = true;
Debug.Log("ImageLengthResetteed");
}
}
}
}
}
}
}
catch (Exception socketException)
{
Debug.Log("SocketException " + socketException.ToString());
}
}
Client Side opens send Thread with following function where socketConnection gets globally initialized on the receiving thread of the client:
private void sendData(byte[] data)
{
try
{
//socketConnection = new TcpClient(IPadrr, port);
using (NetworkStream stream = socketConnection.GetStream())
{
//Prepare the Length Array and send first
byte[] dataLength = BitConverter.GetBytes(data.Length);
int packagesSend = 0;
int numberPackages = data.Length / SEND_RECIEVE_COUNT;
if (stream.CanWrite)
{
for (counter = 0; counter <= data.Length; counter += SEND_RECIEVE_COUNT)
{
if (counter == 0)
{
stream.Write(dataLength, 0, dataLength.Length);
}
if (packagesSend < numberPackages)
{
stream.Write(data, counter, SEND_RECIEVE_COUNT);
Thread.Sleep(20);
packagesSend++;
}
else
{
stream.Write(data, counter, data.Length % SEND_RECIEVE_COUNT);
Debug.Log("FINDISCHD");
}
}
}
}
}
catch (Exception err)
{
print(err.ToString());
}
}
Im glad for any help!
The Problem was on the Client Side. I initialized the
NetworkStream stream;
now globally in the same function the socketConnection gets init.
I'm trying to implement an async TCP client that sends messages from a queue and listens to the response.
some of the server replies are lost (for example send 7 messages and get only 4 replies) and I don't understand why.
This is not a server issue, since the synchronize version I tested works just fine.
ConcurrentQueue<byte[]> msgQueue = new ConcurrentQueue<byte[]>();
public void Connect()
{
try
{
tcpclnt = new TcpClient();
Console.WriteLine("Connecting.....");
Task.Factory.StartNew(() =>
{
IAsyncResult res = tcpclnt.BeginConnect(_ip, _port, null, null);
if (!res.AsyncWaitHandle.WaitOne(CONNECTION_TIMEOUT_SEC * 1000))
{
tcpclnt.Close();
throw new ApplicationException("timed out trying to connect");
}
tcpclnt.EndConnect(res);
Receive();
byte[] message = null;
while (true)
{
message = null;
msgQueue.TryDequeue(out message);
if (message != null)
{
Stream stm = tcpclnt.GetStream();
Console.WriteLine("Transmitting..... " + Thread.CurrentThread.ManagedThreadId);//for debug
stm.Write(message.ToArray(), 0, message.ToArray().Length);
Receive();
}
}
});
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
//will be called from outside
public void SendMessage(byte[] msg)
{
Console.WriteLine("SendMessage..... " + Thread.CurrentThread.ManagedThreadId);//for debug
msgQueue.Enqueue(msg);
}
private void Receive()
{
SocketError error;
byte[] buffer = new byte[MAX_BUFFER_SIZE];
tcpclnt.Client.BeginReceive(buffer, 0, MAX_BUFFER_SIZE, SocketFlags.None, out error, new AsyncCallback(ReceiveHandler), buffer);
}
private void ReceiveHandler(IAsyncResult ar)
{
System.Console.WriteLine("ReceiveHandler " + Thread.CurrentThread.ManagedThreadId); //for debug
//End current async receive
int bytesRead = tcpclnt.Client.EndReceive(ar);
byte[] resultBuffer = (byte[]) ar.AsyncState;
// do a lot of things with resultBuffer
}
I wrote a simple client-server app in c#. Everything works good, but the server only accepts first call of the client and no more. I tried to put the receive method in the loop too (as acceptTcpSocket method), but it's still the same.
Simplified server code:
public class XMLServer
{
public void start()
{
server = new TcpListener(_serverIP, _serverPort);
try
{
server.Start();
}
catch (SocketException socketError)
{
Console.WriteLine(socketError.Message);
}
}
public void listen()
{
try
{
client = server.AcceptTcpClient();
while (true)
{
receiveFromClient();
}
}
catch (SocketException error)
{
Console.WriteLine(error.Message);
}
}
public void receiveFromClient()
{
byte[] bytes = new byte[client.ReceiveBufferSize];
byte[] send;
int readed;
stream = client.GetStream();
readed = stream.Read(bytes, 0, client.ReceiveBufferSize);
if (readed > 0)
{
string[] request = Encoding.UTF8.GetString(bytes).Split(':');
Console.WriteLine(request[0]);
switch (request[0])
{
case "getFileList":
send = encode(XMLFile.getFileList());
if (stream.CanWrite)
{
stream.Write(send, 0, send.Length);
}
break;
case "getFile":
send = encode(XMLFile.getFile(request[1]));
if (stream.CanWrite)
{
stream.Write(send, 0, send.Length);
stream.Flush();
}
break;
}
}
}
}
Using server code:
XMLServer server = new XMLServer("10.0.0.5", "7777");
server.start();
while (true)
{
server.listen();
}
Client code:
public partial class Client : Form
{
private TcpClient client;
private NetworkStream stream;
public Client(TcpClient parentClient)
{
InitializeComponent();
client = parentClient;
getFileList();
}
private void getFileList()
{
byte[] fileList = Encoding.UTF8.GetBytes("getFileList:null");
byte[] fileListResponse;
string[] files;
int Y = 30;
stream = client.GetStream();
stream.Write(fileList, 0, fileList.Length);
fileListResponse = new byte[client.ReceiveBufferSize];
stream.Read(fileListResponse, 0, client.ReceiveBufferSize);
files = Encoding.UTF8.GetString(fileListResponse).Split(';');
foreach (string file in files)
{
RadioButton radioButton = new RadioButton();
radioButton.Text = file;
radioButton.Location = new Point(10, Y);
groupBoxFiles.Controls.Add(radioButton);
Y += 30;
}
}
private void buttonOpenFile_Click(object sender, EventArgs e)
{
String fileName = groupBoxFiles.Controls.OfType<RadioButton>().FirstOrDefault(x => x.Checked).Text;
byte[] getFile = Encoding.UTF8.GetBytes("getFile:" + fileName);
byte[] getFileResponse;
string fileContent;
stream = client.GetStream();
stream.Write(getFile, 0, getFile.Length);
getFileResponse = new byte[client.ReceiveBufferSize];
stream.Read(getFileResponse, 0, client.ReceiveBufferSize);
fileContent = Encoding.UTF8.GetString(getFileResponse);
textBoxEditor.Enabled = true;
textBoxEditor.Text = fileContent;
}
}
First I call XMLFile.getFileList and Iít works good. Then I want to call XMLFile.getFile, after that the app stops.
What is wrong?
It is hard to tell the single root cause, but at least there is a conceptual problem: the result of the Stream.Read Method call, the actual number of bytes read, is ignored.
The send/receive functions of socket does not guarantee that all the data you provided will be sent/received at one call. The functions return actual number of sent/received bytes.
-- TCP/IP client-server application: exchange with string messages, Sergey Brunov.
Also, please note:
You must close the NetworkStream when you are through sending and receiving data. Closing TcpClient does not release the NetworkStream.
-- TcpClient.GetStream Method, MSDN.
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.