I am testing node.js as TCP server and Unity3d as client for my up coming project.
I create a simple chat interface with unity3d that can send and receive data from the server. Everything seems to work fine until I test with 2 clients, one in Unity editor and another with Unity application, whenever I send the message, the server immediately pickup and display in terminal. But the client side only update the display interface when I click to focus on the client, be it Unity editor or the Unity application itself.
Below are my codes:
Node.js
net = require('net');
var clients = [];
net.createServer(function (socket) {
socket.name = socket.remoteAddress + ":" + socket.remotePort
clients.push(socket);
socket.write("Welcome " + socket.name + "\n");
broadcast(socket.name + " joined the chat\n", socket);
socket.on('data', function (data) {
broadcast(socket.name + "> " + data, socket);
});
socket.on('end', function () {
clients.splice(clients.indexOf(socket), 1);
broadcast(socket.name + " left the chat.\n");
});
function broadcast(message, sender) {
clients.forEach(function (client) {
if (client === sender) return;
client.write(message);
});
process.stdout.write(message)
}
}).listen(5000);
// Put a friendly message on the terminal of the server.
console.log("Chat server running at port 5000\n");
client.cs
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Net.Sockets;
using System.IO;
public class client : MonoBehaviour {
private bool socketReady;
private TcpClient socket;
private NetworkStream stream;
private StreamWriter writer;
private StreamReader reader;
public Text servermessage;
public InputField input;
// Use this for initialization
void Start () {
ConnectToServer ();
}
// Update is called once per frame
void Update () {
if(socketReady){
if(stream.DataAvailable){
string data = reader.ReadLine ();
if(data != null){
OnIncomingData (data);
}
}
}
}
public void ConnectToServer(){
if(socketReady)
return;
string host = "127.0.0.1";
int port = 5000;
try
{
socket = new TcpClient(host,port);
stream = socket.GetStream();
writer = new StreamWriter(stream);
reader = new StreamReader(stream);
socketReady = true;
Debug.Log("socket :"+ reader.ToString());
}
catch (System.Exception e)
{
Debug.Log("socket error :"+ e);
}
}
private void OnIncomingData(string data){
Debug.Log ("server : "+ data);
servermessage.text = data;
}
public void OnOutgoingData(string data){
if (!socketReady)
return;
if (input.text == "") {
writer.WriteLine (data);
} else {
writer.WriteLine (input.text);
}
writer.Flush ();
input.text = "";
}
}
What is missing? How can I make it that I can see the immediate update on all my client interface?
This is not caused by your code, but due to the Unity editor. By default the unity editor does not run applications in the background.
You can turn run-in-background on inEdit > Project Settings > Settings-Player
There should be a field Run in background. Turn it on, and it should update even when you are not focused
See Also Run In background
Related
I'm trying to implement a SCS framework server with WinForms in C# but I am having issues making it work. The server standalone works fine when using it in the Main method (no WinForms). I have a client-sided and a server-sided sample code from the SCS framework that I'm trying to implement in WinForms together with some of my own code. It all went well until I decided to try and use WinForms aswell (I had to move the server code to a class of it's own).
I am not getting any errors when I am starting the server, however I can't connect with the client anymore (worked before I moved the server to a class of its own). Client gets System.Net.Sockets.SocketException. On the server-side, I get the error System.InvalidOperationException when the client is trying to connect.
This is my Form1.cs:
using System;
using System.Windows.Forms;
namespace Server_Test
{
public partial class Form1 : Form
{
public static Form1 Self;
Server server = new Server();
public Form1()
{
InitializeComponent();
Self = this;
}
public void rtb1Text(string text)
{
richTextBox1.AppendText(text);
}
public void rtb2Text(string text)
{
richTextBox2.Text = text;
}
private void button1_Click(object sender, EventArgs e)
{
if (button1.Text.EndsWith("Start"))
{
button1.Text = "Stop";
server.ServerInit();
}
else if (button1.Text.EndsWith("Stop"))
{
button1.Text = "Start";
// Does nothing atm
}
}
}
}
And this is my Server.cs
using System;
using Hik.Communication.Scs.Communication.EndPoints.Tcp;
using Hik.Communication.Scs.Communication.Messages;
using Hik.Communication.Scs.Server;
namespace Server_Test
{
class Server
{
public void ServerInit()
{
// Create a server that listens 10085 TCP port for incoming connections
var server = ScsServerFactory.CreateServer(new ScsTcpEndPoint(10085));
// Register events of the server to be informed about clients
server.ClientConnected += Server_ClientConnected;
server.ClientDisconnected += Server_ClientDisconnected;
// Start the server
server.Start();
// Form1.Self.rtb1Text("Server has been started successfully.\n");
Console.WriteLine("Server has been started successfully.\n");
}
static void Server_ClientConnected(object sender, ServerClientEventArgs e)
{
Form1.Self.rtb1Text("A new client with ID: " + e.Client.ClientId + " has connected.\n");
// Register to MessageReceived event to receive messages from new client
e.Client.MessageReceived += Client_MessageReceived;
}
static void Server_ClientDisconnected(object sender, ServerClientEventArgs e)
{
Form1.Self.rtb1Text("A client is disconnected! Client Id = " + e.Client.ClientId + "\n");
}
static async void Client_MessageReceived(object sender, MessageEventArgs e)
{
var message = e.Message as ScsTextMessage; // Server only accepts text messages
if (message == null)
{
return;
}
//Get a reference to the client
var client = (IScsServerClient)sender;
Form1.Self.rtb1Text("Client (ID:" + client.ClientId + ") sent a request: " + message.Text + "\n");
switch (message.Text)
{
case "api":
HttpPost httpPost = new HttpPost();
var apiResponse = await httpPost.SendPost("robot_info");
//Send reply message to the client
client.SendMessage(
new ScsTextMessage(
apiResponse,
message.MessageId //Set first message's id as replied message id
));
break;
default:
break;
}
}
}
}
My guess is that I'm doing something wrong when creating a new instance of the Server class and how I'm initializing/starting the server. Might be something else though, I've tried debugging but it didn't make me any smarter.
Any ideas?
I'm creating a game in which I use TCP/IP connection. The problem is that I'm using .Invoke to help me receive and send message.
The program goes like this: I'm my first window, i'm starting and connecting to the server like this :
{
TcpListener listener = new TcpListener(IPAddress.Any, this.port);
listener.Start();
try {
this.client = listener.AcceptTcpClient();
gameWindow = new GameWindow(this.client, true);
gameWindow.StartGame();
}
}
then i'm connecting to it like this:
{
IPEndPoint ipEnd = new IPEndPoint(this.serverIP, this.port);
{
try {
client.Connect(ipEnd);
if (client.Connected) {
gameWindow = new GameWindow(this.client, false);
gameWindow.StartGame();
}
}
}
The constructor for gameWindow (which is a form) looks like this:
public GameWindow(TcpClient thisClient, bool isServer)
{
InitializeComponent();
this.client = thisClient;
this.reader = new StreamReader(thisClient.GetStream());
this.writer = new StreamWriter(thisClient.GetStream());
this.writer.AutoFlush = true;
}
I must wait for the server to send a message to the client, and then start the client ( I have a function .startGame() that uses .ShowDialog() and creates some pictureBoxs)
But nowhere I can get my handle created. I've tried to put this.createHandle() (read about it here) into GameWindow_Load but still not works. If I try to send a message with:
workerSendData.RunWorkerAsync(); I get:
Additional information: Invoke or BeginInvoke cannot be called on a control until the window handle has been created.
What can I do to get my handler created? Using Thread.Sleep will sleep my whole UI, which does not work (a "solution" found on the internet)
My code for sending message :
private void workerSendData_DoWork(object sender, DoWorkEventArgs e)
{
if (client.Connected) {
this.writer.WriteLine(this.toSend); // aici trimitem datele.
// de modificat : aici vom adauga in lista noastra miscarile.
this.Invoke(new MethodInvoker(delegate () { MessageBox.Show("Me:" + this.toSend + "\n"); }));
}
else {
MessageBox.Show("Send failed");
}
workerSendData.CancelAsync();
}
My code for receiving data:
private void workerReceiveData_DoWork(object sender, DoWorkEventArgs e)
{
while (client.Connected) {
try {
this.received = this.reader.ReadLine();
this.myTurn = true;
this.Invoke(new MethodInvoker(delegate () {
MessageBox.Show("This has been received: " + this.received);
/*this.tbReceive.AppendText("You:" + this.received + "\n");*/
}));
this.received = "";
}
catch (Exception x) {
MessageBox.Show(x.Message.ToString());
}
}
}
It seems that you cannot invoke an action before the Window is fully initialized and loaded. Assuming you are working in Windows Forms, there is a solution provided by #Greg D on this question, but it doesn't be to be the safest way to go.
I would suggest that you try to find a way to start the worker only after the window is loaded (for example using the Loaded event), so that the handle is definitely ready and this situation does not occur.
[I work in c#]
In order to decide weather a device should become a server with local client or client alone (for main-server-less networking) I need to find out if there are any other available servers for that device before turning into a server with local client if not for another client device to join by either receiving NetworkDiscovery broadcasts from a server or not - currently I can't get a client to receive broadcast from a server.
I have created two empty gameobjects each with scripts, one script makes it a server and should be broadcasting from its NetworkDiscovery via NetworkDiscovery.StartAsServer() but currently one my client whose NetworkDiscovery has been set to NetworkDiscovery.StartAsClient() is not getting theOnRecievedBroadcast() function called hence not receiving broadcasts from the server.
The two scripts shown below are the client and server:
Client -
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class SearchForServers : MonoBehaviour {
bool serverIsFound;
NetworkDiscovery NetworkDiscovery;
// Use this for initialization
void Start () {
serverIsFound = false;
NetworkClient Client = new NetworkClient();
NetworkDiscovery = gameObject.AddComponent<NetworkDiscovery>();
NetworkDiscovery.Initialize();
NetworkDiscovery.StartAsClient();
}
void OnRecievedBroadcast(string fromAdress, string data)
{
serverIsFound = true;
}
// Update is called once per frame
void Update () {
Debug.Log("Server Found = " + serverIsFound);
}
}
Server -
using UnityEngine;
using System.Collections;
using UnityEngine.Networking;
public class CreateServer : MonoBehaviour
{
bool create;
int minPort = 10000;
int maxPort = 10010;
int defaultPort = 10000;
NetworkDiscovery NetworkDiscovery;
void Start()
{
create = true;
if (create == true)
{
int serverPort = createServer();
if (serverPort != -1)
{
Debug.Log("Server created on port : " + serverPort);
}
else
{
Debug.Log("Failed to create Server");
}
}
NetworkDiscovery = gameObject.AddComponent<NetworkDiscovery>();
NetworkDiscovery.Initialize();
NetworkDiscovery.StartAsServer();
}
//Creates a server then returns the port the server is created with. Returns -1 if server is not created
int createServer()
{
int serverPort = -1;
//Connect to default port
bool serverCreated = NetworkServer.Listen(defaultPort);
if (serverCreated)
{
serverPort = defaultPort;
Debug.Log("Server Created with default port");
}
else
{
Debug.Log("Failed to create with the default port");
//Try to create server with other port from min to max except the default port which we trid already
for (int tempPort = minPort; tempPort <= maxPort; tempPort++)
{
//Skip the default port since we have already tried it
if (tempPort != defaultPort)
{
//Exit loop if successfully create a server
if (NetworkServer.Listen(tempPort))
{
serverPort = tempPort;
break;
}
//If this is the max port and server is not still created, show, failed to create server error
if (tempPort == maxPort)
{
Debug.LogError("Failed to create server");
}
}
}
}
return serverPort;
}
}
These are the console logs with the debug logging
Thanks for reading I hope that you can realise where I have gone wrong or indeed how to complete said task otherwise. #Programmer
First of all you named each server and client script the-same name. You don't need OnRecievedBroadcast in the server code. You only need it in the client code. OnRecievedBroadcast is not being called on the client side because you did not override NetworkDiscovery. You must override it.
Here is a simple Discovering Code:
Client:
public class NetClient : NetworkDiscovery
{
void Start()
{
startClient();
}
public void startClient()
{
Initialize();
StartAsClient();
}
public override void OnReceivedBroadcast(string fromAddress, string data)
{
Debug.Log("Server Found");
}
}
Server:
public class NetServer : NetworkDiscovery
{
// Use this for initialization
void Start()
{
Application.runInBackground = true;
startServer();
}
//Call to create a server
public void startServer()
{
int serverPort = createServer();
if (serverPort != -1)
{
Debug.Log("Server created on port : " + serverPort);
broadcastData = serverPort.ToString();
Initialize();
StartAsServer();
}
else
{
Debug.Log("Failed to create Server");
}
}
int minPort = 10000;
int maxPort = 10010;
int defaultPort = 10000;
//Creates a server then returns the port the server is created with. Returns -1 if server is not created
private int createServer()
{
int serverPort = -1;
//Connect to default port
bool serverCreated = NetworkServer.Listen(defaultPort);
if (serverCreated)
{
serverPort = defaultPort;
Debug.Log("Server Created with deafault port");
}
else
{
Debug.Log("Failed to create with the default port");
//Try to create server with other port from min to max except the default port which we trid already
for (int tempPort = minPort; tempPort <= maxPort; tempPort++)
{
//Skip the default port since we have already tried it
if (tempPort != defaultPort)
{
//Exit loop if successfully create a server
if (NetworkServer.Listen(tempPort))
{
serverPort = tempPort;
break;
}
//If this is the max port and server is not still created, show, failed to create server error
if (tempPort == maxPort)
{
Debug.LogError("Failed to create server");
}
}
}
}
return serverPort;
}
}
The createServer() function is a function from your last question. I don't think you can have both server and client code running at the-same time in the Editor.
For testing, you must build the code in your pc with the server code/NetServer enabled. Run the built program then from your Editor you can run the client/NetClient code. This should discover game on the server.
I am going to make a basic communication between Unity and Arduino. The problem that i have is that when i start sending data from unity to arduino, it's working properly. But when i start reading serial from Arduino. I got Access denied error !!!
After i read more about the issue, i can't find the real reason for that. I need to understand why something like that happens.
using UnityEngine;
using System.Collections;
using System;
using System.IO.Ports;
using System.Text;
using System.Threading;
public class Program : MonoBehaviour {
public SerialPort mySerialPort = new SerialPort("COM7", 9600);
public volatile float speed=0;
volatile bool isPassed = true;
GameObject cube ;
public GUIStyle style ;
// int readInterval = 4;
// int alreadyCounter = 0;
// string rxString = "";
void Start () {
isPassed = true;
speed = 0;
//mySerialPort.ReadTimeout = 25;
mySerialPort.Parity = Parity.None;
mySerialPort.StopBits = StopBits.One;
mySerialPort.DataBits = 8;
mySerialPort.DtrEnable = true;
cube = GameObject.FindGameObjectWithTag ("cube");
/*foreach(string str in SerialPort.GetPortNames())
{
Debug.Log(string.Format("Existing COM port: {0}", str));
};
*/
try{
mySerialPort.Open();
}catch(Exception ex)
{
print("Start Error Opening : " + ex.ToString());
}
/*
new Thread (delegate() {
updateSpeed();
}).Start();
*/
}
void OnGUI(){
GUI.Box (new Rect(100,100,100,100),"Speed : " + speed , style);
}
// Update is called once per frame
void Update () {
cube.transform.Rotate(Vector3.up * speed *Time.deltaTime);
if (mySerialPort.IsOpen) {
speed = float.Parse (mySerialPort.ReadLine ());
} else {
if(mySerialPort!= null)
{
mySerialPort.Close();
mySerialPort.Open();
}
}
/*if (isPassed == true) {
new Thread(delegate() {
if(mySerialPort.IsOpen) {
updateSpeed();
isPassed = false;
} else {
try {
mySerialPort.Close();
mySerialPort.Open();
} catch (Exception ex) {
print("Update Error Opening : " + ex.ToString());
}
}
}).Start();
}*/
}
public void updateSpeed()
{
while (true) {
speed = float.Parse(mySerialPort.ReadLine ());
print ("Speed = " + speed);
Thread.Sleep (60);
mySerialPort.BaseStream.Flush ();
}
}
void OnDestroy ()
{
mySerialPort.Close();
}
}
When you call Close the SerialPort is disposed as you can read on the MSDN page. It also suggest to not try to reopen it immediately after closing it as it might not be closed yet.
Also since the SerialPort will be disposed you would have to create a new one. I would suggest to not closing and opening the port in Update when it's not open yet. Open it once in Start and just close it in OnDestroy.
edit
It seems you don't have to create a new SerialPort when you called Close on it. So it can be reused after "waiting some time".
Update:
Now, you can use Microsoft .net open source framework instead of the unity default, the serial communication works like a charm there.
I have a c# server socket on a PC, and a client AS3 socket on another PC on the same local network as the first PC.
the problem is when the c# and AS3 are on the same PC the connection is OK, but when i move the c# on another PC on the local network the AS3 can't reach it !!
Socket Programming Using AS 3.0
Socket Programming AS 3.0 API
Please refer given below Code :
package {
import flash.display.Sprite;
public class SocketExample extends Sprite {
private var socket:CustomSocket;
public function SocketExample() {
socket = new CustomSocket("localhost", 80);
}
}
}
import flash.errors.*;
import flash.events.*;
import flash.net.Socket;
class CustomSocket extends Socket {
private var response:String;
public function CustomSocket(host:String = null, port:uint = 0) {
super();
configureListeners();
if (host && port) {
super.connect(host, port);
}
}
private function configureListeners():void {
addEventListener(Event.CLOSE, closeHandler);
addEventListener(Event.CONNECT, connectHandler);
addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
}
private function writeln(str:String):void {
str += "\n";
try {
writeUTFBytes(str);
}
catch(e:IOError) {
trace(e);
}
}
private function sendRequest():void {
trace("sendRequest");
response = "";
writeln("GET /");
flush();
}
private function readResponse():void {
var str:String = readUTFBytes(bytesAvailable);
response += str;
}
private function closeHandler(event:Event):void {
trace("closeHandler: " + event);
trace(response.toString());
}
private function connectHandler(event:Event):void {
trace("connectHandler: " + event);
sendRequest();
}
private function ioErrorHandler(event:IOErrorEvent):void {
trace("ioErrorHandler: " + event);
}
private function securityErrorHandler(event:SecurityErrorEvent):void {
trace("securityErrorHandler: " + event);
}
private function socketDataHandler(event:ProgressEvent):void {
trace("socketDataHandler: " + event);
readResponse();
}
}