Sending and receiving plain text with TCP - c#

I want to send this string through TCP connection:
TR220,2,A10000XX,3545.1743,5119.5794,001.0,1503,52:56:16,2012/09/13,0,0,0,0,0,V,000,0,0,0,,+989123456789,*
I am using this code to send the text:
string uri = "http://localhost:1414";
String record = "TR220,2,A10000XX,3545.1743,5119.5794,001.0,1503,52:56:16,2012/09/13,0,0,0,0,0,V,000,0,0,0,,+989123456789,*";
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = "POST";
byte[] postBytes = GetBytes(record);
request.ContentType = "text/plain";
request.ContentLength = postBytes.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(postBytes, 0, postBytes.Length);
and GetBytes method:
private byte[] GetBytes(string str)
{
byte[] bytes = new byte[str.Length * sizeof(char)];
System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
return bytes;
}
After sending this Request, In the other side app, I get this String:
POST / HTTP/1.1\r\nContent-Type: text/plain\r\nHost: localhost:1414\r\nContent-Length: 212\r\nExpect: 100-continue\r\nConnection: Keep-Alive\r\n\r\n
using this block of code:
tcpListener = new TcpListener(IPAddress.Any, 1414);
listenThread = new Thread(new ThreadStart(ListenForClients));
listenThread.Start();
and ListenForClients method (some code omitted for clarity):
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while (true)
{
bytesRead = 0;
try { bytesRead = clientStream.Read(message, 0, 4096); }
catch { break; }
ASCIIEncoding encoder = new ASCIIEncoding();
String data = encoder.GetString(message, 0, bytesRead);
MessageReceived(data);
}
My question is why sent and received strings are not the same?

Are you sure you know what you are doing? You are sending HTTP Packets to a raw TCP socket, off course you are going to get HTTP protocol strings around your true payload. Use the same kind of sockets on both ends or you will go insane eventually.
This is slightly old but seems good enough for what you need, as always: Google is you friend.
http://www.codeproject.com/Articles/12893/TCP-IP-Chat-Application-Using-C
As for why a TCP socket is receiving an HTTP connection without a hitch? HTTP is run over TCP, it's just a formal protocol on top of it.

Related

Tcp listener vs Http Listener

My needs are to send just a simple string. Which method is more right to use, or faster with better performance.
HttpListener
HttpListener listener = new HttpListener();
foreach (string s in prefixes)
{
listener.Prefixes.Add(s);
}
listener.Start();
Console.WriteLine("Listening..");
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
HttpListenerResponse response = context.Response;
string responseString = "<HTML><BODY> Test </BODY></HTML>";
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
response.ContentLength64 = buffer.Length;
Stream output = response.OutputStream;
output.Write(buffer, 0, buffer.Length);
output.Close();
listener.Stop();
TcpListener
IPAddress ipAd = IPAddress.Parse("172.21.5.99");
TcpListener myList=new TcpListener(ipAd,8001);
myList.Start();
Socket s=myList.AcceptSocket();
byte[] b=new byte[100];
int k=s.Receive(b);
Console.WriteLine("Recieved...");
for (int i=0;i<k;i++)
Console.Write(Convert.ToChar(b[i]));
ASCIIEncoding asen=new ASCIIEncoding();
s.Send(asen.GetBytes("The string was recieved by the server."));
s.Close();
myList.Stop();
I need to send from my client a string with some values, example Name=xxx,Age=xxx
,then server to take this string and answering with an "OK"

async tcp connection C#

TcpListener tcpServer = new TcpListener(8080);
tcpServer.Start();
tcpServer.BeginAcceptTcpClient(new AsyncCallback(this.messageRecived), tcpServer);
I have some code for accept reading from tcp client, client send massage in this way:
TcpClient client = new TcpClient("192.168.0.2", 8080)
string Str = "it's work";
byte[] Buffer = Encoding.ASCII.GetBytes(Str);
client.GetStream().Write(Buffer, 0, Buffer.Length);
the problem is in messageRecived method:
public void messageRecived(IAsyncResult result)
{
byte[] data = new byte[20000];
string outData;
TcpListener server = (TcpListener)result.AsyncState;
server.AcceptTcpClient().GetStream().Read(data, 0, server.Server.ReceiveBufferSize);
outData = Encoding.ASCII.GetString(data);
addLog(outData);
}
When i send message to server the method received run until to this line:
server.AcceptTcpClient().GetStream().Read(data, 0, server.Server.ReceiveBufferSize);
and in the next iteration it begin from next line to the end of method. What is the problem?
probably because you are not closing stream from client, please refer to below link to properly dispose stream from client
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.getstream(v=vs.110).aspx
Try to flush the client Stream.
TcpClient client = new TcpClient("192.168.0.2", 8080)
string Str = "it's work";
byte[] Buffer = Encoding.ASCII.GetBytes(Str);
var stream = client.GetStream()
stream.Write(Buffer, 0, Buffer.Length);
stream.Flush()

