I have created a LAN chat messaging application using C# that connects all clients who run the program to a server on my computer.
I am now trying to convert this application to work with android devices via Xamarin Studio.
When testing this, the device correctly connects to the server as it can send a message ( saying the device has logged in) which is then broadcasted to the other clients.
However, once the application sends this message the program then closes immediately.
Within the desktop version of the chat client I use the code(which is ran on another thread):
NetworkStream serverStream = default(NetworkStream);
private void getMessage()
{
while (this.keepOpen)
{
Console.WriteLine("getMessage");
serverStream = clientSocket.GetStream();
int buffSize = 0;
byte[] inStream = new byte[clientSocket.ReceiveBufferSize];
buffSize = clientSocket.ReceiveBufferSize;
try
{
Console.WriteLine("Read stream");
serverStream.Read(inStream, 0, buffSize);
Console.WriteLine ("Final test");
}
catch
{
Console.WriteLine("failed to read stream");
}
string returndata = Encoding.ASCII.GetString(inStream);
readData = "" + returndata;
message();
}
}
This works the first time it is called as the line "Final test" is displayed. However, after this, when the method gets to this stage again (as it is in a never ending loop) I get an error message saying:
'[dalvikvm-heap] Grow heap (frag case) to 13.455MB for 4194308-byte allocation'
'[dalvikvm-heap] Grow heap (frag case) to 21.444MB for 8388612-byte allocation'
And the line "Final test" is not shown thus the line 'serverStream.Read(inStream, 0, buffSize);' is crashing the app. I have tried to use .Flush() and .Close() however none of these work.
The sending portion of my code runs perfectly using 'serverSocket.Write()' as other clients can receive the messages so why would reading data from the server crash the app?
P.S This is my first android app so I wanted to use a language I was more comfortable with than attempting from scratch with java.
Thanks in advance.
Realised that this error was because I was allocating too much memory when trying to send a messag.
Simple changed
byte[] inStream = new byte[clientSocket.ReceiveBufferSize];
buffSize = clientSocket.ReceiveBufferSize;
To
byte[] inStream = new byte[4096];
buffSize = 4096;
Related
I'm trying to communicate with a device that has a Serial COM port that goes out (using RS232 Protocol), which I've hooked up to a converter box that converts the connection to Ethernet.
I've successfully connected to the converter box (which has its own IP) and I've successfully communicated with the device by sending it commands over telnet by using PuTTY, to which it has responded with various data that I've been able to parse.
I've established a connection by creating a new TcpClient, and I'm able to send strings to the device, but every time I get a response back, it's always "??\u0003" which I've researched and found that \uhhhh is a Unicode escape protocol. This confuses me because I have used ASCII encoding for everything.
public string TcpConnect(string cmd)
{
var client = new TcpClient();
//cmd = "ping";
Console.WriteLine("Connecting to server");
client.Connect("169.254.20.40", 23); //22 = ssh, 23 = telnet, 80 = http
Console.WriteLine("CONNECTED SUCCESSFULLY");
Stream tcpStream = client.GetStream();
ASCIIEncoding A = new ASCIIEncoding();
byte[] enable = A.GetBytes("enable" + Environment.NewLine);
byte[] connect = A.GetBytes("connect line 1" + Environment.NewLine);
byte[] ba = A.GetBytes(cmd);
Console.WriteLine("Transmitting.....");
tcpStream.Write(enable, 0, enable.Length);
tcpStream.Write(connect, 0, connect.Length);
tcpStream.Write(ba, 0, ba.Length);
byte[] responseBytes = new byte[4096];
int numBytesRead = tcpStream.Read(responseBytes, 0, responseBytes.Length);
var message = A.GetString(responseBytes, 0, numBytesRead);
Console.WriteLine("\nServer Closed.");
return message;
}
If I were to pass in "$TEAA4B9\r\n" as the message, I would expect something along the lines of "$TEA,086,040,031,000,3798" which is nowhere close to what I'm getting (which is ??\u0003)
Nevermind figured it out
Just kidding! Here's what I did: I added a "System.Threading.Thread.Sleep("1000") before the "tcpStream.Read" line at the bottom, and now it outputs the data I need. The device was outputting garbage on the first line (perhaps a handshake, not sure) and that's all that was being read before it was being stored into "message" and returned (not enough time was spent reading before it moved on to the next line of code)
I have to develop a simple TCP File Transfer Client as part of an exercise/demonstration but I am having trouble with data delivery.
I am already provided with the TCP File server which will receive the incoming files and I have to code a Client that will connect to and send a file to the server. Thus far I have been successful as far as converting the data of the selected file into to a format ready to transferring and successfully opening a connection and then sending of the data, however even encounter a problem on server that is receiving - I am not allowed to change the code of the server and should thus change my client code in such a way that the data sent can be interpreted by the server. Here is the code I use (some is left out which is simple overhead, like input-box to get IP address etc.):
Link for TCP Server VS Solution (if you prefer): https://www.mediafire.com/?682owf9wtdzmxac
TCP File Transfer Client Sending method:
private void TransferFile(string _sFileName, string _sIPAdress)
{
//Convert data for transfer
Stream strmfilestream = File.OpenRead(_sFileName);
Byte[] bFileBuffer = new Byte[strmfilestream.Length];
//Open TCP/IP Connection
TcpClient tcpClientSocket = new TcpClient(_sIPAdress,8080);
NetworkStream nsNetworkStream = tcpClientSocket.GetStream();
nsNetworkStream.Write(bFileBuffer,0,bFileBuffer.GetLength(0));
nsNetworkStream.Close();
}
*Note: _sFileName is just the full file path + File name from a OpenFileDialog.
Here is the Load Method of the server to get things going:
if (!Directory.Exists(#"C:\TCPFileServer"))
Directory.CreateDirectory(#"C:\TCPFileServer");
//Get Ip address of server host machine
IPHostEntry IPHost = Dns.GetHostEntry(Dns.GetHostName());
lblServerIP.Text = IPHost.AddressList[5].ToString();
lstSockets = new ArrayList();
Thread thdListener = new Thread(new ThreadStart(listenerThread));
thdListener.IsBackground = true; //This will enabe the thread to terminate when application is closed
thdListener.Start();
Here is the listener thread method:
public void listenerThread()
{
TcpListener tcpListener = new TcpListener(IPAddress.Any, 8080);
tcpListener.Start();
while (true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
{
this.Invoke((Action)(() => lstConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.")));
lock (this)
{
lstSockets.Add(handlerSocket);
}
ThreadStart thdsHandler = new ThreadStart(handlerThread);
Thread thdHandler = new Thread(thdsHandler);
thdHandler.Start();
}
}
}
And then lasty here is the handler thread method:
public void handlerThread()
{
try
{
int iBlockSize = 1024 * 3000; //3mb block size
Byte[] dataByte = new Byte[iBlockSize];
Byte[] rcvdData = new Byte[128000 * 1024];//128mb File Limit
Socket handlerSocket = (Socket)lstSockets[lstSockets.Count - 1];
NetworkStream networkStream = new NetworkStream(handlerSocket);
int i = 0;
int iRcvdBytes = 0;
while (true)
{
//Read from socket and store to buffer 'dataByte'
iRcvdBytes = networkStream.Read(dataByte, 0, iBlockSize);
dataByte.CopyTo(rcvdData, i);//Copy recieved bytes,from buffer, to another byte array
i += iRcvdBytes;
if (iRcvdBytes == 0) break;
}
//Get the File name length, BitConvertor occupies the first 4 bytes
int iFileNameLength = BitConverter.ToInt32(rcvdData, 0);
//Get the file name using length as the size and 4 as the offset
string sFileName = Encoding.ASCII.GetString(rcvdData, 4, iFileNameLength);
Stream fileStream = File.Open("C:\\TCPFileServer\\" + sFileName, FileMode.Create);
//Populate raw File on local machine
fileStream.Write(rcvdData, 4 + iFileNameLength, i - 4 - iFileNameLength);
fileStream.Close();
//Update BRS Net Files Server Log
this.Invoke((Action)(() => lstConnections.Items.Add(sFileName + ": Transfered.")));
//Close Connection
networkStream.Close();
handlerSocket = null; //Clear socket
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Now I have debugged and as far I can determine, the first time I can see a problem is when we are trying to determine the file name length where the code reads int iFileNameLength = BitConverter.ToInt32(rcvdData, 0); - When debugging this variable is always determined as '0', which I assume is not correct? I am not sure. The required results that needs to be achieved is that the Server should receive the file and after the successful transfer, the file name should be displayed in the ListBox.
Here is screen shots showing the problem i'm experiencing:
We can see that bytes are definitely received:
Note that the file name can not be retrieved from using the file name length and offset:
And thus, the following error occurs:
My experience and expertise lie elsewhere and this is the first time I am coding within this paradigm(File transfer over network). I do however have theoretical knowledge about/studied the OSI model and TCP/IP Protocol stack, but never coded anything like this. One note given to me was that the server was coded with the assumption that it will be executed on a specific PC and I am allowed to change code of the Server application if it is absolutely necessary.
Try this. You have to do thinks in reverse on the client and using a List makes things easier.
private void TransferFile(string _sFileName, string _sIPAdress)
{
List<Byte> bFileBuffer = File.ReadAllBytes(_sFileName).ToList();
byte[] bFileName = Encoding.ASCII.GetBytes(_sFileName);
bFileBuffer.InsertRange(0, bFileName);
//Get the File name length, BitConvertor occupies the first 4 bytes
byte[] brcvdDataCount = BitConverter.GetBytes((UInt32)_sFileName.Count());
bFileBuffer.InsertRange(0, brcvdDataCount);
//Open TCP/IP Connection
TcpClient tcpClientSocket = new TcpClient(_sIPAdress, 8080);
NetworkStream nsNetworkStream = tcpClientSocket.GetStream();
nsNetworkStream.Write(bFileBuffer.ToArray(), 0, bFileBuffer.Count);
nsNetworkStream.Close();
}
There are two things with the server code you should be aware of
/Get the File name length, BitConvertor occupies the first 4 bytes
int iFileNameLength = BitConverter.ToInt32(rcvdData, 0);
//Get the file name using length as the size and 4 as the offset
string sFileName = Encoding.ASCII.GetString(rcvdData, 4, iFileNameLength);
1) You need to add a byte count to beginning of upload.
2) The code is using Ascii Encoding which means you can not upload binary data.
I am building a system with on one side an Android app, that uses an HTTPURLConnection to communicate with the other side, which is a C# HttpListener. Over this channel they communicate with XML data.
This works very well, except for some larger data. When I try to communicate that, I see the XML from Android arrives the C# application en the C# application does respond. However, before the data arrives the Android, I get a "Connection reset by peer." exception.
This is the Android code:
URL url = new URL(urlString);
connection = (HttpURLConnection)url.openConnection();
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setDoOutput(true);
connection.setFixedLengthStreamingMode(tel.length());
connection.setReadTimeout(30000);
// write our telegram...
OutputStream output = new BufferedOutputStream(connection.getOutputStream());
output.write(tel.getBytes());
output.flush();
and here is the reply read:
InputStream input = new BufferedInputStream(connection.getInputStream());
if (connection.getResponseCode() == HttpStatus.SC_OK) {
String r = null;
byte cbuf[] = new byte[connection.getContentLength()];
if (input.read(cbuf, 0, connection.getContentLength()) != -1) {
r = new String(cbuf);
}
reply = Telegram.fromString(r);
} else {
throw new ProtocolException("HTTP Error code: "+connection.getResponseCode());
}
and this is the C# code:
httpListener = new HttpListener();
httpListener.Prefixes.Add(String.Format("http://*:{0}/", port);
httpListener.Start();
Turns out, the connection.getContentLength() does not always match the number of bytes read in the input.read(), so the read call waits (and eventually, the server resets as it is done sending I guess).
To fix, I rewrote the receiving side to:
int bufs = 256, read;
ByteArrayOutputStream cbuf = new ByteArrayOutputStream(bufs);
byte[] tempbuf = new byte[bufs];
while ((read = input.read(tempbuf, 0, bufs)) != -1) {
Log.d(PocketApplication.TAG, "Read "+read+" bytes.");
cbuf.write(tempbuf);
}
and it works fine now. Making the size of bufs too large causes it to fail again (e.g. with 1024, the same problem occurs).
I'm trying to learn the basics of networking and I've built an echo server from this tutorial. I checked the server with telnet and it works perfect.
Now when I'm using some of the many client samples on the Internet:
// Create a TcpClient.
// Note, for this client to work you need to have a TcpServer
// connected to the same address as specified by the server, port
// combination.
TcpClient client = new TcpClient(server, port);
// 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);
Console.WriteLine("Sent: {0}", message);
// Receive the TcpServer.response.
// 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);
responseData = System.Text.Encoding.ASCII.GetString(data, 0, bytes);
Console.WriteLine("Received: {0}", responseData);
// Close everything.
stream.Close();
client.Close();
It doesn't work very well. If I will comment the stream.Read line, everything works perfect (expect I can't read). I was also trying to accomplish that in a similar way using asynchronous callback method for the read. and then it only works after I terminate the program (the server handles the request)
I suspect that the way I'm reading from the stream cause this block, but I'm too clueless to understand what I'm doing wrong.
The implementation will block until at least one byte of data can be
read, in the event that no data is available.
From MSDN
Your server propably isn't sending you any data.
Edit:
I tested your client and it works perfectly fine. Try it yourself and set the following parameters:
string server = "google.com";
int port = 80;
string message = "GET /\n";
It's definitely your server which has the problem.
I have a quick and dirty question. So as it stands, i have two clients and a server running. I can communicate messages from the clients to the server without any problem. my problem appears when i want to read two messages from the client - rather than just one message.
The error which i receive is: IOException was unhandled. Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
Here is my code on the server side:
private static void HandleClientComm(object client)
{
/** creating a list which contains DatabaseFile objects **/
List theDatabase = new List();
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
// Blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch (Exception)
{
// 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.WriteLine("To: " + tcpClient.Client.LocalEndPoint);
Console.WriteLine("From: " + tcpClient.Client.RemoteEndPoint);
Console.WriteLine(encoder.GetString(message, 0, bytesRead));
if (encoder.GetString(message, 0, bytesRead) == "OptionOneInsert")
{
byte[] message2 = new byte[4096];
int bytesRead2 = 0;
**bytesRead2 = clientStream.Read(message, 0, 4096);** //ERROR occurs here!
Console.WriteLine("Attempting to go inside insert)");
Menu.Insert(theDatabase, bytesRead2);
}
Here is my client code:
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("OptionOneInsert");
Console.ReadLine();
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
NetworkStream clientStream2 = client.GetStream();
String text = System.IO.File.ReadAllText("FirstNames.txt");
clientStream2.Write(buffer, 0, buffer.Length);
clientStream2.Flush();
ASCIIEncoding encoder2 = new ASCIIEncoding();
byte[] buffer2 = encoder2.GetBytes(text);
Console.WriteLine("buffer is filled with content");
Console.ReadLine();
When the client sends the message "optionOne" it is received by the server just fine. It's only when i attempt to send the string called "text" that the issues appears!
Any help would be greatly appreciated - I'm not all that familiar with Sockets, hence i've been struggling with trying to understand this for sometime now
You've got a big problem here - there's nothing to specify the end of one message and the start of another. It's quite possible that the server will receive two messages in one go, or half a message and then the other half.
The simplest way of avoiding that is to prefix each message with the number of bytes in it, e.g. as a fixed four-byte format. So to send a message you would:
Encoding it from a string to bytes (ideally using UTF-8 instead of ASCII unless you're sure you'll never need any non-ASCII text)
Write out the length of the byte array as a four-byte value
Write out the content
On the server:
Read four bytes (looping if necessary - there's no guarantee you'd even read those four bytes together, although you almost certainly will)
Convert the four bytes into an integer
Allocate a byte array of that size
Loop round, reading from "the current position" to the end of the buffer until you've filled the buffer
Convert the buffer into a string
Another alternative is simply to use BinaryReader and BinaryWriter - the ReadString and WriteString use length-prefixing, admittedly in a slightly different form.
Another alternative you could use is to have a delimiter (e.g. carriage-return) but that means you'll need to add escaping in if you ever need to include the delimiter in the text to transmit.