TcpClient NetworkStream gets stuck until TcpClient closed - c#

I want to send messages between the server and the client through TcpClient. Here's my code. The client sends "HELLO" to the server, the server prints the message after receiving it, and sends "HI" to the client, the client prints the message after receiving it.
Note the code at (1) in the Client code, the program will be stuck here. If I remove this code, the program can run normally, but of course, the client cannot receive the response from the server. What's the problem and how to solve it? Thx.
Server
void Main()
{
var listener = new TcpListener(IPAddress.Any, 1234);
listener.Start();
var client = listener.AcceptTcpClient();
var rs = new StreamReader(client.GetStream());
var msg = rs.ReadLine();
Console.WriteLine($"RECEIVED: {msg}");
var ws = client.GetStream();
var data = Encoding.ASCII.GetBytes("HI");
ws.Write(data, 0, data.Length);
client.Close();
}
Client
void Main()
{
var client = new TcpClient();
client.Connect(IPAddress.Parse("127.0.0.1"), 1234);
var ws = client.GetStream();
var data = Encoding.ASCII.GetBytes("HELLO");
ws.Write(data, 0, data.Length);
var msg = "nothing";
msg = new StreamReader(client.GetStream()).ReadLine(); //(1)
Console.WriteLine($"RECEIVED: {msg}");
client.Close();
}

Related

Tcp connection fails on LAN

I am trying to send a message from my laptop to my desktop over the LAN.
I have written a Tcp server that listens for a connection on a port, and a client that tries to connect to it and send a simple string as a message.
Server:
void Listen()
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
while (true)
{
Debug.Log($"listening to {listener.LocalEndpoint}...");
var socket = listener.AcceptSocket();
Debug.Log("connected!");
var bytes = new byte[100];
int k = socket.Receive(bytes);
var data = Encoding.ASCII.GetString(bytes, 0, k);
Debug.Log(data);
socket.Send(new byte[] {1});
Debug.Log("responded");
socket.Close();
Debug.Log("closed connection");
}
}
Client:
public void Send()
{
client = new TcpClient();
Debug.Log("connecting...");
client.Connect("192.168.0.12", port);
Debug.Log("connected!");
var data = Encoding.ASCII.GetBytes("Hello!");
var stream = client.GetStream();
Debug.Log("sending data");
stream.Write(data, 0, data.Length);
Debug.Log("data sent! waiting for response...");
var reply = new byte[100];
stream.Read(reply,0,100);
Debug.Log("received response");
client.Close();
}
They communicate correctly when they are both on the same machine, but the client never connects to the server when I am running it on a different machine.
I have a rule in my firewall that allows an incoming connection through the port I have specified.
I have tried it with both computer's firewalls off and the connection still doesn't go through.
Any help would be greatly appreciated.

Sending message from server and receive from the client end

