ReadToEnd from a TCP Client - c#

I am using utility in c# that helps me connect via telnet on a remote unix server ( http://www.codeproject.com/KB/IP/MinimalisticTelnet/MinimalisticTelnet.zip ) This utility, uses a function called Write to write in the shell.
TcpClient tcpSocket;
public void Write(string cmd)
{
if (!tcpSocket.Connected)
return;
byte[] buf = System.Text.ASCIIEncoding.ASCII.GetBytes(cmd.Replace("\0xFF","\0xFF\0xFF"));
tcpSocket.GetStream().Write(buf, 0, buf.Length);
}
An other function is called to read the output :
public string Read()
{
if (!tcpSocket.Connected)
return null;
StringBuilder sb=new StringBuilder();
do
{
ParseTelnet(sb);
System.Threading.Thread.Sleep(TimeOutMs);
} while (tcpSocket.Available > 0);
return sb.ToString();
}
This function does return the output of the command, but since the commands can last very long time, it cannot return all the output that I need since it quits before the execution finishes. I can't do Thread.Sleep(time) because the execution time is not constant for all the commands.
Is there any way to force the code to read the data till the end with TcpClient ? Thank you!

The solution was this :
public string WriteCommandOverTcp(string cmd)
{
string response = "";
using (NetworkStream stream = tcpSocket.GetStream())
{
using (StreamWriter writer = new StreamWriter(stream))
{
writer.AutoFlush = true;
using (StreamReader reader = new StreamReader(stream))
{
writer.WriteLine(cmd);
// If I comment the line below, the server receives the first message
// otherwise it keeps waiting for data
response = reader.ReadLine();
}
}
}
return response;
}
I stumbled on the solution when I heard about the NetworkStream API and it was the solution to read a stream till the end from the Network.

Related

XML Serialization over TCP Issues

Just testing a simple example program, for sending an XML Serialized object over TCP. I'm finding that unless I close the stream or TcpClient on the side that sends a serialized object, the receiver never receives it.
class Program
{
private static XmlSerializer positionSerializer = new XmlSerializer(typeof(GazePosition));
static void Main(string[] args)
{
new Thread(Server).Start();
new Thread(Client).Start();
Console.ReadLine();
}
static void Server()
{
TcpListener listener = new TcpListener(IPAddress.Loopback, 30000);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
Stream stream = client.GetStream();
StreamReader reader = new StreamReader(stream);
var cmd = reader.ReadLine();
if (cmd == "GetPosition")
{
Console.WriteLine("Received GetPosition Command");
GazePosition pos = new GazePosition(-5, 5);
positionSerializer.Serialize(stream, pos);
}
//client.Close();
listener.Stop();
}
static void Client()
{
TcpClient client = new TcpClient();
client.Connect(IPAddress.Loopback, 30000);
Stream stream = client.GetStream();
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine("GetPosition");
writer.Flush();
var pos = (GazePosition)positionSerializer.Deserialize(stream);
Console.WriteLine("Received: {0}", pos);
stream.Close();
client.Close();
}
}
[Serializable]
[XmlRoot("GazePosition")]
public class GazePosition
{
[XmlElement("X")]
public float X;
[XmlElement("Y")]
public float Y;
public GazePosition()
{
}
public GazePosition(float x, float y)
{
X = x;
Y = y;
}
public override string ToString()
{
return string.Format("{0},{1}", X, Y);
}
}
This prints out only:
Received GetPosition command
However, if I uncomment client.Close()
This prints out:
Received GetPosition command
Received -5, 5
I would like this example be able to scale to receiving multiple commands, but this is painful while I'm forced to close the stream each time I receive a command. If someone could enlighten me why this is happening, I would be very thankful!
Here what you are missing is that you are supposed to read from the TcpClient's stream on the client side. Please have a look what I simply did to get it to work. Please keep in mind that this is simply an example.
writer.WriteLine("GetPosition");
writer.Flush();
//Just like you did you should seperate the payload
//Either by size or new line or some special key you set
byte[] buffer = new byte[1024];
stream.Read(buffer, 0, buffer.Length);
using (var ms = new MemoryStream(buffer))
{
var gazePos = (GazePosition)positionSerializer.Deserialize(ms);
//DOSTUFF
}
//Added code finished
Here is some simple beta level library. You may want to have a look→
Simple Server
Edit: I further looked at NetworkStream's Dispose method. It has native calls to Windows API so I am not able to further into implementation details.However, as you can see here, during a graceful shutdown, which occurs when you dispose a network stream, sends a FD_CLOSE

