Client side:
Something like my code:
var socket = Connect();
var reader = new BinaryReader(socket.GetStream());
var writer = new BinaryWriter(socket.GetStream());
// In other thread
writer.Write((byte) 5);
writer.Write("C:\\no-file.exe");
var exists = reader.ReadBoolean();
Stuck in System.Net.Sockets.Socket.Receive
:
// Decompiled with JetBrains decompiler
UnsafeNclNativeMethods.OSSOCK.recv(this.m_Handle.DangerousGetHandle(), numPtr + offset, size, socketFlags);
I can see packet with my boolean value in WireShark, but ReadBoolean
still executing and socket.Available
equals zero.
Server prototype:
Minimal code that acts like a real server and causes the same problem.
var server = new TcpListener(IPAddress.Any, 2386);
server.Start();
var socket = server.AcceptTcpClient();
socket.NoDelay = true;
Console.WriteLine("Connected: " + socket.Client.RemoteEndPoint);
var stream = socket.GetStream();
var reader = new BinaryReader(stream);
var writer = new BinaryWriter(stream);
while (socket.Connected) {
while (!stream.DataAvailable);
if (stream.ReadByte() != 5) {
break;
}
var path = reader.ReadString();
Console.WriteLine("Requested file " + path);
var exists = File.Exists(path);
writer.Write(exists);
writer.Flush();
Console.WriteLine(exists ? "File exists" : "Not found");
}
Console.WriteLine("Disconnected: " + socket.Client.RemoteEndPoint);
I found in my code that I have other thread that stole my boolean.
// TcpClient thread inside Connect method
while (client.Connected) {
DispatchPacketType(stream.ReadByte());
}
// Thread that calls Connect
reader.ReadBoolean(); // stuck!
EDIT:
So I made
WaitPacket
method to fix this problem. Not the best solution, but this works.
Making special waiting method was completely wrong, because it caused a lot of problems. The only one normal decision is project refactoring.
In same case you can try:
DispatchPacketType
). Now client sends packet's type byte, its contents and reads server reply in same method (ex. FetchSomeData
), because server (in my situation) responds sequentially.TCPClient
from multiple threads or use lockers as mentioned @500-Internal Server Error in his comment. I rewrote many lines of code and now it works more safier and performant.