Calling method from loop in tcp server c#

I was writing a threaded tcp server and within this thread i wrote this:
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
byte[] buffer = null;
string answer = null;
while (true)
{
bytesRead = 0;
try
{
bytesRead = clientStream.Read(message, 0, 4096);
}
catch(Exception ex)
{
write("Error: " + ex.Message);
break;
}
if (bytesRead == 0)
{
write("Client connection lost!");
break;
}
txtLogger.Text += "Command accepted\n";
ASCIIEncoding encoder = new ASCIIEncoding();
clientreq = encoder.GetString(message, 0, bytesRead);
clientreq = clientreq.ToUpper();
if (clientreq == "CLIENTIP")
{
//THIS PART
answer = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
buffer = encoder.GetBytes(answer);
}
//some more if's
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
write("Server finished work.");
}
//some more code
Now i would like the THIS PART to be a method that will be called if the input is CLIENTIP, as requested from client. how i would be doind that.
Thanks in advance :)
By the way, every client req should be handled with new tcp connection.
I've tried this, with pretty bad result: the client freezes and NOTRespondin occured
public void IPKLIENTI()
{
TcpClient client = this.TCPMonitoruesi.AcceptTcpClient();
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] Bufer = null;
string answer = null;
ASCIIEncoding encoder = new ASCIIEncoding();
answer = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
Bufer = encoder.GetBytes(answer);
}
To break up your if statement to handle the "CLIENTIP" request, you need to pass the TcpClient you are connected to to the method which does all the work (the IPKLIENTI method) as below.
if (clientreq == "CLIENTIP")
{
// call to IPCLIENTI retrives the RemoteEndPoint of the given TcpClient and encodes a response to be sent
buffer = IPKLIENTI(client, encoder);
}
A revised IPKLIENTI implementation is shown below. The key changes are:
Takes a TcpClient as a paramater rather than accepting a new TcpClient (this behavior lets you work with the TcpClient you recieved the request from and will later respond to, the old behavior attempted to accept another client all together)
Takes an ASCIIEncoding object to do the encoding with - you could re-build it as you used to, but this is tidier and ensures consistency in the future
We don't need to access the NetStream in this function, so we can do away with the call to GetStream
We return an encoded byte array to use as the response to the client when we call clientStream.Write() later in the HandleClientComm function
Revised IPKLIENTI method:
// Method takes a TcpClient Object and Encoder, returning a response to the CLIENTIP request
public byte[] IPKLIENTI(TcpClient tcpClient, ASCIIEncoding encoder)
{
string answer = ((IPEndPoint)tcpClient.Client.RemoteEndPoint).Address.ToString();
byte[] buffer = encoder.GetBytes(answer);
return buffer;
}
Essentially it just stores the intended response in a string (the RemoteEndPoint of the given TcpClient) and then encodes it via the given encoder, returning a byte array of the encoded response to be sent to the client.

How to properly pass stream through rest service to retrieve its length

I'm passing the stream this way:
StreamReader sr = new StreamReader(openFileDialog1.FileName);
byte[] fileStream = Utility.ReadFully(sr.BaseStream);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress));
request.Method = "POST";
request.ContentType = "application/octet-stream";
Stream serverStream = request.GetRequestStream();
serverStream.Write(fileStream, 0, fileStream.Length);
serverStream.Close();
HttpWebResponse response2 = (HttpWebResponse)request.GetResponse();
if (response2.StatusCode == HttpStatusCode.OK)
{
MessageBox.Show(Utility.ReadResponse(response2));
}
-------------------------------------------------------------------------
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
if (input != null)
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
return ms.ToArray();
}
}
Then handling it on the server:
public bool UploadPhotoStream(string someStringParam, Stream fileData)
{
string filePath = string.Format("{0}/{1}", 'sdfgsdf87s7df8sd', '24asd54s4454d5f4g');
ProductPhoto newphoto = new ProductPhoto();
newphoto.FileSizeBytes = fileData.Length / 1024 / 1024;
newphoto.FileLocation = filePath;
...
}
Now I'm getting NotSupportedException when calling fileData.Length. I know it happens because the stream is closed. But how can I re-open it? Or what should I do so that when I pass the stream to the service I can still get its length?
Why don't you pass content-length header? Your server can check the header and know exactly how many bytes is the content being sent. How you read the header depends on which http framework you are using, ASP.NET Web Api, classic WCF Web Api, HttpListener, etc.
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress));
request.Method = "POST";
request.ContentType = "application/octet-stream";
request.ContentLength = new FileInfo(openFileDialog1.FileName).Length
Without a Content-Length header, an http server can never know how many bytes are left to read. All it knows is there is a Stream and will read it till there is no more data. This is also how your browser can display a progress bar when downloading something. It takes bytesDownloaded / Content-Length.
According to this post: https://stackoverflow.com/a/8239268/1160036
You can access the header like this from your web method.
long dataLength = long.Parse(HttpContext.Current.Request.Headers["Content-Length"]);