How to wait for response from NamedPipeServer?

I have the following client code, that I write stuff to my Server pipe, I was able to read it on the Server side but before I could reply back, the client would already try to read the still empty pipe. How do you wait on the NamedPipeClientStream?
using (NamedPipeClientStream pipe = new NamedPipeClientStream(".", pipename, PipeDirection.InOut))
{
pipe.Connect(5000);
pipe.ReadMode = PipeTransmissionMode.Byte;
byte[] ba = Encoding.Default.GetBytes("hello world");
pipe.Write(ba, 0, ba.Length);
var result = await Task.Run(() => {
// this would return as soon as Server finished reading
// but then server hasn't wrote anything back yet
pipe.WaitForPipeDrain();
// sample code on how i am planning to read, not tested,
// since the pipe is still empty at this point
using (StreamReader reader = new StreamReader(pipe))
using (MemoryStream ms = new MemoryStream())
{
reader.BaseStream.CopyTo(ms);
return Encoding.Default.GetString(ms.ToArray());
}
});
return result;
}
I don't think I should be using WaitForPipeDrain but then there are no other options for my to wait, or to know when is ready to read? There are many examples out there, but none of them shows the proper way for the client to wait for a response.
The example shown from Microsoft seems to be using ReadLine() and leveraging EOL character when you send string data, but I'm dealing with byte[] data ("hello world" is just to get some bytes).
You don't need to wait for data. NamedPipeClientStream represents a stream of bytes (it derives from System.IO.Stream) and if no data is currently available, reading from pipe (or from StreamReader that wraps that pipe) will simply block until data arrives.
For transfering textual data, reading with StreamReader.ReadLine() and writing with StreamWriter.WriteLine() will work fine. To transfer binary data, you can either encode binary data into textual form (for example using base64 encoding) and keep using StreamReader.ReadLine() / StreamWriter.WriteLine(). Or you can set server and client pipes into PipeStream.TransmissionMode to Message mode, and transfer each byte array as a single message, as follows (error checks omitted for brevity):
Client:
class Client
{
static async Task Main(string[] args)
{
using (NamedPipeClientStream pipe = new NamedPipeClientStream(".", "testpipe", PipeDirection.InOut))
{
pipe.Connect(5000);
pipe.ReadMode = PipeTransmissionMode.Message;
byte[] ba = Encoding.Default.GetBytes("hello world");
pipe.Write(ba, 0, ba.Length);
var result = await Task.Run(() => {
return ReadMessage(pipe);
});
Console.WriteLine("Response received from server: " + Encoding.UTF8.GetString(result));
Console.ReadLine();
}
}
private static byte[] ReadMessage(PipeStream pipe)
{
byte[] buffer = new byte[1024];
using (var ms = new MemoryStream())
{
do
{
var readBytes = pipe.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, readBytes);
}
while (!pipe.IsMessageComplete);
return ms.ToArray();
}
}
}
Server:
class Server
{
static void Main(string[] args)
{
using (NamedPipeServerStream pipeServer = new NamedPipeServerStream(
"testpipe",
PipeDirection.InOut,
NamedPipeServerStream.MaxAllowedServerInstances,
PipeTransmissionMode.Message))//Set TransmissionMode to Message
{
// Wait for a client to connect
Console.Write("Waiting for client connection...");
pipeServer.WaitForConnection();
Console.WriteLine("Client connected.");
//receive message from client
var messageBytes = ReadMessage(pipeServer);
Console.WriteLine("Message received from client: " + Encoding.UTF8.GetString(messageBytes));
//prepare some response
var response = Encoding.UTF8.GetBytes("Hallo from server!");
//send response to a client
pipeServer.Write(response, 0, response.Length);
Console.ReadLine();
}
}
private static byte[] ReadMessage(PipeStream pipe)
{
byte[] buffer = new byte[1024];
using (var ms = new MemoryStream())
{
do
{
var readBytes = pipe.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, readBytes);
}
while (!pipe.IsMessageComplete);
return ms.ToArray();
}
}
}

Unity .net socket + protobuf issues

