UDP behavior goes wrong when using two identical scripts in Unity - c#

I attached two of the following scripts to a single GameObject.
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
public class TestScript : MonoBehaviour
{
static UdpClient udp;
private string udp_message = "";
Thread thread;
public int port = 8888;
void Start()
{
udp = new UdpClient(port);
thread = new Thread(new ThreadStart(ThreadMethod));
thread.Start();
}
// Update is called once per frame
void Update()
{
string port_string = port.ToString();
Debug.Log(port_string + ":" + udp_message);
}
void ThreadMethod()
{
while (true)
{
try
{
IPEndPoint remoteEP = null;
byte[] data = udp.Receive(ref remoteEP);
udp_message = Encoding.ASCII.GetString(data);
}
catch
{
}
}
}
}
Then, I used 8888 as the port for one script, as shown in the following image. The other script used port 8889.
I am using two different ports on 8888 and 8889.
However, when I send data to only the 8888 port, the UDP on the 8889 port also seems to be responding.
What is the cause of this?
How can I fix it?

Well your udp field is static!
Both instances of your component overwrite it with different references in
udp = new UdpClient(port);
So basically whichever script runs last "wins" and you are only ever using that UdpClient instance.
Later both your threads will access the very same udp reference for doing
udp.Receive(...);
Simply do not make you field static and you should be fine ^^
private UdpClient udp;
And to your empty catch block ... I would at least make it
catch(Exception e)
{
Debug.LogException(e);
}
which displays an error in the console but doesn't interrupt the thread.
And then also make sure to clean up!
private void OnDestroy()
{
thread?.Abort();
udp?.Dispose();
}
otherwise you might end up with zomby threads or blocked UDP ports ;)

Related

Detect SQL event with C# application

I have the code below (a literal copy/paste from MSDN website just to be clear), which seems to connect as it should (except for an "Access Denied" error which is okay because my security requests haven't gone through yet). What I need to do is detect when our sql server has executed an insert or update operation. Basically this application should be running 24/7 and perform certain functions when an operation as such comes across the listener. I'm not asking for the code to be laid out in front of me, but I am asking where to start. This is something I have no clue how to do at this point and am being told I have roughly a week to figure it out and get it done. Can someone point me in the right direction? Thank you in advance!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Connect_Server
{
class Program
{
static string output = "";
static void Main(string[] args)
{
createListener();
}
static public void createListener()
{
// Create an instance of the TcpListener class.
TcpListener tcpListener = null;
IPAddress ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
// Set the listener on the local IP address
// and specify the port.
tcpListener = new TcpListener(ipAddress, 80);
tcpListener.Start();
output = "Waiting for a connection...";
}
catch (Exception e)
{
output = "Error: " + e.ToString();
Console.Write(output);
}
while (true)
{
// Always use a Sleep call in a while(true) loop
// to avoid locking up your CPU.
Thread.Sleep(10);
// Create a TCP socket.
// If you ran this server on the desktop, you could use
// Socket socket = tcpListener.AcceptSocket()
// for greater flexibility.
TcpClient tcpClient = tcpListener.AcceptTcpClient();
// Read the data stream from the client.
byte[] bytes = new byte[256];
NetworkStream stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
SocketHelper helper = new SocketHelper();
helper.processMsg(tcpClient, stream, bytes);
}
}
}
}
Check out SQL Server Notifications. This will send a signal to your app when some underlying dataset changes. I'm not sure how heavy this is for the server, so if you have a large number of clients waiting for a notification you should load-test it carefully....

Cannot figure out how to get Socket to receive data C#

