I'm trying to use lua script to extract some data from a program, and then send that data to a c# script which then processed it and returns some simple messages for the lua script to then pass along to the program.
The lua script is as follows
-- Socket decls
local socket = require("socket")
local host, port = "127.0.0.1", 3000
local tcp = assert(socket.tcp())
tcp:connect(host,port)
tcp:settimeout(0)
tcp:send("Stream starting...")
function sendEventInfoToServer(string)
tcp:send(string)
end
function processEventInfo()
local received, status = tcp:receive()
if received ~= nil then
print(received, status);
end
end
while true do
-- unrelated logic
processEventInfo();
end
and on the C# end
public class SimpleTCPListener
{
private TcpListener tcpListener;
private TcpClient _tcpClient;
private Thread listenThread;
private NetworkStream clientStream;
List<string> eventsWaiting;
public List<string> EventsWaiting {
get {
List<string> tempList = new List<string>();
for (int i = 0; i < eventsWaiting.Count; i++)
tempList.Add(eventsWaiting[i]);
EventsWaiting = new List<string>();
return tempList;
}
private set { eventsWaiting = value; }
}
public SimpleTCPListener()
{
EventsWaiting = new List<string>();
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
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(HandleClientCom));
clientThread.Start(client);
clientStream = client.GetStream();
}
}
public void SendSavestateLoadRequest()
{
if(clientStream != null)
{
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes("HelloLua!\n");
Console.WriteLine("Sending data back to lua");
if (clientStream.CanWrite)
clientStream.Write(buffer, 0, buffer.Length);
else
Console.WriteLine("Connection close!");
//clientStream.Flush();
}
}
private void HandleClientCom(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
byte[] message = new byte[4096];
int bytesRead;
while(true)
{
bytesRead = 0;
try
{
// blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
// a socket error has occured
break;
}
if(bytesRead == 0)
{
// the client disconnected
break;
}
// message has been recieved
ASCIIEncoding encoder = new ASCIIEncoding();
System.Diagnostics.Debug.WriteLine(encoder.GetString(message, 0, bytesRead));
string s = encoder.GetString(message, 0, bytesRead);
Console.WriteLine(s);
if (!string.IsNullOrEmpty(s))
eventsWaiting.Add(s);
}
tcpClient.Close();
}
}
Now, the Lua talks to the C# thread no problem, and the C# doesn't report any errors when sending data back to the lua, but on the lua side it's constantly receiving nil, however if I remove the nil check it sometimes receives and prints the string, but with the nil check it never seems to find 'received' as not nil. I'm really new with lua script so hopefully it's something simple I'm not understanding about the syntax but I can't seem to find lot of documentation.
Any suggestions would be hugely appreciated.
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.
static void Main(string[] args)
{
Console.Title = "Socket Server";
Console.WriteLine("Listening for client messages");
Socket serverSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPAddress serverIp = IPAddress.Any;
IPEndPoint serverEP = new IPEndPoint(serverIp, 8000);
SocketPermission socketPermission = new SocketPermission(NetworkAccess.Accept,
TransportType.Tcp,
"127.0.0.1", 8000);
serverSocket.Bind(serverEP);
serverSocket.Listen(2);
while(true)
{
//Socket connection = serverSocket.Accept();
connection = serverSocket.Accept();
Thread clientThread = new Thread(new ParameterizedThreadStart(MultiUser));
clientThread.Start(connection);
}
}
public static void MultiUser(object connection)
{
byte[] serverBuffer = new byte[10025];
string message = string.Empty;
int bytes = ((Socket)connection).Receive(serverBuffer, serverBuffer.Length, 0);
message += Encoding.ASCII.GetString(serverBuffer, 0, bytes);
Console.WriteLine(message);
TcpClient client = new TcpClient();
client.Client = ((Socket)connection);
IntPtr handle = client.Client.Handle;
}
I want to write a chat program which has one server and 2 clients. The problem is that, I can not direct the message sent from the client1 to client2 via the server. How can the server distinguish threads so that it can send the received message from client1 to client2?
Each client has their own handle. You can access this via the Handle property. For example:
TcpClient client = tcpListener.AcceptTcpClient();
IntPtr handle = client.Client.Handle; //returns a handle to the connection
Then all you need to do is store this in a hashtable, and iterate through it, looking for available data. When you detect data on the wire for one of the connections, then save it and retransmit it to the other clients in the table.
Remember to make sure that you make this multithreaded so a listen request on one client does not block any send or receive functions on other clients!
I've added some code here you should be able to work with (tested it out on my system)
private void HandleClients(object newClient)
{
//check to see if we are adding a new client, or just iterating through existing clients
if (newClient != null)
{
TcpClient newTcpClient = (TcpClient)newClient;
//add this client to our list
clientList.Add(newTcpClient.Client.Handle, newTcpClient);
Console.WriteLine("Adding handle: " + newTcpClient.Client.Handle); //for debugging
}
//iterate through existing clients to see if there is any data on the wire
foreach (TcpClient tc in clientList.Values)
{
if (tc.Available > 0)
{
int dataSize = tc.Available;
Console.WriteLine("Received data from: " + tc.Client.Handle); //for debugging
string text = GetNetworkString(tc.GetStream());
//and transmit it to everyone else
foreach (TcpClient otherClient in clientList.Values)
{
if (tc.Client.Handle != otherClient.Client.Handle)
{
Send(otherClient.GetStream(), text);
}
}
}
}
}
public void Send(NetworkStream ns, string data)
{
try
{
byte[] bdata = GetBytes(data, Encoding.ASCII);
ns.Write(bdata, 0, bdata.Length);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex.Message);
}
}
protected string GetNetworkString(NetworkStream ns)
{
if (ns.CanRead)
{
string receivedString;
byte[] b = GetNetworkData(ns);
receivedString = System.Text.Encoding.UTF8.GetString(b);
log.Info("Received string: " + receivedString);
return receivedString;
}
else
return null;
}
protected byte[] GetNetworkData(NetworkStream ns)
{
if (ns.CanRead)
{
log.Debug("Data detected on wire...");
byte[] b;
byte[] myReadBuffer = new byte[1024];
MemoryStream ms = new MemoryStream();
int numberOfBytesRead = 0;
// Incoming message may be larger than the buffer size.
do
{
numberOfBytesRead = ns.Read(myReadBuffer, 0, myReadBuffer.Length);
ms.Write(myReadBuffer, 0, numberOfBytesRead);
}
while (ns.DataAvailable);
//and get the full message
b = new byte[(int)ms.Length];
ms.Seek(0, SeekOrigin.Begin);
ms.Read(b, 0, (int)ms.Length);
ms.Close();
return b;
}
else
return null;
}
You will want to call HandleClients from a main thread that checks to see if there are any pending requests or not, and runs on a loop.
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.