I have this code to send String messages to a server. These messages are supposed to be sent separately, but the Stream of the TcpClient is sending the messages in one bug chunk after the Stream is closed.
What can I do to send separated messages with this code:
public void sendData()
{
const int PORT_NO = 12900;
const string SERVER_IP = "127.0.0.1";
TcpClient client = new TcpClient(SERVER_IP, PORT_NO);
try
{
client.NoDelay = true;
NetworkStream nwStream = client.GetStream();
sendText(nwStream, "Text-1"); // Here is it supposed to send "Text-1"
sendText(nwStream, "Text-2");
sendText(nwStream, "Text-3");
}
finally
{
client.Close(); // But, all messages are sent here!
}
}
private void sendText(NetworkStream nwStream, String text)
{
byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(text);
nwStream.Write(bytesToSend, 0, bytesToSend.Length);
nwStream.Flush();
}
With this code the Server ends up receiveing: Text-1Text-2Text-3 in one message and it is supposed to receive 3 different messages. What is wrong here?
Related
I'm trying to send requests to an API that talks JSON-RPC. I've tested the server with Curl as such:
> curl -v -d 'SOME_INVALID_REQUEST' http://erbium1.sytes.net:50001
{"jsonrpc": "2.0", "error": {"code": -32700, "message": "invalid JSON"}, "id": null}
Some of the requests that interest me are subscriptions, thus sending POST requests seem unfit for this because I don't expect the server to reply instantly, rather receive one or more notifications.
I'm trying to talk to this server using C#, but the server never replies. To send the messages I've done the following :
Created a TcpClient
Connected the client to the server (erbium1.sytes.net,50001)
Go a NetworkStream from the connected client
Wrote to the NetworkStream
When I send these messages to the server, the read callback function is never invoked thus I am never receiving replies from the server. If I were to send the messages to port 50002 (TLS) instead of 50001, the server replies with an empty string.
My guess is, doing a raw TcpClient connection does not send the messages with the HTTP headers thus the server is just dropping them? If so, what would be a suitable way of requesting subscriptions to the server and be able to receive notifications?
What would be the difference between a TcpClient connection and a WebSocket? Would WebSocket be the suitable thing to use here?
Below a sample of my code :
// State object for receiving data from remote device.
public class ReceiverState {
public ReceiverState(NetworkStream s) {
this.stream = s;
}
public NetworkStream stream;
public const int bufferSize = 1024;
public byte[] buffer = new byte[bufferSize];
public AutoResetEvent receivedEvent = new AutoResetEvent(false);
}
static AutoResetEvent received = new AutoResetEvent(false);
public static void PingServer(NetworkStream stream) {
if (stream.CanWrite) {
try {
String rpc = "INVALID_REQUEST";
Byte[] data = System.Text.Encoding.UTF8.GetBytes(rpc);
stream.Write(data, 0, data.Length);
stream.Flush();
Console.WriteLine("Pinging...");
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
} else {
// TODO Throw an exception
Console.WriteLine("Unable to write to stream");
}
}
public static void BeginAsyncRead(NetworkStream stream, ReceiverState readState) {
if (stream.CanRead) {
try {
stream.BeginRead(readState.buffer, 0, 1024,
new AsyncCallback(readCallBack),
readState);
}
catch (Exception e) {
Console.WriteLine(e.ToString());
}
} else {
// TODO Throw an exception
Console.WriteLine("Unable to read from stream");
}
}
private static void readCallBack(System.IAsyncResult ar) {
// Get the state from AsyncResult
ReceiverState state = (ReceiverState) ar.AsyncState;
if(ar.IsCompleted){
Int32 numBytes = state.stream.EndRead(ar);
Console.WriteLine("Received : ");
Console.WriteLine(Encoding.ASCII.GetString(state.buffer,0,numBytes+10));
state.receivedEvent.Set();
}
}
private static void synchronousRead(NetworkStream myNetworkStream) {
if(myNetworkStream.CanRead){
byte[] myReadBuffer = new byte[1024];
StringBuilder myCompleteMessage = new StringBuilder();
int numberOfBytesRead = 0;
// Incoming message may be larger than the buffer size.
do{
numberOfBytesRead = myNetworkStream.Read(myReadBuffer, 0, myReadBuffer.Length);
myCompleteMessage.AppendFormat("{0}", Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
}
while(myNetworkStream.DataAvailable);
// Print out the received message to the console.
Console.WriteLine("You received the following message : " +
myCompleteMessage);
}
else{
Console.WriteLine("Sorry. You cannot read from this NetworkStream.");
}
}
public static void Main(string[] args) {
// Create a new TcpClient
TcpClient client = new TcpClient();
Console.WriteLine("Connecting...");
client.Connect("electrum3.hachre.de", 50001);
NetworkStream stream = client.GetStream();
Stream inStream = new MemoryStream();
ReceiverState readState = new ReceiverState(stream);
readState.receivedEvent = received;
BeginAsyncRead(stream, readState);
PingServer(stream);
received.WaitOne();
}
I'm wanting to run a little socket server in C# to be accessed by a browser. I have a socket listener up and running on a specific port, and am trying to access it via the browser:
class WebSocketServer
{
private static string output = string.Empty;
public void CreateListener()
{
TcpListener tcpListener = null;
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
tcpListener = new TcpListener(ipAddress, 1313);
tcpListener.Start();
output = "Waiting for a connection";
}
catch (Exception e)
{
throw;
}
var socketHelper = new SocketHelper();
while (true)
{
Thread.Sleep(10);
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] bytes = new byte[256];
var stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
socketHelper.ProcessMessage(tcpClient, stream, bytes);
}
}
}
class SocketHelper
{
private static int counter = 0;
public void ProcessMessage(TcpClient tcpClient, NetworkStream stream, byte[] bytesReceived)
{
// handle message received and send response to client
var msg = Encoding.ASCII.GetString(bytesReceived);
string response = string.Empty;
if (msg.Substring(0, 10) == "GET / HTTP")
{
response = "";// html page
}
byte[] bytesToSend = Encoding.ASCII.GetBytes(response);
stream.Write(bytesToSend, 0, bytesToSend.Length);
}
The browser appears to connect to it, but it never seems to display the html - what's wrong? I'm eventually wanting to be able to serve up JSON data via a REST interface. In addition, is there a much easier solution to (I assume) this common problem.
I have this simple tcp server class
class Server
{
private TcpListener tcpListener;
private Thread listenThread;
public Server()
{
this.tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
Console.WriteLine("Hello");
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
Console.WriteLine("New connexion");
clientThread.Start(client);
}
}
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
Console.WriteLine("Got Stream");
byte[] message = new byte[4096];
int bytesRead;
Console.WriteLine("Initializing..");
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
Console.WriteLine("Reading..");
bytesRead = clientStream.Read(message, 0, 4096);
Console.WriteLine("Received something");
}
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.WriteLine(encoder.GetString(message, 0, bytesRead));
}
tcpClient.Close();
}
}
I simply call it in the main function like this :
Server server = new Server();
And in a separate client program I have this class
class TheClient
{
public void ConnectV2()
{
TcpClient client = new TcpClient();
IPEndPoint serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 3000);
client.Connect(serverEndPoint);
NetworkStream clientStream = client.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
for (int i = 0; i < 20; i++)
{
byte[] buffer = encoder.GetBytes("Hello Server! " + i.ToString() + " ");
Console.WriteLine("Processing..");
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
Console.WriteLine("Hello Server sent");
}
}
}
I call it in the main function like
TheClient tc = new TheClient();
tc.ConnectV2();
My problem is that the server program seems slower than the client, he don't react before the 13th, or more, message from the client :
[I can't post images because of reputation]
It reads the first dozen of messages in one go, and then reads the others one by one.
And if I make the server emit first, the client receive the message, but they both stop, like if both wait for the other to send something.
Can someone explain me this behavior ? How can I control and synchronize it ?
TCP is not message based. It provides a stream of bytes. It is your responsibility to separate messages. Also note, that you might receive only a part of a message in one Read call.
Here's a simple way to do that: Send the messages as individual lines. Possibly using StreamWriter. Receive the messages using StreamReader.ReadLine().
That way you can also use a more sane encoding such as Encoding.UTF8.
Besides that your code is actually fine and workable. It is extremely rare to see almost working TCP code on Stack Overflow. Most code is horribly broken. Congratulations.
It's because that your client AP is always sending data ,but your server AP cannot receive those data right away. So,those data stacked in buffer and then server AP receive all at once.
You can try:
Set fixed lengths when you send or receive data.
or
Receive and split data.
I am trying to connect with a robot controller from PC using TCP/IP. The robot controller accepts only the ASCII string data from the PC (TCP Client). According to the Robot controller's command structure I have to send a particular string and get ACK from it to get the access.
I used the following code
try
{
System.Net.IPAddress IPADD = System.Net.IPAddress.Parse("192.168.255.2");
int PortNo = 80;
char[] ok = new char[33];
byte[] Data = new byte[33];
byte[] StartReq = new byte[21];
String Start = "CONNECT Robot_access";
// INITIALIZING TCP CLIENT
TcpClient TCP = new TcpClient();
Console.WriteLine("Connecting..........");
TCP.Connect(IPADD, PortNo);
Console.WriteLine("Connected");
NetworkStream NS = TCP.GetStream();
// START REQUEST
StartReq = Encoding.ASCII.GetBytes(Start);
NS.Write(StartReq, 0, StartReq.Length);
Console.WriteLine("start request send..........");
// RECEIVE ACK FOR ROBOT ACCESS
Int32 RespData = NS.Read(Data, 0, Data.Length);
string ACK = Encoding.ASCII.GetString(Data, 0, RespData);
Console.WriteLine("The ACK is {0} ", ACK);
Console.WriteLine("ACK Received");
Console.Read();
}
catch (Exception e)
{
Console.WriteLine(e.StackTrace);
Console.Read();
}
I have aslo tried Streamwriter and Bufferstream to send and receive string couldn't succeed. My program runs through completely without any exception (except a 30s delay for Networkstream reading).
I am working on a c# and php project where the PHP script opens a socket to a c# program and the c# program will read the data and then send a response back.
In the PHP script I have the following:
echo "Opening Client";
$fp = fsockopen("127.0.0.1", 12345, $errno, $errstr, 30);
if (!$fp)
{
echo "Error: $errstr ($errno)<br />";
}
else
{
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: 127.0.0.1\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp))
{
echo fgets($fp, 128);
}
fclose($fp);
}
In the C# project I have the following:
public void startListen()
{
int port = 12345;
IPAddress serverAddress = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(serverAddress, 12345);
listener.Start();
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
byte[] data = new byte[client.ReceiveBufferSize];
int bytesRead = stream.Read(data, 0, Convert.ToInt32(client.ReceiveBufferSize));
string request = Encoding.ASCII.GetString(data, 0, bytesRead);
Console.WriteLine(request);
Console.ReadLine();
The PHP script seems to stay waiting and doesn't finish, I'm guessing its being its because the socket on the c# app to send a response back but I have no idea how to do this. Another problem, in the C# I need to have Console.ReadLine() otherwise the c# program will exit but the PHP Script does then finish as expected.
Basically, what I want to know is this the best way to read the data that is sent on the socket, what is the best way to keep the program running so it keep on listening on the socket and how I send back a reply so that the php script can finish.
Thanks for any help you can provide.
I managed to figure this out, after processing the data I need to then send a stream.write which is what sends the reply back.
Below is the code
int port = 12345;
IPAddress serverAddress = IPAddress.Parse("127.0.0.1");
TcpListener listener = new TcpListener(serverAddress, port);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
NetworkStream stream = client.GetStream();
byte[] data = new byte[client.ReceiveBufferSize];
int bytesRead = stream.Read(data, 0, Convert.ToInt32(client.ReceiveBufferSize));
string request = Encoding.ASCII.GetString(data, 0, bytesRead);
Console.WriteLine(request);
byte[] msg = System.Text.Encoding.ASCII.GetBytes("200 OK");
// Send back a response.
stream.Write(msg, 0, msg.Length);
client.Close();
}
Thanks for your help
Mr. Boardy's solution is correct but I think doing this by socket is better.
So the socket solution is:
private void Form3_Load(object sender, EventArgs e)
{
sc_listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ip_local = new IPEndPoint(IPAddress.Loopback, 1225);
sc_listener.Bind(ip_local);
sc_listener.Listen(10);
AsyncCallback callback = new AsyncCallback(procces_incoming_socket);
sc_listener.BeginAccept(callback, sc_listener);
}
void procces_incoming_socket(IAsyncResult socket_object)
{
Socket sc_listener = ((Socket)socket_object.AsyncState).EndAccept(socket_object);
AsyncCallback receive = new AsyncCallback(receive_data);
buffer = new byte[100];
sc_listener.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, receive, sc_listener);
}
void receive_data(IAsyncResult socket)
{
// the system need to wait so i make a loop when it gets data
//i end the loop by flag=false
bool flag = true;
Socket re_socket = ((Socket)socket.AsyncState);
while(flag)
{
int bytes_recieved = re_socket.EndReceive(socket);
string data = UTF8Encoding.UTF8.GetString(buffer);
if (textBox1.InvokeRequired)
{
// for cross thread problem
textBox1.Invoke(new MethodInvoker(delegate { textBox1.Text = data; }));
}
else
{
textBox1.Text = data;
}
flag = false;
}
string back_data = "my pm socket back";
byte[] buffers = new byte[50];
buffers = UTF8Encoding.UTF8.GetBytes(back_data);
re_socket.Send(buffers);
// if the socket is not closed php will load for maximum required time and then error
re_socket.Close();
//start for next listening (O-0)
AsyncCallback callback = new AsyncCallback(procces_incoming_socket);
sc_listener.BeginAccept(callback, sc_listener);
}
I am not a php guy by any stretch of the imagination so my answer is contingent upon php being able to respond correctly. On the C# side, create a while/do-while loop that continues to run to accept the next incoming request. Here's a simple example:
http://www.csharp-examples.net/socket-send-receive/
Make sure to set the NoDelay option so that the information is flushed.