Here is a sample server program written in c# which receives an id from a client. My sample code is given below. I want to send a string array to client and display is on the client console.
The sample array string can be:
string[] arr1 = new string[] { "one", "two", "three" };
What additional code I need to add with the following server and client code?
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace server
{
class Program
{
static void Main(string[] args)
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
int recv = ns.Read(data, 0, data.Length);
string id = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(id);
}
}
}
}
Since Tcp is a stream based protocol, I would suggest you use something higher level that plain byte[]. If all you need is to send strings from client to server and vice-versa, I think a StreamReader and a StreamWriter on both ends would work great. On the StreamWriter side, you've got a WriteLine(string) method to send to the client and the StreamReader has a similar method ReadLine().
Here's a simplification that you could apply to your model:
Server side:
TcpClient client; //Let's say it's already initialized and connected properly
StreamReader reader = new StreamReader(client.GetStream());
while(client.Connected)
{
string message = reader.ReadLine(); //If the string is null, the connection has been lost.
}
Client side:
TcpClient client; //Same, it's initialized and connected
StreamWriter writer = new StreamWriter(client.GetStream());
writer.AutoFlush = true; //Either this, or you Flush manually every time you send something.
writer.WriteLine("My Message"); //Every message you want to send
StreamWriter will end every message with a new line so that the StreamReader knows when the full string has been received.
Note that a TCP connection is a full-duplex connection. Meaning you can simultaneously send and receive data. Checkout the WriteLineAsync(string) and ReadLineAsync() methods if you want to implement something like this.
If you want to send arrays, establish a simple protocol looking a bit like this:
Send the length of the string[]. Example: writer.WriteLine(myArray.Length.ToString);
Receive and parse this length
Send all strings one after the other on the server side
Receive all strings in a for loop on the client side.
Once you received all strings, repeat the process.
Sending String Array to client
TcpListener tcpListener = new TcpListener(IPAddress.Any, 1234);
tcpListener.Start();
while (true)
{
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] data = new byte[1024];
NetworkStream ns = tcpClient.GetStream();
string[] arr1 = new string[] { "one", "two", "three" };
var serializer = new XmlSerializer(typeof(string[]));
serializer.Serialize(tcpClient.GetStream(), arr1);
tcpClient.GetStream().Close()
tcpClient.Close();
int recv = ns.Read(data, 0, data.Length);
in this line
string id = Encoding.ASCII.GetString(data, 0, recv);
Console.WriteLine(id);
}
}
Client
try
{
byte[] data = new byte[1024];
string stringData;
TcpClient tcpClient = new TcpClient("127.0.0.1", 1234);
NetworkStream ns = tcpClient.GetStream();
var serializer = new XmlSerializer(typeof(string[]));
var stringArr = (string[])serializer.Deserialize(tcpClient.GetStream());
foreach (string s in stringArr)
{
Console.WriteLine(s);
}
string input = Console.ReadLine();
ns.Write(Encoding.ASCII.GetBytes(input), 0, input.Length);
ns.Flush();
}
catch (Exception e)
{
Console.Write(e.Message);
}
Console.Read();

Failed to read an incomplete http request with NetworkStream