So what I am specifically trying to do is get a serial proxy going to pipe an arduino into Unity3d to run on linux. System.IO.Ports just doesn't work on linux with unity.
So I have gotten a python based serial proxy script, I have that up and running just fine. I can netcat into that localhost and actually get output from the arduino.
nc localhost 8082
g'day from bitty 1.0 -- type 'logout' to disconnect
Connecting to /dev/tty.usbmodem5d11... connected.
HELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLOHELLO
I have the arduino only printing out HELLO on repeat.
But the serial proxy is up and running, and has data going over it.
Now I am trying to write the code in Unity to receive this data, and I just can't get it to work.
This is my code for that:
public Socket socket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
public byte[] buffer = new byte[256];
int pinRead = 0;
void Start ()
{
socket.Connect(IPAddress.Parse("127.0.0.1"),8082);
}
void Update ()
{
if (socket.IsBound)
{
try
{
int bytesRead;
bytesRead = socket.Receive(buffer);
string incommingdata = System.Text.Encoding.ASCII.GetString(buffer);
Debug.Log(bytesRead+" || "+incommingdata);
}
catch (System.Exception e)
{
}
}
bytesRead is ALWAYS 0 and incomingData just doesn't have anything. It connects, and isBound returns true. I just can't get the code right to receive the data and put it in a format that is usable.
Please help. I need to get this working and its far out of my area of expertise. How do I make this work?
So I got this to work using tcpclient objects and some snippets of code that were posted on a random unity blog....
Here it is if anyone wants to see. I would still be really curious to know how to get the Socket implementation functioning though.
using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System;
using System.Text;
using System.IO;
using System.Threading;
public class ArduinoTest : MonoBehaviour
{
private bool socketReady = false;
private TcpClient mySocket;
private NetworkStream theStream;
private StreamWriter theWriter;
private StreamReader theReader;
private string Host = "localhost";
private Int32 Port = 9900;
private int pinRead = 0;
void Start ()
{
setupSocket();
}
void Update ()
{
string read = readSocket();
if (read != "")
{
int value = int.Parse(read);
if ( value > 53)
{
Debug.Log((value-54)+" DOWN");
}
else
{
Debug.Log(value+" UP");
}
}
}
void OnApplicationQuit()
{
writeSocket("logout");
closeSocket();
}
public void setupSocket()
{
try
{
mySocket = new TcpClient(Host, Port);
theStream = mySocket.GetStream();
theWriter = new StreamWriter(theStream);
theReader = new StreamReader(theStream);
socketReady = true;
}
catch (Exception e)
{
Debug.Log("Socket error:" + e);
}
}
public void writeSocket(string theLine)
{
if (!socketReady)
return;
String tmpString = theLine + "\r\n";
theWriter.Write(tmpString);
theWriter.Flush();
}
public string readSocket()
{
if (!socketReady)
return "";
if (theStream.DataAvailable)
return theReader.Read().ToString();
return "";
}
public void closeSocket()
{
if (!socketReady)
return;
theWriter.Close();
theReader.Close();
mySocket.Close();
socketReady = false;
}
public void maintainConnection()
{
if(!theStream.CanRead)
{
setupSocket();
}
}
}
(Sorry I can't post comments yet or would do so there)
BytesRead = 0 typically means the remote side disconnected.
For what it's worth, your code works fine when I run a test TCP server listening for connections on port 8082 and sending out some text messages. So I doubt the problem is on the C# client-side.
Beyond this simple example, "getting this to work" is not necessarily a simple question. Here are a couple things you should keep in mind:
You are making a blocking Receive call, which means you will need to call Update in a loop.
TCP is a streaming protocol, so you might get partial messages or many messages bundled together in the same Read call. Look up "TCP Framing" to get more details on this.
You can try using telnet on this socket, just to see if you can connect to it.
telnet 127.0.0.1 8082

>1 client can't connect to server in c#

I am creating a chat client in C# to be demonstrated on localhost.
Here's the relevant code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.IO;
using System.Threading;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
static List<TcpListener> garabage_collection_preventor = new List<TcpListener>();
static Dictionary<IPEndPoint, bool> address_dictionary = new Dictionary<IPEndPoint, bool>();
static int port_increment = 9999;
static int client_id = 0;
void start_listening()
{
while (true)
{
TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
garabage_collection_preventor.Add(listen);
listen.Start();
TcpClient client = listen.AcceptTcpClient();
IPEndPoint temp_end = ((IPEndPoint)listen.LocalEndpoint);
address_dictionary.Add(temp_end, false);
port_increment++;
new Thread(new ParameterizedThreadStart(connection_stuff)).Start(client);
}
}
void writer(object ob,int end_point)
{
StreamWriter write = ob as StreamWriter;
while (true)
{
foreach (KeyValuePair<IPEndPoint, bool> value in address_dictionary)
{
IPEndPoint index = value.Key;
int temp = value.Key.Port;
if (temp == end_point)
{
while (address_dictionary[index] == true)
{
write.WriteLine(msg_box.Text);
}
}
}
}
}
void reader(StreamReader read)
{
while (true)
{
MessageBox.Show(read.ReadLine());
}
}
void connection_stuff(object ob)
{
TcpClient client = ob as TcpClient;
int writer_identification_endpoint = ((IPEndPoint)client.Client.LocalEndPoint).Port;
NetworkStream stream = client.GetStream();
StreamReader read = new StreamReader(stream);
StreamWriter write = new StreamWriter(stream);
ThreadStart port_passing = delegate { writer(write, writer_identification_endpoint); };
Thread thread = new Thread(port_passing);
reader(read);
thread.Start();
}
public Form1()
{
InitializeComponent();
}
private void send_Click(object sender, EventArgs e)
{
int end_point = int.Parse(port.Text);
foreach (KeyValuePair<IPEndPoint, bool> value in address_dictionary)
{
IPEndPoint index = value.Key;
int temp = value.Key.Port;
if (temp == end_point)
{
address_dictionary[index] = true;
}
}
}
private void listener_Click(object sender, EventArgs e)
{
new Thread(start_listening).Start();
listener.Enabled = false;
}
}
}
Now the problem is that the first client can easily connect with the program and send messages which this program can easily read. However every subsequent client cannot connect.
I know that I shouldn't be making creating than one TCPListener but the problem is that I have to demonstrate the program on localhost and port number is the only true way to differentiate between client.
So please tell me what's wrong with the code I have been banging my head against the wall on it for hours.
EDIT
this is what happens when english is not a first language :) This code(not complete presently) will be a chat client. Each instance of this code will be able to connect with other instance of this same code to communicate. Any number of instances should be able to connect with any number of instances(like if double click 5 times the program there would now be 5 instances ready to communicate with each other).
Now the problem is that every instance will have the same IP Address(Because they are all running on the same machine). The question arises how say instance 1 suppose to connect to instance 4, ip can't be used here because instance 2,3 and 5 will also have the same IP address. So what i am trying to do is to connect instance 1 with instance 4 with IP Address and PORT instead of just using just the IP Address as is the case with a single TCPListener.
Try moving these three lines of code outside the while(true) loop in your start_listening routine.
TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
garabage_collection_preventor.Add(listen);
listen.Start();
You only need one listener, from which you accept many different connections.
Try it like this:
void start_listening()
{
TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
garabage_collection_preventor.Add(listen);
listen.Start();
while (true)
{
TcpClient client = listen.AcceptTcpClient();
// etc
}
}
That is, once you have created your listener, it runs in the loop accepting incoming connections from the client.
Edit: The problem you are having is because your simulation is flawed. In the real world, each chat server runs in a single O/S instance, on one, known, port number. Because you only have one O/S instance yourself, you can't run multiple chat servers on that instance all listening on the same port. But something like this might work, i.e., you need two loops, the first one to create your listeners, and the second inner loop for each listener to accept multiple clients. Note: these loops need exit conditions!
void start_listening()
{
while (true)
{
TcpListener listen = new TcpListener(IPAddress.Any, port_increment);
garabage_collection_preventor.Add(listen);
listen.Start();
while (true)
{
TcpClient client = listen.AcceptTcpClient();
IPEndPoint temp_end = ((IPEndPoint)listen.LocalEndpoint);
address_dictionary.Add(temp_end, false);
new Thread(new ParameterizedThreadStart(connection_stuff)).Start(client);
}
port_increment++;
}
}