C# client/server Question

I'm incredibly confused as to what is going on here. I've been putting in break points and I just can't seem to understand. Basically, I have a client and a server. I want the client to send two separate strings of data. From putting in break points, I noticed that my client does in fact fill both strings with the appropriate data. However, the server never ever sees the second string. Why is this happening and how do I fix it? Any help at all would be greatly appreciate! Below is my code:
Server:
private static void HandleClientComm(object client)
{
/** creating a list which contains DatabaseFile objects **/
List<DatabaseFile> theDatabase = new List<DatabaseFile>();
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StringBuilder response = new StringBuilder();
byte[] message = new byte[4096];
int bytesRead;
do
{
bytesRead = 0;
try
{
/*do
{
bytesRead = clientStream.Read(message, 0, message.Length);
response.Append(Encoding.ASCII.GetString(message, 0, bytesRead));
} while (clientStream.DataAvailable);*/
when i change this commented code to bytesRead = clientStream.Read(message, 0, 4096); i get an IOException Error that reads as follows: Unable to write data to the transport connection: An existing connection was forcibly closed by the remote host. Hence, i changed it to a do while loop. How do i get around this IOException and accept the second string?
ASCIIEncoding encoder = new ASCIIEncoding();
String file = encoder.GetString(message, 0, bytesRead);
Menu.Insert(theDatabase, file);
}
catch (Exception)
{
// A socket error has occured
break;
}
if (bytesRead == 0)
{
// The client has disconnected from the server
break;
}
} while (clientStream.DataAvailable);
// Release connections
clientStream.Close();
tcpClient.Close();
}
Client:
static void Main(string[] args)
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8888);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
NetworkStream clientStream2 = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
ASCIIEncoding encoder2 = new ASCIIEncoding();
String text = System.IO.File.ReadAllText("FirstNames.txt");
String text2 = System.IO.File.ReadAllText("LastNames.txt");
byte[] buffer = encoder.GetBytes(text);
Console.ReadLine();
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
Console.ReadLine();
byte[] buffer2 = encoder2.GetBytes(text2);
clientStream2.Write(buffer2, 0, buffer2.Length);
clientStream2.Flush();
Console.ReadLine();
}
}
The communication between client and server happens like this (note that the order of steps is just for illustration purposes, the actual order at runtime may be different):
Client: client.Connect(serverEndPoint)
Server: HandleClientComm(newClient)
Client: clientStream.Write(buffer, 0, buffer.Length)
Server: bytesRead = clientStream.Read(message, 0, message.Length)
Note that Read is not guaranteed to read entire message. It is perfectly ok to return just the portion that has been received so far
Client: Console.ReadLine()
Server: while (clientStream.DataAvailable)
There is no data on the stream - the client has not sent any. This would likely happen even without ReadLine - there is a window of time before the client sends data again
Server: tcpClient.Close()
Client: clientStream2.Write(buffer2, 0, buffer2.Length)
You can get an exception here, or not - depending on whether the server has already closed the connection, in any case the server is not reading anymore.
You need to define your own message protocol that both server and client will honor. For example, you can have the client close the connection when it is done sending:
Client:
using (var client = new TcpClient("localhost", 8888))
using (var clientStream = client.GetStream())
{
var buffer = Encoding.ASCII.GetBytes( File.ReadAllText("FirstNames.txt") );
clientStream.Write(buffer, 0, buffer.Length);
buffer = Encoding.ASCII.GetBytes( File.ReadAllText("LastNames.txt") );
clientStream.Write(buffer, 0, buffer.Length);
}
Server:
using (var tcpClient = (TcpClient)client)
using (var clientStream = tcpClient.GetStream())
{
// Store everything that the client sends.
// This will work if the client closes the connection gracefully
// after sending everything
var receivedData = new MemoryStream();
clientStream.CopyTo(receivedData);
var rawBytes = receivedData.ToArray();
var file = Encoding.ASCII.GetString(rawBytes, 0, rawBytes.Length);
Menu.Insert(theDatabase, file);
}
The protocol is simple, and may be enough for your case. However, there are issues with it which should be addressed in production code (e.g. what if the client sends too much data, exhausting server memory, what if the client stops sending without closing the connection, etc.)
because while (clientStream.DataAvailable) is no longer true after your first client call.
You are exiting your client-recv loop in your server just because DatAvailable is false. This means if the client were to send a frame of data (which you consume) and pause then your server would see no data available at that moment and disconnect, even if a split second later another frame of data from the client was about to come in. Almost always, the end of a dialog is based on the content of the data being passed. You can certainly never try to rely on the fact that DataAvailable happens to be false one time.
As a follow-up, if you provide more info on the protocol that is used we can give more assitance. For example, if the prototcol is that two strings are sent with CR/LF at the end then the server loop should be inspecting the buffer for that to know when to disconnect.

Categories