Currently I'm trying to develop a multiplayer game with Unity. I checked the Unity's built-in Network and NetworkManager but I need the server dedicated. Hence I developed a java server and implements the protolbuf which is provided by Google. It works with my cocos project but not with this Unity one.
Two problems, first, no matter what did I send to server, the server side has a InvalidProtolBufferException :
While parsing a protocol message, the input ended unexpectedly in the middle > of a field. This could mean either than the input has been truncated or that > embedded message misreported its own length.
second, the stream.read method always makes my unity not responding. Here is my client-side code:
public class SocketClient : MonoBehaviour {
public Text send;
public Text read;
const string ipAddress = "192.168.0.233";
const int port = 8080;
TcpClient socket;
NetworkStream stream;
BinaryWriter bw;
BinaryReader br;
// Use this for initialization
void Start () {
SetupSocket();
}
void SetupSocket() {
socket = new TcpClient(ipAddress, port);
stream = socket.GetStream();
bw = new BinaryWriter(socket.GetStream());
br = new BinaryReader(socket.GetStream());
}
// Update is called once per frame
void Update () {
ReadMessage();
}
public void SendMessage() {
//NetworkStream stream = new NetworkStream(socket.Client);
MessagesProto msg = new MessagesProto();
msg.id = int.Parse(send.text);
using (MemoryStream ms = new MemoryStream())
{
Serializer.Serialize<MessagesProto>(ms, msg);
ms.Position = 0;
byte[] data = ms.ToArray();
ms.Position = 0;
//foreach (byte d in data) {
// Debug.Log(d);
//}
stream.Write(data, 0 , data.Length);
}
}
public void ReadMessage() {
if (stream.CanRead) {
//byte[] receiveData = new byte[socket.ReceiveBufferSize];
byte[] receiveData = new byte[4];
socket.GetStream().Read(receiveData, 0, 4);
Debug.Log("Loading...");
using (MemoryStream ms = new MemoryStream()) {
ms.Write(receiveData, 0, receiveData.Length);
ms.Position = 0;
var msg = Serializer.Deserialize<MessagesProto>(ms);
read.text = msg.data + "";
}
}
}
}
I tried to set the stream.CanRead to stream.DataAvailable, no more crash but not reading anything either, these .Net sockets problems drive me crazy, anyone can help me with this please?
It is not responding because your socket code is synchronous(blocking). You can solve this by either using asynchronous version of the socket functions or use Thread to do all your receiving stuff. This has been answered many times and I will just link to the answers.
TCP Server in Unity
Just port the code to Client.
UDP.

Can I read the stream from TcpClient in a better way?

I have a system where in one end I have a device communicating with a module via RS-232.
The module is connected to a PC via TCP, and translates TCP messages to RS-232 and vice versa.
This is how I do it:
I read out every byte on the stream
build a string
compare the latter part of the string to a delimiter
then I stop reading the stream (and fire an event, though not shown here).
My current code for handling this is
string delimiter = "\r\n";
byte[] reply = new byte[1];
string replyString = string.Empty;
bool readOk = true;
int dl = delimiter.Length;
bool delimiterReached = false;
do
{
try
{
stream.Read(reply, 0, 1);
}
catch (Exception e)
{
readOk = false;
break;
}
replyString += Encoding.ASCII.GetString(reply, 0, reply.Length);
int rl = replyString.Length;
if (rl > dl)
{
string endString = replyString.Substring(rl-dl, dl);
if (endString.Equals(delimiter))
delimiterReached = true;
}
} while (!delimiterReached);
where stream is the TcpClient.GetStream()
I don't much care for the constant string building, so I was wondering if there is a better way of doing this?
Once the TCP connection is established, wrap the TcpClient stream in a StreamReader:
var reader = new StreamReader( stream, Encoding.ASCII );
Since your delimiter is \r\n, StreamReader.ReadLine will read a complete message:
var reply = reader.ReadLine();
Be careful to create the StreamReader once per TCP connection; it may read and buffer additional data from the underlying TCP stream for efficiency.

Using pipes for IPC in same process using C#

