I have been following this tutorial "http://tech.pro/tutorial/704/csharp-tutorial-simple-threaded-tcp-server" on setting up a mini server that can send and receive messages and have multiple clients connected.
Everything is working which is great.. but unfortunately one thing that is missing in this tutorial is how the client can set up a listener to listen to the server.
I have only this much:
public void SetupReceiver()
{
TcpClient tcpClient = new TcpClient(this.Host, this.Port);
NetworkStream networkStream = tcpClient.GetStream();
// What next! :( or is this already wrong...
}
As far as I can imagine.. I would need to connect to the server (As a TcpClient) and get the stream (Like above). And then wait for messages and do something with it. The reason I cannot just have the client receive a message back from the server immediately after sending one is because the client will send a message to the server, and then that message will be broadcast to all the clients that are connected. So each client needs to be "listening" for messages from the server.
The TCPclient class has the necessary resources to enable a connection, send and receive data to and from the server and the TCPListener class is essentially the server.
Following the general example provided in the msdn page for TCPclient and can also be used for TCPListener (of which my generalised explanation is based on!)
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient%28v=vs.110%29.aspx
The first part is to send data to the server:
// Translate the passed message into ASCII and store it as a Byte array.
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
// Get a client stream for reading and writing.
NetworkStream stream = client.GetStream();
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length); //(**This is to send data using the byte method**)
The following part is to receive data from the server:
// Buffer to store the response bytes.
data = new Byte[256];
// String to store the response ASCII representation.
String responseData = String.Empty;
// Read the first batch of the TcpServer response bytes.
Int32 bytes = stream.Read(data, 0, data.Length); //(**This receives the data using the byte method**)
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes); //(**This converts it to string**)
The byte method can be replaced with streamreader and streamwriter once they have been linked to the networkstream
Hope this helps!!
**PS: If you would like a more versatile coding experience with networking classes in c#, i would personally recommend looking into using sockets as it is the main class from which the tcpclient and tcplistener are born.
Related
I want to send a string converted in byte but i don't know how to do that. I already tried to modify buffer and byteread but the server is just broken.
private void Server(string ip, int port)
{
BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate (object s, DoWorkEventArgs args)
{
//---listen at the specified IP and port no.---
IPAddress localAdd = IPAddress.Parse(ip);
TcpListener listener = new TcpListener(localAdd, port);
Console.WriteLine("Listening...");
listener.Start();
while (true)
{
//---incoming client connected---
TcpClient client = listener.AcceptTcpClient();
//---get the incoming data through a network stream---
NetworkStream nwStream = client.GetStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
//---read incoming stream---
int bytesRead = nwStream.Read(buffer, 0, client.ReceiveBufferSize);
//---convert the data received into a string---
string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received : " + dataReceived);
//---write back the text to the client---
Console.WriteLine("Sending back : " + dataReceived);
nwStream.Write(buffer, 0, bytesRead); // How do i send back a string ??
client.Close();
}
};
worker.RunWorkerAsync();
}
You already are sending back the bytes that represent the same string (via ASCII) that you received in the first Read, then closing the socket. Note: if you intended to send back the bytes for a different string value: Encoding.ASCII or Encoding.Utf8 are your friends; the process of converting between string data and byte data (for transmission or storage) is exactly what an Encoding does. You're already using this with GetString(...); the reverse operation is GetBytes(...) (with various overloads for using pooled buffers etc).
If this isn't working as intended, we'd need a lot more detail. In particular, TCP is a stream protocol; data isn't terminated inherently (like it would be in UDP packets, for example), so there is no guarantee whatsoever that you've received a logical unit of string data in your Read - all we know is that one Read has completed. This could return zero bytes (indicating EOF, i.e. the other end didn't send anything and closed their outbound socket), one byte, or a few thousand bytes - but: except for the EOF case, that tells us nothing about whether we have an entire "message". In fact, if you were using UTF8 rather than ASCII, we might not even have an entire character - we could have partial/incomplete character data.
So if the "other end" is trying to send us a paragraph of data, we might have received the first word-and-a-half; you then send back the same word-and-a-half, and terminate the connection. We have never seen the rest of the data. Whether this is what you want is unclear, but seems unlikely. That's assuming this actually is a text-based protocol!
For this reason, usually any network protocol includes framing details to tell us how to identify logical units of data in the stream. For a text protocol this might be looking for sentinel characters like CR/LF/NUL; for a binary protocol, this usually takes the form of some header that tells us the number of bytes in the data frame in a well-defined format ("big endian int32", "varint", etc), followed by that same number of bytes. The caller then buffers appropriately so that they're processing only entire frames.
So: in theory you're already sending something back (unless it was EOF), but without the protocol details: we can't say whether than means anything.
I have an exe which simulates a video stream. I connect to it and very occasionally read the expected data, but usually I get only the first 28 bytes and then 65508 bytes of zeros. Assume the video stream is working correctly.
TcpClient tcpClient = new TcpClient ();
int port = 13000;
myIP = IPAddress.Loopback.ToString();
tcpClient.Connect (myIP, port);
NetworkStream netStream = tcpClient.GetStream ();
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
netStream.Read (bytes, 0, (int)tcpClient.ReceiveBufferSize);
string dataString = Encoding.ASCII.GetString (bytes);
Console.WriteLine("\ndataString: "+dataString.Substring(0,1000));
Console.WriteLine("\nnumber of bytes read: "+bytes.Length);
tcpClient.Close ();
// Closing the tcpClient instance does not close the network stream.
netStream.Close();
How can I make it so that I get the expected output every time?
TCP represents a (bi-directional) stream of data. You're supposed to keep reading from it in a loop, and parsing the data as you need them. It doesn't have a concept of messages - ten writes on one side can result in a single read on the other side just as easily as one write on one side can result in ten reads on the other side.
The contract you have with TCP is as follows:
If there is data in the receive buffer, Read returns immediately, filling the buffer you provided with as much data as is available, up to the length of the buffer. The number of bytes read is the return value of Read.
If there is no data in the receive buffer, Read will block until there's at least a single byte of data. Then it follows as in the first case.
If the other sides shuts down the socket, Read will return zero.
So to get TCP working, you need a loop. How exactly you form the loop depends on what you're trying to do. If you're really working with data that is logically a stream (e.g. audio data), just keep reading as fast as you can and process whatever data you get as it comes in. If you need to send messages, you need to implement a message protocol. If you need a one-off message, you can just keep reading until Read returns zero.
Your case can be handled with the first approach - keep reading until the stream closes, and push the received data forward. Assuming the data is actually a UTF8 stream of text, the basic receiver would look something like this:
using (var client = new TcpClient())
{
tcpClient.Connect(myIP, port);
var stream = client.GetStream();
var buffer = new byte[4096]; // Adapt the size based on what you want to do with the data
var charBuffer = new char[4096];
var decoder = Encoding.UTF8.GetDecoder();
int bytesRead;
while ((bytesRead = stream.Read(buffer, 0, buffer.Length)) != 0)
{
var expectedChars = decoder.GetCharCount(buffer, 0, bytesRead);
if (charBuffer.Length < expectedChars) charBuffer = new char[expectedChars];
var charCount = decoder.GetChars(buffer, 0, bytesRead, charBuffer, 0);
Console.Write(new string(charBuffer, 0, charCount));
}
client.Close();
}
Note that this does no error handling, so don't use it as is in any production code. You would probably also want to use Async methods if you're expecting more than a few simultaneous connections. It's just to illustrate the basic way one would handle a stream of data being received over TCP.
If you want some more insight into dealing with TCP, I have a few very simple examples at https://github.com/Luaancz/Networking. I haven't found any good tutorials or code samples for C#, so if this isn't enough, you'll probably have to dig deeper into the documentation around sockets, TCP and all that.
Or just use an existing networking library, rather than trying to write your own :) TCP is still very low level.
I created a client in Java and I want simply to send some data to my server that is in C#.
The problem is that if I write in the client for example hello, I get only the first letter. In the byte array there is only one element.
I guess there is some problem with the server side because in my server in JAVA works everything fine so the client in JAVA works fine.
Does anybody see any problem?
Thank you in advance.
You're thinking about TCP the wrong way, you don't simply "Receive" once and get the result of one "Send".
TCP is a "streaming" protocol and does not automatically separate into "packets". You may even get data of 2 sends in one receive.
A common pattern is to prefix one message with its length, so you can call receive until you get the amount of bytes requested. To make Receive return immediately if no data is in the buffer, set your socket to non-blocking.
Here's another good article on the topic.
Now, your provided code should work either way because there is next to no latency on local networks. Have you checked if your Java part buffers steam / can you manually flush them?
As Damon Gant said, TCP is a streaming protocol. I suggest you create your own protocol. I wouldn't send strings. If you're doing anything non-trivial this is really the best way to go.
Typically I include a magic number, checksum, packet body length in bytes, and protocol version in my protocol headers. The magic number makes it easier to delineate packets in a stream (very useful for debugging your custom protocol stream.) Having a checksum helps ensure you're parsing things correctly. A checksum doesn't help much with integrity over TCP as the TCP protocol already has a checksum. The packet body length helps you detect when you have all the bytes for your packet. The protocol version can help you know how to interpret the packet body's bytes.
Upon receiving data, place all bytes into a separate buffer and scan for your protocol header. If you can parse your header, check to see that packet's bytes are all present. If so, parse the packet. Repeat this process till you find an incomplete packet, or the buffer is empty.
For each packet you want to send, I'd create a class. When you want to send a packet, create and serialize the proper class, and prepend your protocol header for that class's bytes.
You could use Java's serializer, but if you've many client's connecting to a single server, you probably don't want to use Java for the server. This makes things difficult because now you need to implement a java serializer in another language. Because of this its typically better to either convert your packets into bytes by hand (tedious but simple,) OR you could write your own serializer using reflection. I'd suggest the latter for bigger projects.
problem is prabably in java side because your listener works fine.
I copy pasted your listener code in a test application.
Than I created another test applicationand send hello word and I listened it completely.
public static void sender()
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("192.168.2.236"), 30000);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("Hello Server!");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
Connection accepted from 192.168.2.236:22811
Recieved...
Hello Server!
Btw, this might be better listener.
public void listener()
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 30000);
tcpListener.Start();
TcpClient tcpClient = tcpListener.AcceptTcpClient();
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
Console.Write(encoder.GetString(message, 0, bytesRead));
}
tcpClient.Close();
}
In my windows service I need to stream data to a tcp server. I declared a global TcpClient and NetworkStream and initiate them when the service starts.
Every 30 seconds I go through an array of about 30-40 strings to send to the tcp server.
The send method looks like this:
private void sendMessage(string message)
{
Byte[] data = System.Text.Encoding.ASCII.GetBytes(message);
Globals._stream.Write(data, 0, data.Length);
if (Globals._responseEnabled)
{
data = new Byte[256];
String responseData = String.Empty;
Int32 bytes = Globals._stream.Read(data, 0, data.Length);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
if (Globals._logStream)
Globals._el.writeEventToWindowsLog("Received: " + responseData, "Info");
}
}
Problem is that every 30 seconds only a few packets are sent with all of the strings combined inside, I want the strings to be sent in one packet each.
So how do I get the NetworkStream.write method to send the packet immediately? If I declare a new TCPClient and NetworkStream each time I call the send method (about 60times per minute) the data is sent seperately, but thats not a very nice solution. I tried NetworkStream.flush but that wasnt working..
You should set the NoDelay property on the TcpClient to true;
When NoDelay is false, a TcpClient does not send a packet over the
network until it has collected a significant amount of outgoing data.
Because of the amount of overhead in a TCP segment, sending small
amounts of data is inefficient. However, situations do exist where you
need to send very small amounts of data or expect immediate responses
from each packet you send.
Since you're wrapping it in a stream, you may still need to flush the stream to send immediately.
I'm in the process of building a client/server based game for a project(feeling quite out my depth). I've been using TCPclient and a multi-threaded socket server. Everything is working fine at the moment but I have been using StreamReader and StreamWriter to communicate between both client and server.
I keep seeing examples like this for recieving data:
byte[] data = new byte[1024];
int recv = sock.ReceiveFrom(data, ref ep);
string stringData = Encoding.ASCII.GetString(data, 0, recv);
and this for sending:
byte[] data = Encoding.ASCII.GetBytes("This is a test message");
server.SendTo(data, iep);
I was wondering what are the benefits of using this over streamReader? Would using this also be buffering?
Thanks in advance.
It's just a different style. ReceiveFrom and SendTo are more Unix-style, and using a StreamReader is more of a .NET style. StreamReader would be of more use to you, as you could then pass it to other methods that accept a TextReader.
sendTo() and receiveFrom() are used for connection less sockets, that use UDP as the transport protocol. You can use Send() or Recieve() when using connection oriented or stream sockets that use TCP as the protocol.
StreamReader and StreamWriter are the classes of IO namespace that will help in solving the message boundary problem that come with TCP sockets.
Message boundary problem means that all send calls are not picked up in all receive calls.
To avoid the message boundary problem we use networkstream with streamreader and streamwriter.