I have written some code to transfer data from external server to Hololens. I am able to connect Hololens to the server. But I am facing problem in sending the data from server to Hololens. Whenever I call ReadData function it isn't even connected(it prints Not connected).
I am quite new to c# and unity and isn't able to sort out this matter yet.
I am using StreamSocket and DataReader classes to connect and read the data respectively. Function Connect() connects with the server in start() method and then I call ReadData function in update() method to get the data from the server at every frame. I am attaching my code file.
Can you help me out in solving my problem Thanks in advance.
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using System.Text;
using System.Net;
using System;
using UnityEngine;
#if !UNITY_EDITOR && UNITY_METRO
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using Windows.Networking;
using Windows.Foundation;
#endif
public class TCPclientRead : MonoBehaviour
{
public string ServerIP = "10.1.2.35";
[Tooltip("The connection port on the machine to use.")]
public int ConnectionPort = 11000;
private string data = "connected" ;
public TextMesh mesh;
private bool connected = false;
#if !UNITY_EDITOR && UNITY_METRO
private StreamSocket networkConnection;
/// <summary>
/// Temporary buffer for the data we are recieving.
/// </summary>
//private byte[] dataBuffer;
public void Connect( )
{
// Setup a connection to the server.
HostName networkHost = new HostName(ServerIP.Trim());
//HostName networkHost = new HostName( IPAddress.Any.ToString());
networkConnection = new StreamSocket();
// Connections are asynchronous.
// !!! NOTE These do not arrive on the main Unity Thread. Most Unity operations will throw in the callback !!!
IAsyncAction outstandingAction = networkConnection.ConnectAsync(networkHost, ConnectionPort.ToString());
AsyncActionCompletedHandler aach = new AsyncActionCompletedHandler(NetworkConnectedHandler);
outstandingAction.Completed = aach;
}
public void NetworkConnectedHandler(IAsyncAction asyncInfo, AsyncStatus status)
{
if (status == AsyncStatus.Completed)
{
connected = true;
// Here Just display connected
}
else
{
connected = false;
Debug.Log("Failed to establish connection. Error Code: " + asyncInfo.ErrorCode);
// In the failure case we'll requeue the data and wait before trying again.
networkConnection.Dispose();
}
}
public void ReadData()
{
if(connected)
{
DataReader reader = new DataReader(networkConnection.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
reader.LoadAsync(512);
data = reader.ReadString(512);
}
}
private void Start()
{
mesh = gameObject.GetComponent<TextMesh>();
Connect();
}
private void Update()
{
if (connected)
{
mesh.text = data;
}
else
mesh.text = "Not Connected";
ReadData();
}
#endif
}
Edit : 1. I have doubt that ReadData() needs to be called asynchronously Therefore I updated the code but it isn't working even now.
2. I am using Unity Editor and I have enabled the required settings and I am able to connect to the server. It's just that I am not able to transfer the data.
3. I am using netcat to create server.
My updated code
delegate void DelegateMethod();
public async void ReadData()
{
if(connected)
{
DataReader reader = new DataReader(networkConnection.InputStream);
reader.InputStreamOptions = InputStreamOptions.Partial;
await reader.LoadAsync(512);
data = reader.ReadString(512);
}
}
public void AsynCall()
{
DelegateMethod dlgt = new DelegateMethod(this.ReadData);
IAsyncResult ar = dlgt.BeginInvoke(null, null);
dlgt.EndInvoke(ar);
}
private void Start()
{
mesh = gameObject.GetComponent<TextMesh>();
Connect();
}
private void Update()
{
if (connected)
{
if(String.IsNullOrEmpty(data))
data = "Improper";
AsynCall();
mesh.text = data;
}
else
mesh.text = "Not Connected";
}
My suspicion is that you have not enabled the UWP Capability "InternetClient" which would prevent it from actually connecting to the remote server. You don't mention what tool chain you are using, but if you are in Unity check under Build Settings -> Publish Settings -> Windows Store -> Publishing Settings -> Capabilities. If you are working in Visual Studio, you can adjust this in the project properties.
Related
I have searched everywhere but couldn't find as they are all answering to send message to all clients. What I want to achieve is multiple clients request to server to request data from another client and other client sends data to server telling it that data is for requesting client and so. I don't know how to achieve this. I'm new to this.
What I want to achieve:
I have tried with Data sending client to listen and requesting client to connect to it and transfer data. I have achieved this on local network but to make it work online it needs port forwarding and my user will be a lot of different people so port forwarding is not possible for every user. So I can rent a server which will act as a center of transfer. I programmed a test server in console which will listen to a server IP:port X and accept new clients and their data on port X and forward it to server IP:port Y but what this does is send data to all clients on port Y. I cannot send it to clients public ip address directly for obvious reasons. I understand that all the requesting clients are connected to port Y but I cannot create and assign new ports to all the clients interacting. So I want a way to determine how to request and receive the data without the need of assigning or creating new ports to different clients on same server.
What I have tried:
Server code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Test___server
{
class server
{
public static string serverIP = "192.168.0.102";
static void Main(string[] args)
{
Thread listenSendingThread = new Thread(listenSending);
listenSendingThread.IsBackground = true;
listenSendingThread.Start();
Thread listenReceivingThread = new Thread(listenReceiving);
listenReceivingThread.IsBackground = true;
listenReceivingThread.Start();
Console.ReadKey();
}
public static List<TcpClient> listSending = new List<TcpClient>();
public static List<TcpClient> listReceiving = new List<TcpClient>();
public static TcpClient clientSending = null;
private static void listenSending()
{
TcpListener listenerSending = new TcpListener(IPAddress.Parse(serverIP), 5319);
listenerSending.Start();
Console.WriteLine("Server listening to " + serverIP + ":5319");
while(true)
{
clientSending = listenerSending.AcceptTcpClient();
listSending.Add(clientSending);
Console.WriteLine("Sender connection received from " + clientSending.Client.RemoteEndPoint);
}
}
private static void send()
{
StreamWriter sw = new StreamWriter(clientSending.GetStream());
sw.WriteLine(message);
sw.Flush();
Console.WriteLine("Message sent!");
}
public static string message = string.Empty;
private static void listenReceiving()
{
TcpListener listener = new TcpListener(IPAddress.Parse(serverIP), 0045);
listener.Start();
Console.WriteLine("Server listening to " + serverIP + ":0045");
while (true)
{
TcpClient client = listener.AcceptTcpClient();
listReceiving.Add(client);
Console.WriteLine("Receiver connection received from " + client.Client.RemoteEndPoint);
StreamReader sr = new StreamReader(client.GetStream());
message = sr.ReadLine();
send();
}
}
}
}
Requesting client code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Test____admin
{
class admin
{
static void Main(string[] args)
{
Console.WriteLine("Begin");
string serverIP = "192.168.0.102";
System.Net.Sockets.TcpClient clientSocket = new System.Net.Sockets.TcpClient();
clientSocket.Connect(serverIP, );
Console.WriteLine("Connected");
while (true)
{
Console.WriteLine("Reading");
StreamReader sr = new StreamReader(clientSocket.GetStream());
Console.WriteLine("Message: " + sr.ReadLine());
}
}
}
}
Request satisfying client code
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace Test___client
{
class client
{
public static string serverIP = "192.168.0.102";
static void Main(string[] args)
{
clientConnect();
}
private static void clientConnect()
{
try
{
TcpClient client = new TcpClient(serverIP, 0045);
StreamWriter sw = new StreamWriter(client.GetStream());
sw.WriteLine("Karan!");
sw.Flush();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
}
You are using a very low-level API, and doing it the right way is challenging. Instead, try YARP as a reverse proxy. The requesting client should notify the reverse proxy about the desired destination client. One option is sending the destination client name in the request header. You will also need to split a single server request into multiple client requests, then merge their responses into a single one. You can achieve it by implementing Transphorms.
I'm not sure this approach applies to your situation because clients should implement server API using REST, Grpc or any other supported technology.
I have a MCU that is sending data to serial port. I want Unity3D to read the data. So far, nothing I have found works and I'm looking for some help on getting Unity to read the serial port.
Expected behavior is for the serial data to be saved to a string in order to perform operations with the data contained.
At the moment, when I run the Unity editor everything is fine until I actually try to read the serial port. As soon as an attempt is made to read the serial port the Unity editor totally freezes. There are no error logs, no console errors within the editor (since it is frozen), and the editor does not respond to my inputs (clicks, scrolls, etc.).
The solution at this point is to open the task manager and end the task for the Unity editor.
My current implementation is utilizing threads, however, I'm looking for the best practice to read serial port. Perhaps coroutines? Anyway, here's what I have so far.
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using System.IO.Ports;
using UnityEngine;
public class Arduino_Read_Serial : MonoBehaviour
{
[Header("Settings")]
[SerializeField] private bool enableReadThread = false;
private SerialPort data_stream = new SerialPort("COM6", 115200);
[SerializeField] private string receivedString;
private Thread readThread;
void Start()
{
data_stream.WriteTimeout = 300;
data_stream.ReadTimeout = 5000;
data_stream.DtrEnable = true;
data_stream.RtsEnable = true;
data_stream.Open();
if (data_stream.IsOpen)
{
readThread = new Thread(ReadThread);
}
}
void Update()
{
if (enableReadThread && data_stream.IsOpen)
{
readThread.Start();
enableReadThread = false;
}
else
{
Debug.Log("Pulse...");
}
if (receivedString != "")
{
//readThread.
}
//string[] datas = receivedString.Split(',');
//Debug.Log(datas);
}
void ReadThread()
{
while (data_stream.IsOpen)
{
receivedString = data_stream.ReadLine();
}
}
public void OnApplicationQuit()
{
Debug.Log("Thread stopped...");
readThread.Abort();
}
}
Any insight on some best practices for reading the serial port in Unity would be supremely appreciated.
These are the answers I attempted to use but none of them are working:
[1] Unity Serial.ReadLine() issue
[2] https://answers.unity.com/questions/1696938/arduino-serial-delegate-help.html
[3] https://answers.unity.com/questions/1735855/unity-crashes-when-connecting-to-a-serial-port.html
[4] https://forum.unity.com/threads/cant-use-system-io-ports.141316/
[5] https://www.youtube.com/watch?v=5ElKFY3N1zs
I am trying to receive socket communication with C # on Unity.
The following unityRecieve.cs will result in an error if Send.py is interrupted.
Send.py
import socket
import random
HOST = '127.0.0.1'
PORT = 50007
client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
a = random.randrange(3)
result = str(a)
print(a)
client.sendto(result.encode('utf-8'),(HOST,PORT))
time.sleep(2.0)
unityRecieve.cs
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class unityRecieve : MonoBehaviour
{
static UdpClient udp;
void Start()
{
int LOCA_LPORT = 50007;
udp = new UdpClient(LOCA_LPORT);
udp.Client.ReceiveTimeout = 100;
}
void Update()
{
IPEndPoint remoteEP = null;
byte[] data = udp.Receive(ref remoteEP);
string text = Encoding.UTF8.GetString(data);
Debug.Log(text);
}
}
https://jump1268.hatenablog.com/entry/2018/11/25/143459
How can I make unitiRecieve.cs keep running without giving an error message when Send.py is interrupted?
Not sure if you have considered exception handling. If you did not, this might point you in the right direction.
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/try-catch
I am a beginner in networking but I have to start with something, so I decided to create a chat app in visual studio 2010 using C# language (winforms).
I googled a lot about that and I've found almost exactly what I needed.
I found the following code samples (in C# - console):
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx
http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener(v=VS.71).aspx
I want to create that application using TCP protocol (I don't know if there are easier ways to do that, but I understood the basics of TCP when I tried to create that chat in C#.
When I executed the code samples in the links above, they worked! So I tried to adapt those samples at my chat application.
My chat application consists actually of two apps: a server and a client. Both of them have the same GUI (two text boxes, a button and two labels for displaying whether the client is connected to the server).
textBox1 on the server/client app is the one that display the message sent by the client/server app.
In the textBox2 on the server/client app the user types a message and then presses the button to send the message to the client/server app.
Let me show you what I've tried until now:
This is the server application 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;
using System.Net.Sockets;
namespace Server_TCP_WINFORMS
{
public partial class Form1 : Form
{
//Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 13000);
public Form1()
{
InitializeComponent();
server.Start();
}
byte[] bytes = new byte[256];
String data = null;
TcpClient client = new TcpClient();
bool sw = true;
int data_at_byte_level = 0;
private void Form1_Load(object sender, EventArgs e)
{
try
{
label2.Text = "Waiting for an incoming connection...";
if (!server.Pending())
{
label2.Text = "For moment, there are no connections requests!";
}
else
{
client = server.AcceptTcpClient();
label2.Text = "Connected!";
sw = false;
}
}
catch (SocketException xyz)
{
MessageBox.Show("Exception occured!");
}
if (sw == false)
{
NetworkStream stream = client.GetStream();
while ((data_at_byte_level = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes);
textBox1.Text += data;
data = null;
bytes = null;
}
}
}
private void button1_Click(object sender, EventArgs e)
{
String dataT;
if (textBox2.Text!=null && sw == false)
{
NetworkStream stream = client.GetStream();
dataT = textBox2.Text;
byte[] msg = System.Text.Encoding.ASCII.GetBytes(dataT);
stream.Write(msg, 0, msg.Length);
}
}
}
}
And this is the client application 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;
namespace Client_TCP_WINFORMS
{
public partial class Form1 : Form
{
TcpClient client = new TcpClient("127.0.0.1", 13000);
public Form1()
{
InitializeComponent();
label2.Text = "Conected to the server!";
}
private void button1_Click(object sender, EventArgs e)
{
NetworkStream stream = client.GetStream();
if (textBox2.Text != null)
{
String data_str = textBox2.Text;
Byte[] data_byte = System.Text.Encoding.ASCII.GetBytes(data_str);
stream.Write(data_byte, 0, data_byte.Length);
}
}
private void Form1_Load(object sender, EventArgs e)
{
Byte[] data_byte = new Byte[290];
int bytes;
string Data;
NetworkStream stream = client.GetStream();
bytes = stream.Read(data_byte, 0, data_byte.Length);
Data = System.Text.Encoding.ASCII.GetString(data_byte, 0, bytes);
textBox1.Text += Data;
}
}
}
I want that those two apps to behave in the following way: I start the server application then I start the client application. When both of them are open, I want them to be already connected (because it's simpler that way, I think).
Then, I want that both of them to be receptive which means that when the server (for example) sends a message to the client, the latter one should receive the message and display it. If the server send another message, the client should receive and display it too.
If the user (of the client or the user of the server) presses the send button, the application should send the message from the textBox2 to the other application. How can I do those things in windows forms?
I see in the code samples in console that there is a main loop where the server reads the message from the client. But what if the server wants to send a message too? If the send button is pressed, the event for the button_pressed occurs and then it sends the message, but when it finished sending the message, it goes back to the main loop?
Please excuse my english. I am not a native speaker.
Thank you respectfully.
"When both of them are open, I want them to be already connected (because it's simpler that way, I think)."
For this, you need to use UDP(User Datagram Protocol) rather than TCP
I have a library that handles reading and writing a cache file. This library is used by a Windows Service and several instances of a console application on the same machine. The console application runs when a user logs in.
I am getting occasional IO errors saying the cache file is in use by another process. I assume that collisions are occurring between the different application instances and service trying to read and write at the same time.
Is there a way to lock the file when it is in use and force all other requests to "wait in line" to access the file?
private void SaveCacheToDisk(WindowsUser user) {
string serializedCache = SerializeCache(_cache);
//encryt
serializedCache = AES.Encrypt(serializedCache);
string path = user == null ? ApplicationHelper.CacheDiskPath() :
_registry.GetCachePath(user);
string appdata = user == null ? ApplicationHelper.ClientApplicationDataFolder() :
_registry.GetApplicationDataPath(user);
if (Directory.Exists(appdata) == false) {
Directory.CreateDirectory(appdata);
}
if (File.Exists(path) == false) {
using (FileStream stream = File.Create(path)) { }
}
using (FileStream stream = File.Open(path, FileMode.Truncate)) {
using (StreamWriter writer = new StreamWriter(stream)) {
writer.Write(serializedCache);
}
}
}
private string ReadCacheFromDisk(WindowsUser user) {
//cache file path
string path = user == null ? ApplicationHelper.CacheDiskPath() :
_registry.GetCachePath(user);
using (FileStream stream = File.Open(path, FileMode.Open)) {
using (StreamReader reader = new StreamReader(stream)) {
string serializedCache = reader.ReadToEnd();
//decrypt
serializedCache = AES.Decrypt(serializedCache);
return serializedCache;
}
}
}
Sure, you could use a mutex and permit access only when holding the mutex.
You could use a cross-process EventWaitHandle. This lets you create and use a WaitHandle that's identified across processes by name. A thread is notified when it's its turn, does some work, and then indicates it's done allowing another thread to proceed.
Note that this only works if every process/thread is referring to the same named WaitHandle.
The EventWaitHandle constructors with strings in their signature create named system synchronization events.
One option you could consider is having the console applications route their file access through the service, that way there's only one process accessing the file and you can synchronise access to it there.
One way of implementing this is by remoting across an IPC channel (and here's another example from weblogs.asp.net). We used this technique in a project for the company I work for and it works well, with our specific case providing a way for a .net WebService to talk to a Windows Service running on the same machine.
Sample based on the weblogs.asp.net example
Basically what you need to do with the code below is create a Solution, add two Console Apps (one called "Server" and the other called "Client" and one Library to it. Add a reference to the Library to both console apps, paste the code below in and add a reference to System.Runtime.Remoting to both Server & Console.
Run the Server app, then run the client app. Observe the fact that the server app has a message passed to it by the client. You can extend this to any number of messages/tasks
// Server:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
namespace RemotingSample
{
public class Server
{
public Server()
{
}
public static int Main(string[] args)
{
IpcChannel chan = new IpcChannel("Server");
//register channel
ChannelServices.RegisterChannel(chan, false);
//register remote object
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(RemotingSample.RemoteObject),
"RemotingServer",
WellKnownObjectMode.SingleCall);
Console.WriteLine("Server Activated");
Console.ReadLine();
return 0;
}
}
}
// Client:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using RemotingSample;
namespace RemotingSample
{
public class Client
{
public Client()
{
}
public static int Main(string[] args)
{
IpcChannel chan = new IpcChannel("Client");
ChannelServices.RegisterChannel(chan);
RemoteObject remObject = (RemoteObject)Activator.GetObject(
typeof(RemotingSample.RemoteObject),
"ipc://Server/RemotingServer");
if (remObject == null)
{
Console.WriteLine("cannot locate server");
}
else
{
remObject.ReplyMessage("You there?");
}
return 0;
}
}
}
// Shared Library:
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
namespace RemotingSample
{
public class RemoteObject : MarshalByRefObject
{
public RemoteObject()
{
Console.WriteLine("Remote object activated");
}
public String ReplyMessage(String msg)
{
Console.WriteLine("Client : " + msg);//print given message on console
return "Server : I'm alive !";
}
}
}
Check out the TextWriter.Synchronized method.
http://msdn.microsoft.com/en-us/library/system.io.textwriter.synchronized.aspx
This should let you do this:
TextWriter.Synchronized(writer).Write(serializedCache);