I want to send data over tcp to a specific ip\port I've written a sample which should send there some string:
internal class TcpSender : BaseDataSender
{
public TcpSender(Settings settings) : base(settings)
{
}
public async override Task SendDataAsync(string data)
{
Guard.ArgumentNotNullOrEmptyString(data, nameof(data));
byte[] sendData = Encoding.UTF8.GetBytes(data);
using (var client = new TcpClient(Settings.IpAddress, Settings.Port))
using (var stream = client.GetStream())
{
await stream.WriteAsync(sendData, 0, sendData.Length);
}
}
}
The issue here that my stream is disposed before tcp client have sent all the data. How should I rewrite my code to wait all data to be written and only after that dispose all resources? Thanks
UPD: called from console util:
static void Main(string[] args)
{
// here settings and date are gotten from args
try
{
GenerateAndSendData(settings, date)
.GetAwaiter()
.GetResult();
}
catch (Exception e)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(e);
}
}
public static async Task GenerateAndSendData(Settings settings, DateTime date)
{
var sender = new TcpSender(settings);
await sender.SendDataAsync("Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.");
}
Upd2: Echo server code (was stolen from some stackoverflow question):
class TcpEchoServer
{
static TcpListener listen;
static Thread serverthread;
public static void Start()
{
listen = new TcpListener(System.Net.IPAddress.Parse("127.0.0.1"), 514);
serverthread = new Thread(new ThreadStart(DoListen));
serverthread.Start();
}
private static void DoListen()
{
// Listen
listen.Start();
Console.WriteLine("Server: Started server");
while (true)
{
Console.WriteLine("Server: Waiting...");
TcpClient client = listen.AcceptTcpClient();
Console.WriteLine("Server: Waited");
// New thread with client
Thread clientThread = new Thread(new ParameterizedThreadStart(DoClient));
clientThread.Start(client);
}
}
private static void DoClient(object client)
{
// Read data
TcpClient tClient = (TcpClient)client;
Console.WriteLine("Client (Thread: {0}): Connected!", Thread.CurrentThread.ManagedThreadId);
do
{
if (!tClient.Connected)
{
tClient.Close();
Thread.CurrentThread.Abort(); // Kill thread.
}
if (tClient.Available > 0)
{
byte pByte = (byte)tClient.GetStream().ReadByte();
Console.WriteLine("Client (Thread: {0}): Data {1}", Thread.CurrentThread.ManagedThreadId, pByte);
tClient.GetStream().WriteByte(pByte);
}
// Pause
Thread.Sleep(100);
} while (true);
}
}
The easy part is that the echo server works slowly because it pauses for 100ms after each read. I guess that's so you get a chance to see what's happening.
For why you don't see all the data, I'm not sure exactly, but what I think might be happening is:
using
block, the stream is disposed (thanks to Craig.Feied in his answer for pointing out that execution proceeds before the underlying sockets have finished the physical transmission of the data)NetworkStream
causes it to issue a shutdown to the underlying Socket
Socket
to finish sending any buffered data before it finally closes. Reference: Graceful Shutdown, Linger Options, and Socket ClosureNetworkStream
itself as it passes all writes directly to the socket. So even if the NetworkStream is disposed before the transfer completes no data is lostSo, your echo server receives data from the transfer already in progress (okay) but then issues a new write request on the connection (not okay.) I suspect this write is causing the echo server to exit early without reading all the data. Either:
tClient.GetStream().WriteByte(pByte);
It should be easy to check if it is indeed either of the above.