Sanding data from a C# TCP server to connected client outside of the listening thread

I am writing a simple Tcp server in Unity and have my Flash application connects to it. I found a great tutorial on threaded Tcp server online, and my flash app connects to it nicely. However, I am not able to send data outside of the listening thread to the connected client. I tried to create a global reference of the Tcpclient obtained inside of the thread. However, that reference (sclient) only works inside of the listening thread, printed Null to console outside of the thread. There must be something I can do to retain the TCP client reference for later use or access it from outside of block thread. Please help!
using UnityEngine;
using System.Collections;
using System;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
public class TCPServer: MonoBehaviour
{
private TcpListener tcpListener;
private Thread listenThread;
private TcpClient sclient;
public float fireRate = 0.5F;
private float nextFire = 0.0F;
public TCPServer()
{
IPAddress localAddress = IPAddress.Parse("127.0.0.1");
this.tcpListener = new TcpListener(localAddress, 9001);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
public void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
sclient = this.tcpListener.AcceptTcpClient();
print(sclient);//print "System.Net.Sockets.TcpClient" in console
this.sMessage("Can you hear me now?");//this one works fine
}
}
public void sMessage(String m){
print(cStream); //print "Null" to console
NetworkStream clientStream = sclient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(m);
print("Received Connection from " + tcpClient.Client.RemoteEndPoint );
print("Sending message..");
print(clientStream.CanWrite);//returns true in console
clientStream.Write(buffer, 0 , buffer.Length);
clientStream.WriteByte (0);
clientStream.Flush();
}
void Update() {
if (Input.GetButton("Fire1") && Time.time > nextFire) {
nextFire = Time.time + fireRate;
this.sMessage("BOOM BOOM");//this one won't work. keep saying sclient is null
}
}
Where is the method that calls Update?
Sounds like no client has been connected yet when you invoke it.
In general it's besit if you avoid synchronous methods of socket,networkstream, you should use xxxxAsync(socket has such methods) or BeginXXX methods. This gives you high performance with count of connected clients. Ok now about synchornous ... you should create new thread for each new connected client and start session processing on that thread. I suggest you to make some session class for connected client, and all processing in that class.
public class Your_Session
{
private TcpClient m_pClient = null;
public Your_Session(TcpClient client)
{
mpClient = client; // Assign client to mpClient
}
internal void Start(Object state)
{
// NOTE: call this Start method:
// ThreadPool.QueueUserWorkItem(new WaitCallback(session.Start));
// Start your session processing here. This method is called from threapool thread.
}
}
Just call create session class instance(Your_Session session = new YourSession ...) in ListenForClients method and call ThreadPool.QueueUserWorkItem(new WaitCallback(session.Start)); to start session processing.