I have two threads. One threads reads requests and passes it to server using message queue and other thread reads the response from message queue and sends it back. In the same process the caller class method writes the request on the pipe (using the server pipe stream shared by first thread) and then reads the response using the client pipe stream shared by the second thread. This can be easily done using Java PipeInputStream and PipeOutputStream as follows. Essentially I am looking for equivalent of following Java logic in C#. I tried unsuccessfully using anonymous pipes in C#.
RequestHandlerThread (Thread1 as mentioned above)
out = new PipedOutputStream();
readPipeIs = new PipedInputStream(out);
readDataIs = new DataInputStream(readPipeIs);
// read data from readDataIs
// Send it to server over message queue
// Share 'out' so that other class method can write to it.
Response Handler (Thread 2 as mentioned above)
in = new PipedInputStream();
writePipeOs = new PipedOutputStream(in);
writeDataOs = new DataOutputStream(writePipeOs);
// Wait and read from message queue
// write received data to 'writeDataOs'
// Share 'in' so that other class method can read from it.
I am not sure if C# pipes are restricted for communicating between two processes. All the above logic is in same process just that there are two threads to communicate with message server.
I tried pair of AnonymousPipeServerStream and AnonymousPipeClientStream pair in both threads. I shared the server stream for writing and client stream for reading by other class method.
Any obvious flaw in above logic or any suggestions with choice of IPC ?
Adding source code
Here is the Test class
class Test
{
private static byte[] ret;
private static bool ready;
Stream outStream;
Stream inStream;
private void clientConnReqHandler()
{
AnonymousPipeServerStream pipeServer = new
AnonymousPipeServerStream(PipeDirection.Out);
outStream = pipeServer;
string pipeHandle =
pipeServer.GetClientHandleAsString();
AnonymousPipeClientStream pipeClient =
new AnonymousPipeClientStream(PipeDirection.In,
pipeHandle);
pipeServer.DisposeLocalCopyOfClientHandle();
ready = false;
BinaryReader binReader = new BinaryReader(pipeClient);
int mesgSize = binReader.ReadInt32();
System.Console.WriteLine("Message Lenght To read: " +
mesgSize);
byte[] buffer = binReader.ReadBytes(mesgSize);
System.Console.WriteLine("Message read: " +
buffer.ToString());
// Simulate some processing
Thread.Sleep(5000);
mesgProcessing(buffer);
}
private static void mesgProcessing(byte[] buffer)
{
System.Text.UTF8Encoding encoding = new
System.Text.UTF8Encoding();
byte[] extra = encoding.GetBytes("Echo : ");
ret = new byte[buffer.Length + extra.Length];
System.Buffer.BlockCopy(extra, 0, ret, 0, extra.Length);
System.Buffer.BlockCopy(buffer, 0, ret, extra.Length,
buffer.Length);
ready = true;
}
private void clientConnRespHandler()
{
AnonymousPipeServerStream pipeServer = new
AnonymousPipeServerStream(PipeDirection.Out);
string pipeHandle =
pipeServer.GetClientHandleAsString();
AnonymousPipeClientStream pipeClient =
new AnonymousPipeClientStream(PipeDirection.In,
pipeHandle);
inStream = pipeClient;
pipeServer.DisposeLocalCopyOfClientHandle();
while (ready)
{
BinaryWriter binWriter = new
BinaryWriter(pipeServer);
binWriter.Write(ret.Length);
binWriter.Write(ret);
ready = false;
}
}
public static void Main()
{
Test setup = new Test();
setup.threadTest();
Test2 threadTest = new Test2();
// This method will do actuall read and write.
threadTest.runTest(setup.inStream, setup.outStream);
}
public void threadTest()
{
Thread reqHandlerThread = new Thread(new
ThreadStart(clientConnReqHandler));
Thread respHandlerThread = new Thread(new
ThreadStart(clientConnRespHandler));
reqHandlerThread.Start();
respHandlerThread.Start();
}
}
The class that does read/write:
class Test2
{
internal void runTest(System.IO.Stream inStream,
System.IO.Stream outStream)
{
BinaryWriter writer = new BinaryWriter(outStream);
System.Text.UTF8Encoding encoding = new
System.Text.UTF8Encoding();
byte[] mesg = encoding.GetBytes("Hello World!!!");
writer.Write(mesg.Length);
writer.Write(mesg);
BinaryReader reader = new BinaryReader(inStream);
int mesgSize = reader.ReadInt32();
System.Console.WriteLine("Message Lenght To read: " +
mesgSize);
byte[] buffer = reader.ReadBytes(mesgSize);
System.Console.WriteLine("Message read: " +
buffer.ToString());
}
}
thanks
OK. It worked after getting rid of DisposeLocalCopyOfClientHandle(). Of course had to fix some new-by mistakes of while loop condition to check if the data is ready and printing the string correctly from byte array.

Categories

Resources