I have implemented a Server and Client with TcpListener and TcpClient.
Basically the server wait to a client connected to receive data and close, the client will connect, write and close too.
The problem is when I send an incomplete http request the server can't read it. For example "GET / HTTP/1.1\r\n" is incomplete because it must end with '\r\n' twice, but if i send "PET / HTTP/1.1\r\n" (is not an http request) the server read it fine. What's happened there?
This is my example code:
static void Main()
{
var message = #"GET / HTTP/1.1
";
var encodingMessage = message.Select(Convert.ToByte).ToArray();
// SERVER
var serverThread = new Thread(() =>
{
var tcpListener = new TcpListener(IPAddress.Parse("172.20.48.37"), 23000);
tcpListener.Start();
var tcpClient = tcpListener.AcceptTcpClient();
var networkStream = tcpClient.GetStream();
var buffer = new byte[250];
var bytesCount = networkStream.Read(buffer, 0, buffer.Length);
Console.WriteLine(#"received bytes: {0}", bytesCount); // print the received bytes
networkStream.Close();
networkStream.Dispose();
tcpClient.Close();
tcpListener.Stop();
});
serverThread.Start();
Thread.Sleep(3000);
// CLIENT
var client = new TcpClient();
client.Connect(new IPEndPoint(IPAddress.Parse("172.20.48.37"), 23000));
var stream = client.GetStream();
stream.Write(encodingMessage, 0, encodingMessage.Length);
stream.Close();
stream.Dispose();
client.Close();
}

Reading data from a TCP Socket not getting all of the data

I am working on a C# and android client/server application.
Android is sending a message to C# and I can see it is sending the correct data, however C# doesn't receive all of it.
Below is the code I have in C#
TcpListener tcpListener = new TcpListener(IPAddress.Any, serverTCPPort);
tcpListener.Start();
while (true)
{
tcpClient = tcpListener.AcceptTcpClient();
stream = tcpClient.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
writer.NewLine = "\r\n";
writer.AutoFlush = true;
byte[] serverData = new byte[tcpClient.ReceiveBufferSize];
int length = stream.Read(serverData, 0, serverData.Length);
string received = Encoding.ASCII.GetString(serverData, 0, length);
}
Below is how I am sending the data via Android
i
f (contactInformation.photoBase64String != null) {
bitmap = MediaStore.Images.Media.getBitmap(context.getContentResolver(), Uri.parse(contactInformation.photoBase64String));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] b = baos.toByteArray();
bitmap64Encoded = Base64.encodeToString(b, Base64.DEFAULT);
}
Toast.makeText(context, "Incoming call from " + contactInformation.contactName, Toast.LENGTH_LONG).show();
XmlSettings xmlSettings = new XmlSettings();
xmlSettings.setIndent(true);
XmlWriter xmlWriter = new XmlWriter(xmlSettings);
xmlWriter.writeStartDocument();
xmlWriter.writeStartElement("StatusManager");
xmlWriter.writeElementString("Command", Defines.ServerCommands.IncomingCall.toString());
xmlWriter.writeStartElement("CallInformation");
xmlWriter.writeElementString("PhoneNumber", phoneNumber);
xmlWriter.writeElementString("ContactName", contactInformation.contactName);
if (contactInformation.photoBase64String != null)
{
xmlWriter.writeElementString("PhotoUri", bitmap64Encoded);
}
xmlWriter.writeEndElement();
xmlWriter.writeEndElement();
String xml = xmlWriter.returnXmlOutput();
TCPSender tcpSender = new TCPSender(context, DeviceManagement.servers.get(0), xmlWriter.returnXmlOutput());
Thread thread = new Thread(tcpSender);
thread.start();
The TCP Sender is
#Override
public void run() {
Log.d("TCPSender", xml);
HelperClass helperClass = new HelperClass();
try
{
Socket socket = new Socket(foundServerInformation.ipAddress, foundServerInformation.tcpServerPort);
OutputStream out = socket.getOutputStream();
PrintWriter output = new PrintWriter(out);
output.println(xml);
output.flush();
I guess the data is too big for the byte array but I can't find a way of how to ensure I get all of the information that Android is sending.
It's difficult to know where the problem might be (I see your code is OK), but here you have a working example from Microsoft how it should be done, maybe it gives you some clues.
TcpListener server=null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while(true)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
Console.WriteLine("Sent: {0}", data);
}
// Shutdown and end connection
client.Close();
}
}
catch(SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
I've finally managed to get it working, it was something to do with using the SendReceiveBuffer which I did try but didn't work but now it does so I guess I missed something.
Below is the code I am using to receive all of the data
TcpListener tcpListener = new TcpListener(IPAddress.Any, serverTCPPort);
tcpListener.Start();
string received = "";
while (true)
{
tcpClient = tcpListener.AcceptTcpClient();
stream = tcpClient.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
writer.NewLine = "\r\n";
writer.AutoFlush = true;
byte[] bytes = new byte[tcpClient.SendBufferSize];
int recv = 0;
while (true)
{
recv = stream.Read(bytes, 0, tcpClient.SendBufferSize);
received += System.Text.Encoding.ASCII.GetString(bytes, 0, recv);
if (received.EndsWith("\n\n"))
{
break;
}
}
}

Calling AcceptTcpClient on sockect never continues in a win application

I wrote the code as seen below as a C# console app, and it works correctly.
However when I use in win application it dose not work.
I put in a break point, and it stops on " tcpClient = tcpListener.AcceptTcpClient();" line,
and does not do any work and does not show any thing, and no errors are returned.
part of my code :
void _func_send()
{
byte[] bytes = new byte[512];
IPAddress add = ipHost.AddressList[2];
Socket server = new Socket(add.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
TcpListener tcpListener = null;
tcpListener = new TcpListener(add, 50);
//tcpListener.Stop();
tcpListener.Start();
while (true)
{
/////on this line it stops
tcpClient = tcpListener.AcceptTcpClient();
stream = tcpClient.GetStream();
if (stream.DataAvailable)
{
stream.Read(bytes, 0, bytes.Length);
_txt_show.Text = _txt_show.Text + Encoding.UTF8.GetString(bytes);
byte[] msg = Encoding.UTF8.GetBytes(".:: thanks ::.");
stream.Write(msg, 0, msg.Length);
}
}
}

Categories