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();
}
Related
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();
}
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.
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;
}
}
}
I'm sending an object (class name House) over TCP using the TcpListener on the server side in response to any message received from the TcpClient.
When the message is received, it is currently populating a text box named textBox1.
If I send a line of text, it works fine. You'll notice that I have a redundant line "Hello, I'm a server" for testing this purpose. But when I send the XML, it is cutting it off prematurely.
When I send serialised XML in to the stream, I'm also receiving this error from the server side:
Unable to read data from the transport connection: An existing
connection was forcibly closed by the remote host.
Here's my server code
// Set the variables for the TCP listener
Int32 port = 14000;
IPAddress ipaddress = IPAddress.Parse("132.147.160.198");
TcpListener houseServer = null;
// Create IPEndpoint for connection
IPEndPoint ipend = new IPEndPoint(ipaddress, port);
// Set the server parameters
houseServer = new TcpListener(port);
// Start listening for clients connecting
houseServer.Start();
// Buffer for reading the data received from the client
Byte[] bytes = new Byte[256];
String data = "hello, this is a house";
// Show that the TCP Listener has been initialised
Console.WriteLine("We have a TCP Listener, waiting for a connection...");
// Continuing loop looking for
while (true)
{
// Create a house to send
House houseToSendToClient = new House
{
house_id = 1,
house_number = 13,
street = "Barton Grange",
house_town = "Lancaster",
postcode = "LA1 2BP"
};
// Get the object serialised
var xmlSerializer = new XmlSerializer(typeof(House));
using (var memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, houseToSendToClient);
}
// Accept an incoming request from the client
TcpClient client = houseServer.AcceptTcpClient();
// Show that there is a client connected
//Console.WriteLine("Client connected!");
// Get the message that was sent by the server
NetworkStream stream = client.GetStream();
// Blank int
int i;
// Loop for receiving the connection from the client
// >>> ERROR IS ON THIS LINE <<<
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
Console.WriteLine("here");
// Take bytes and convert to ASCII string
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received s, return house");
// Convert the string to a byte array, ready for sending
Byte[] dataToSend = System.Text.Encoding.ASCII.GetBytes("Hello, I'm a server");
// Send the data back to the client
//stream.Write(dataToSend, 0, dataToSend.Length);
// Send serialised XML in to the stream
xmlSerializer.Serialize(stream, houseToSendToClient);
}
// Close the connection
client.Close();
}
Client code
// Get the object serialised
var xmlSerializer = new XmlSerializer(typeof(House));
// Set the variables for the TCP client
Int32 port = 14000;
IPAddress ipaddress = IPAddress.Parse("127.0.0.1");
IPEndPoint ipend = new IPEndPoint(ipaddress, port);
string message = "s";
try
{
// Create TCPCLient
//TcpClient client = new TcpClient("localhost", port);
TcpClient client = new TcpClient();
// Convert the string to a byte array, ready for sending
Byte[] dataToSend = System.Text.Encoding.ASCII.GetBytes(message);
// Connect using TcpClient
client.Connect(ipaddress, port);
// Client stream for reading and writing to server
NetworkStream stream = client.GetStream();
// Send the data to the TCP Server
stream.Write(dataToSend, 0, dataToSend.Length);
//xmlSerializer.Serialize(stream, houseToSend);
// Buffer to store response
Byte[] responseBytes = new Byte[256];
string responseData = String.Empty;
// Read the response back from the server
Int32 bytes = stream.Read(responseBytes, 0, responseBytes.Length);
responseData = System.Text.Encoding.ASCII.GetString(responseBytes, 0, bytes);
textBox1.Text = responseData;
// Close the stream and the client connection
stream.Close();
client.Close();
}
catch (SocketException e)
{
MessageBox.Show(e.ToString());
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
I've marked on the code where the error is appearing.
Is it because the message is too long?
Your client code is assuming that the entire message will come through in one call to the Read(...) method, which is absolutely wrong. From the MSDN docs: "An implementation is free to return fewer bytes than requested even if the end of the stream has not been reached."
It's possible that, for a 1024-byte XML document, you may have to call Read(...) 1024 times to get the entire message.
Really, you'd do well to send a four-byte length before you send the XML, so that the client knows how much data to expect. The client will read four bytes, convert that to an integer length, then read that many more bytes, then turn those bytes into XML.
I have a client application that serializes a object and sends it to a server application. The server should deserialize the object, make changes to it, then serialize it and send it back.
Server Code:
TcpClient client = server.AcceptTcpClient();
using(NetworkStream stream = client.GetStream())
{
using(StreamReader streamReader = new StreamReader(stream))
{
string xmlData = streamReader.ReadToEnd();
}
}
The ReadToEnd doesn't return unless the client closes the stream. But if the client closes the stream, I can't send a response.
Is there a better way to do this?
You can signal "end of data" by closing only your half of the duplex TCP connection. This is accomplished with Socket.Disconnect.
See how it works with this example, which I kept similar to yours. The client sends the data and then calls Disconnect; this allows ReadToEnd to return while still keeping the server's half of the connection open. The server then sends a response and also disconnects, after which both parties can Close their end of the connection to tear it down.
static void Main(string[] args)
{
Action clientCode = () =>
{
var buffer = new byte[100];
var clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
clientSocket.Connect(IPAddress.Loopback, 6690);
clientSocket.Send(buffer);
clientSocket.Disconnect(false);
Console.WriteLine("Client: message sent and socket disconnected.");
while (true) {
var bytesRead = clientSocket.Receive(buffer);
if (bytesRead == 0) {
break;
}
Console.WriteLine("Client: read " + bytesRead + " bytes.");
}
clientSocket.Dispose();
};
var server = new TcpListener(IPAddress.Loopback, 6690);
var thread = new Thread(new ThreadStart(clientCode));
server.Start();
thread.Start();
var client = server.AcceptTcpClient();
using(NetworkStream stream = client.GetStream()) {
using(StreamReader streamReader = new StreamReader(stream))
{
var data = streamReader.ReadToEnd();
Console.WriteLine("Server: read " + data.Length + " bytes.");
// Since we 're here we know that the client has disconnected.
// Send the response before StreamReader is disposed, because
// that will cause the socket itself to be closed as well!
Thread.Sleep(TimeSpan.FromSeconds(1));
Console.WriteLine("Server: sending response.");
stream.Write(new byte[10], 0, 10);
Console.WriteLine("Server: closing socket.");
}
}
server.Stop();
Console.WriteLine("Server: waiting for client thread to complete.");
thread.Join();
return;
}
You could use a higher level framework like WCF, or if you are hell-bent on managing your own streams, then don't use ReadToEnd()- use ReadLine() (and have the client send messages as lines), or use Read() and have a special character (a sentinel) represent the end of a message.