How can I use a threadpool to process each connection in a new thread

I have a simple server that waits for a client to connect, reads the incoming stream, and sends a message back. What I would like to do is have every connection handled by a separate thread. This is my first time working with sockets and threads in C#, and most of the examples I have found are really confusing, so any help or simple examples would be much appreciated.
Here is what I have right now.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
[STAThread]
static void Main(string[] args)
{
TestServer ts = new TestServer();
ts.Start();
}
class TestServer
{
private readonly int port = 48888;
private readonly IPAddress ip = IPAddress.Parse("127.0.0.1");
private TcpListener listener;
public TestServer()
{
this.listener = new TcpListener(this.ip, this.port);
}
public void Start()
{
this.listener.Start();
Console.WriteLine("Server Running...");
Socket s;
Byte[] incomingBuffer;
int bytesRead;
Byte[] Message;
while (true)
{
s = this.listener.AcceptSocket();
incomingBuffer = new Byte[100];
bytesRead = s.Receive(incomingBuffer);
string message = "Hello from the server";
Message = Encoding.ASCII.GetBytes(message.ToCharArray());
s.Send(Message);
}
}
}
Try this:
public void Start()
{
this.listener.Start();
Console.WriteLine("Server running...");
while (true)
{
Socket s = this.listener.AcceptSocket();
ThreadPool.QueueUserWorkItem(this.WorkMethod, s);
}
}
private void WorkMethod(object state)
{
using (Socket s = (Socket)state)
{
byte[] buffer = new byte[100];
int count = s.Receive(buffer);
string message = "Hello from the server";
byte[] response = Encoding.ASCII.GetBytes(message);
s.Send(response);
}
}
Not answering your question directly, but ...
Thread pools are not about 'new thread per connection', they are about having some meaningful number of threads (with some relation to number of cores on the box) already running and waiting for work. This "work" is given to the pool by the producer thread (the one accepting the connections in your case) via one or more queues.
Please note that this is not always the best solution though. Take a look at C10K and at Hight Performance Server Architecture pages.
Use a threadpool. You can use instantiate threads manually but since you have might have a huge number of connections, a threadpoool is more efficient.
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(processMessage), socket);
processMessage is the method that will process the message. And there will be one thread per connection. Really simple actually.

Categories

Resources