C# - Get error result by sending images via NetworkStream - c#

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.

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());
}
}

My .NET tcp server application will randomly use 100% CPU

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");
}
}

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);
}

Socket server accepts only first call

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.

Respond to a client using a socket?

I have two basic console apps that communicate "over the network" even though all of the communication takes place on my local machine.
Client code:
public static void Main()
{
while (true)
{
try
{
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 500);
Console.WriteLine("Connected.");
byte[] data = ASCIIEncoding.ASCII.GetBytes(new FeederRequest("test", TableType.Event).GetXmlRequest().ToString());
Console.WriteLine("Sending data.....");
using (var stream = client.GetStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
Console.WriteLine("Data sent.");
}
client.Close();
Console.ReadLine();
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
}
Server code:
public static void Main()
{
try
{
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
Console.WriteLine("Starting TCP listener...");
TcpListener listener = new TcpListener(ipAddress, 500);
listener.Start();
Console.WriteLine("Server is listening on " + listener.LocalEndpoint);
while (true)
{
Socket client = listener.AcceptSocket();
Console.WriteLine("\nConnection accepted.");
var childSocketThread = new Thread(() =>
{
Console.WriteLine("Reading data...\n");
byte[] data = new byte[100];
int size = client.Receive(data);
Console.WriteLine("Recieved data: ");
for (int i = 0; i < size; i++)
Console.Write(Convert.ToChar(data[i]));
//respond to client
Console.WriteLine("\n");
client.Close();
Console.WriteLine("Waiting for a connection...");
});
childSocketThread.Start();
}
}
catch (Exception e)
{
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
How can I alter both of these applications so that when the Server has received the data, it responds to the Client with some kind of confirmation?
Thanks in advance!
Here a short example how I would do it:
Server:
class Server
{
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 1500);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
// Create BinaryWriter for writing to stream
BinaryWriter binaryWriter = new BinaryWriter(stream);
// Creating BinaryReader for reading the stream
BinaryReader binaryReader = new BinaryReader(stream);
while (true)
{
// Read incoming information
byte[] data = new byte[16];
int receivedDataLength = binaryReader.Read(data, 0, data.Length);
string stringData = Encoding.ASCII.GetString(data, 0, receivedDataLength);
// Write incoming information to console
Console.WriteLine("Client: " + stringData);
// Respond to client
byte[] respondData = Encoding.ASCII.GetBytes("respond");
Array.Resize(ref respondData, 16); // Resizing to 16 byte, because in this example all messages have 16 byte to make it easier to understand.
binaryWriter.Write(respondData, 0, 16);
}
}
}
Client:
class Client
{
private static void Main(string[] args)
{
Console.WriteLine("Press any key to start Client");
while (! Console.KeyAvailable)
{
}
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 1500);
NetworkStream networkStream = client.GetStream();
// Create BinaryWriter for writing to stream
BinaryWriter binaryWriter = new BinaryWriter(networkStream);
// Creating BinaryReader for reading the stream
BinaryReader binaryReader = new BinaryReader(networkStream);
// Writing "test" to stream
byte[] writeData = Encoding.ASCII.GetBytes("test");
Array.Resize(ref writeData, 16); // Resizing to 16 byte, because in this example all messages have 16 byte to make it easier to understand.
binaryWriter.Write(writeData, 0, 16);
// Reading response and writing it to console
byte[] responeBytes = new byte[16];
binaryReader.Read(responeBytes, 0, 16);
string response = Encoding.ASCII.GetString(responeBytes);
Console.WriteLine("Server: " + response);
while (true)
{
}
}
}
I hope this helps! ;)
You can perform both Read and Write on the same stream.
After you send all the data over, just call stream.Read as in
using (var stream = client.GetStream())
{
stream.Write(data, 0, data.Length);
stream.Flush();
Console.WriteLine("Data sent.");
stream.Read(....); //added sync read here
}
MSDN documentation on TcpClient has an example as well http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
If you want feed back such as reporting # of bytes received so far, you'll have to use async methods.
Here's an example of what (I think) you want to do:
static void Main(string[] args) {
var server = new Task(Server);
server.Start();
System.Threading.Thread.Sleep(10); // give server thread a chance to setup
try {
TcpClient client = new TcpClient();
client.Connect("127.0.0.1", 1500);
Console.WriteLine("Connected.");
var data = new byte[100];
var hello = ASCIIEncoding.ASCII.GetBytes("Hello");
Console.WriteLine("Sending data.....");
using (var stream = client.GetStream()) {
stream.Write(hello, 0, hello.Length);
stream.Flush();
Console.WriteLine("Data sent.");
// You could then read data from server here:
var returned = stream.Read(data, 0, data.Length);
var rec = new String(ASCIIEncoding.ASCII.GetChars(data, 0, data.Length));
rec = rec.TrimEnd('\0');
if (rec == "How are you?") {
var fine = ASCIIEncoding.ASCII.GetBytes("fine and you?");
stream.Write(fine, 0, fine.Length);
}
}
client.Close();
Console.ReadLine();
}
catch (Exception e) {
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
public static void Server() {
try {
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
Console.WriteLine("*Starting TCP listener...");
TcpListener listener = new TcpListener(ipAddress, 1500); // generally use ports > 1024
listener.Start();
Console.WriteLine("*Server is listening on " + listener.LocalEndpoint);
Console.WriteLine("*Waiting for a connection...");
while (true) {
Socket client = listener.AcceptSocket();
while (client.Connected) {
Console.WriteLine("*Connection accepted.");
Console.WriteLine("*Reading data...");
byte[] data = new byte[100];
int size = client.Receive(data);
Console.WriteLine("*Recieved data: ");
var rec = new String(ASCIIEncoding.ASCII.GetChars(data, 0, size));
rec = rec.TrimEnd('\0');
Console.WriteLine(rec);
if (client.Connected == false) {
client.Close();
break;
}
// you would write something back to the client here
if (rec == "Hello") {
client.Send(ASCIIEncoding.ASCII.GetBytes("How are you?"));
}
if (rec == "fine and you?") {
client.Disconnect(false);
}
}
}
listener.Stop();
}
catch (Exception e) {
Console.WriteLine("Error: " + e.StackTrace);
Console.ReadLine();
}
}
}
Keep in mind that data sent via sockets can arrive fragmented (in different packets). This doesn't usually happen with the packets are small.

Categories

Resources