I am trying to create a client server app using Unity3D and python. I am trying to send big amount of data from server to client in real time. In order to do that i divided the data to be received in smaller bulks so the serialization/deserialization to be faster so the update of unity objects based on data to be faster as well.
I approached the problem like this:
I open 5 sockets and each try to handle the request based on an identifier
On client I use parallel.foreach for sending the five identifiers and receiving then in parallel.
The issue is that client.Receive blocks when there is no data to receive. I tried to set a timeout but it is not really helpful.
Also the length of data is variable for the packages received.
Python server implementation is similar to this but it is not that relevant i assume tho: Is it possible to run multiple asyncio in the same time in python?
Socket class:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Net.Sockets;
using System;
using System.IO;
public class SocketConnector
{
public string ip = "127.0.0.1";
public int port = 60000;
private Socket client;
[SerializeField]
private int dataOut;
private byte[] dataIn; //debugging
public SocketConnector() { }
public void establishConnection(int port)
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(ip, port);
}
public byte[] ServerRequest(int dataOut)
{
//print("request");
this.dataOut = dataOut; //debugging
this.dataIn = SendAndReceive(dataOut); //debugging
return this.dataIn;
}
private byte[] SendAndReceive(int dataOut)
{
byte[] z = new byte[1024 * 1024 * 1500];
try
{
byte[] intBytes = BitConverter.GetBytes(dataOut);
client.Send(intBytes);
client.ReceiveTimeout = 2000;
//allocate and receive bytes
byte[] bytes = new byte[1024 * 1024 * 1500];
Array.Clear(bytes, 0, bytes.Length);
int lenght = 1, byteIndex = 0;
lenght = client.Receive(bytes); // is blocking here cos no data is received sometime
Buffer.BlockCopy(bytes, 0, z, byteIndex, lenght);
byteIndex += lenght;
Array.Resize(ref z, byteIndex);
Debug.Log("request received");
}
catch (Exception e)
{
Debug.Log("smth happened");
}
client.Close();
return z;
}
}
Main class:
...
void Start()
{
ThreadCompoennt threadComponent = new ThreadComponent(socketConnector, this, featureMapCreator);
threadComponent.init();
}
...
Thread component:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
using System.Linq;
using System.Threading.Tasks;
using MessagePack;
using System;
public class ThreadComponent
{
Thread thread;
SocketConnector socketConnector;
Main main;
Dictionary<string, Dictionary<string, ushort[][]>> feature;
StructHelper structHelper;
byte[] z;
public ThreadComponent(SocketConnector socketConnector, Main main, FeatureMapCreator featureMapCreator)
{
this.featureMapCreator = featureMapCreator;
this.socketConnector = socketConnector;
this.main = main;
}
public void init()
{
thread = new System.Threading.Thread(doLogic);
thread.IsBackground = true;
thread.Start();
}
void doLogic()
{
List<int> integerList = Enumerable.Range(1, 5).ToList();
while (true)
{
Thread.Sleep(2000);
Parallel.ForEach(integerList, i =>
{
socketConnector.establishConnection(60000 + i);
doLogicGetData(i, socketConnector);
});
}
}
void doLogicGetData(int batchIdentifier, SocketConnector socketConnector)
{
z = socketConnector.ServerRequest(batchIdentifier);
if (z.Length != 0)
{
this.feature = MessagePackSerializer.Deserialize<Dictionary<string, Dictionary<string,ushort[][]>>>(z);
..... do update based on batch identifier
}
}
Related
I'm trying to get data from BT device. I know that i can use InTheHand library for it in C#, but i can't connect to device and get data. I use sniffer and know that device work and send data. Maybe someone know how to work with BT in C#? I need only data from it, not send or etc.
I've got this code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using InTheHand.Net.Sockets;
using InTheHand.Net;
using InTheHand.Net.Bluetooth;
using InTheHand.Windows.Forms;
using System.Net.Sockets;
using System.Diagnostics;
using System.Threading;
namespace BLE{
static class Program
{
private static string sCode = "0000";
// My BT notebook
private static BluetoothEndPoint EP = new BluetoothEndPoint(BluetoothAddress.Parse("50:76:AF:99:D3:87"), BluetoothService.BluetoothBase);
private static BluetoothClient BC = new BluetoothClient(EP);
// The BT device that would connect
private static BluetoothDeviceInfo BTDevice = new BluetoothDeviceInfo(BluetoothAddress.Parse("34:29:F0:F4:49:C8"));
private static NetworkStream stream = null;
static void Main(string[] args)
{
if (BluetoothSecurity.PairRequest(BTDevice.DeviceAddress, sCode))
{
Console.WriteLine("PairRequest: OK");
if (BTDevice.Authenticated)
{
Console.WriteLine("Authenticated: OK");
BC.SetPin(sCode);
BC.BeginConnect(BTDevice.DeviceAddress, BluetoothService.SerialPort, new AsyncCallback(Connect), BTDevice);
}
else
{
Console.WriteLine("Authenticated: No");
}
}
else
{
Console.WriteLine("PairRequest: No");
}
Console.ReadLine();
}
private static void Connect(IAsyncResult result)
{
if (result.IsCompleted)
{
// client is connected now :)
Console.WriteLine(BC.Connected);
stream = BC.GetStream();
if (stream.CanRead)
{
byte[] myReadBuffer = new byte[1024];
StringBuilder myCompleteMessage = new StringBuilder();
int numberOfBytesRead = 0;
// Incoming message may be larger than the buffer size.
do
{
numberOfBytesRead = stream.Read(myReadBuffer, 0, myReadBuffer.Length);
for (int i = 0; i < numberOfBytesRead; i++)
myCompleteMessage.AppendFormat("0x{0:X2} ", myReadBuffer[i]);
}
while (stream.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.");
}
Console.ReadLine();
}
}
}
}
In console i see "PairRequest: No"...
Can you help me to get the correct result?
I ran into a strange problem. When I'm trying to send the file via a TCP socket, the first 4 bytes of sended information cuts off.
That is sending and receives pieces of code.
Client side
for (var i = 0; i < fileContentByte.Length; i += buffer.Length)
{
var size = (i + buffer.Length > fileContentByte.Length) ? fileContentByte.Length - i : buffer.Length;
clientSocket.Write(fileContentByte, i, size);
}
Server side
using(var file = File.Create("C:\\test\\"+fileName.Substring(0, fileName.IndexOf('\0'))))
while(bytesReceived < numberOfBytes && (count = clientStream.Read(buffer, 0, buffer.Length)) > 0)
{
file.Write(buffer, 0, count);
bytesReceived += count;
}
Here is link on full code - http://pastebin.com/VwTgTxgb
You're doing something very strange here.
First of all, retrieval of file name can be greatly simplified down to Path.GetFileName() call.
Second, are you sure ASCII will suffice?
Third, reading the entire file into memory is OK-ish for a proof-of-concept project, but be ready to switch to streaming operations.
Fourth, your protocol is somewhat wonky. When sending variable-size payload, it is required to first tell the receiving party exactly how much bytes are you going to send. This is exactly what you don't do when sending file name.
Here's a snippet to get you started:
using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace FolderSync
{
class Program
{
static void Main()
{
var server = new Server();
server.Start();
new Client().TransmitFile(
new IPEndPoint(IPAddress.Loopback, 35434),
#"f:\downloads\ubuntu-14.04.3-desktop-amd64.iso");
Console.ReadLine();
server.Stop();
}
}
class Server
{
private readonly TcpListener tcpListener;
public Server()
{
tcpListener = new TcpListener(IPAddress.Loopback, 35434);
}
public void Start()
{
tcpListener.Start();
tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
}
public void Stop()
{
tcpListener.Stop();
}
private void AcceptTcpClientCallback(IAsyncResult asyncResult)
{
//
// Big fat warning: http://stackoverflow.com/a/1230266/60188
tcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, null);
using(var tcpClient = tcpListener.EndAcceptTcpClient(asyncResult))
using(var networkStream = tcpClient.GetStream())
using(var binaryReader = new BinaryReader(networkStream, Encoding.UTF8))
{
var fileName = binaryReader.ReadString();
var length = binaryReader.ReadInt64();
var mib = length / 1024.0 / 1024.0;
Console.WriteLine("Receiving '{0}' ({1:N1} MiB)", fileName, mib);
var stopwatch = Stopwatch.StartNew();
var fullFilePath = Path.Combine(Path.GetTempPath(), fileName);
using(var fileStream = File.Create(fullFilePath))
networkStream.CopyTo(fileStream);
var elapsed = stopwatch.Elapsed;
Console.WriteLine("Received in {0} ({1:N1} MiB/sec)",
elapsed, mib / elapsed.TotalSeconds);
}
}
}
class Client
{
public void TransmitFile(IPEndPoint endPoint, string fileFullPath)
{
if(!File.Exists(fileFullPath)) return;
using(var tcpClient = new TcpClient())
{
tcpClient.Connect(endPoint);
using(var networkStream = tcpClient.GetStream())
using(var binaryWriter = new BinaryWriter(networkStream, Encoding.UTF8))
{
var fileName = Path.GetFileName(fileFullPath);
Debug.Assert(fileName != null, "fileName != null");
//
// BinaryWriter.Write(string) does length-prefixing automatically
binaryWriter.Write(fileName);
using(var fileStream = File.OpenRead(fileFullPath))
{
binaryWriter.Write(fileStream.Length);
fileStream.CopyTo(networkStream);
}
}
}
}
}
}
I'm newbie in audio programming and in sockets programming. I'm trying to send guitar signal over a network using NAudio AsioOut class and Sockets.
Here's source code of Receiver and Sender.
It seems like the receiver really gets the bytes array from sender, but all what I hear is white noise.
Receiver source code
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Threading;
using NAudio.Utils;
using NAudio.Wave;
using NAudio.Wave.SampleProviders;
namespace Reciever
{
internal class Program
{
private static Socket Listener;
private static Socket Accepter;
private static AsioOut Output;
private static BufferedWaveProvider OutputBuffer;
[STAThread]
private static void Main(string[] args)
{
IPHostEntry ipHostEntry = Dns.GetHostEntry("192.168.1.4");
IPAddress ipAddr = ipHostEntry.AddressList[2];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 7777);
Listener = new Socket(ipAddr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Console.WriteLine("Слушатель готов по адресу:{0} ", ipEndPoint);
Listener.Bind(ipEndPoint);
Listener.Listen(10);
Accepter = Listener.Accept();
Console.WriteLine("Клиент с адресом {0} подключен", Accepter.RemoteEndPoint);
Output = new AsioOut();
Output.ShowControlPanel();
Console.Read();
OutputBuffer = new BufferedWaveProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100, 2));
Output.Init(OutputBuffer);
Thread playing = new Thread(new ThreadStart(Output.Play));
Thread listening = new Thread(new ThreadStart(Listening));
playing.Start();
listening.Start();
}
public static void Listening()
{
while (true)
{
byte[] buffer = new byte[65538];
int ReceivedData = Accepter.Receive(buffer);
OutputBuffer.AddSamples(buffer, 0, ReceivedData);
}
}
}
}
Sender source code
using System;
using System.Net;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using NAudio.Wave;
namespace Sender
{
class Program
{
private static Socket sck;
[STAThread]
static void Main(string[] args)
{
AsioOut asioout = new AsioOut();
IPHostEntry ipHostEntry = Dns.GetHostEntry("192.168.1.2");
IPAddress ipAddr = ipHostEntry.AddressList[1];
IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 7777);
sck = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
BufferedWaveProvider buffer = new BufferedWaveProvider(WaveFormat.CreateIeeeFloatWaveFormat(44100,2));
sck.Bind(ipEndPoint);
try
{
sck.Connect("192.168.1.4", 7777);
}
catch (Exception ex)
{
Console.WriteLine("Соединие не установлено");
Console.Read();
return;
}
Console.WriteLine("Соединение установлено");
asioout.InitRecordAndPlayback(buffer, 2, 44100);
asioout.AudioAvailable += new EventHandler<AsioAudioAvailableEventArgs>(asioout_AudioAvailable);
asioout.Play();
Console.Read();
}
private static void asioout_AudioAvailable(object sender, AsioAudioAvailableEventArgs e)
{
var samples = e.GetAsInterleavedSamples();
byte[] OutputBuffer = new byte[e.SamplesPerBuffer*4];
byte[] SendingBuffer = new byte[e.SamplesPerBuffer*4];
Console.WriteLine(e.SamplesPerBuffer*4);
for (int i = 0; i < e.InputBuffers.Length; i++)
{
Marshal.Copy(e.InputBuffers[i], OutputBuffer, 0, e.SamplesPerBuffer*4);
Buffer.BlockCopy(samples, 0, SendingBuffer, 0, e.SamplesPerBuffer*4);
Marshal.Copy(OutputBuffer, 0, e.OutputBuffers[i], e.SamplesPerBuffer * 4);
}
sck.Send(SendingBuffer);
e.WrittenToOutputBuffers = true;
}
}
}
UPD.1 (07.10.2015): Sender code and Receiver code are updated. Now I can hear the guitar signal from receiver, but it sounds very distorted. What I do wrong?
P.S. I'm using M-Audio Fast Track USB sound card on my desktop PC. The signal goes from that one to my laptop with ASIO4ALL driver over the network.
Your receiver assumes that the incoming audio is 16 bit, but with ASIO, it could easily be 24 or 32 bit. In fact, your sending code seems to assume 32 bit. So start by trying to use an IEEE float WaveFormat on the receiving end
Sorry if this is hard to understand, trying out C# for the first time.
I am trying to make a simple public 'chat' between clients that are connected to the server. I've tried passing integers to the server and printing them out and everything was fine, however,when I switched to strings, it seems that it can only pass 1 character (because of ns.Write(converted, 0, 1);). If I increase the ns.Write to ns.Write(converted,0,10) everything crashes (both the client and the server) when I enter a message that is less than 10 characters.
Server code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net.Sockets;
namespace MultiServeris
{
class Multiserveris
{
static void Main(string[] args)
{
TcpListener ServerSocket = new TcpListener(1000);
ServerSocket.Start();
Console.WriteLine("Server started");
while (true)
{
TcpClient clientSocket = ServerSocket.AcceptTcpClient();
handleClient client = new handleClient();
client.startClient(clientSocket);
}
}
}
public class handleClient
{
TcpClient clientSocket;
public void startClient(TcpClient inClientSocket)
{
this.clientSocket = inClientSocket;
Thread ctThread = new Thread(Chat);
ctThread.Start();
}
private void Chat()
{
byte[] buffer = new byte[10];
while (true)
{
NetworkStream ns = clientSocket.GetStream();
ns.Read(buffer,0,1);
string line = Encoding.UTF8.GetString(buffer);
Console.WriteLine(line);
}
}
}
}
Client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
namespace Klientas
{
class Klientas
{
static void Main(string[] args)
{
while (true)
{
TcpClient clientSocket = new TcpClient("localhost", 1000);
NetworkStream ns = clientSocket.GetStream();
byte[] buffer = new byte[10];
string str = Console.ReadLine();
byte[] converted = System.Text.Encoding.UTF8.GetBytes(str);
ns.Write(converted, 0, 1);
}
}
}
}
You're best using the BinaryReader/BinaryWriter classes to correctly format and read out data. This removes the need to process it yourself. For example in the client do:
BinaryWriter writer = new BinaryWriter(clientSocket.GetStream());
writer.Write(str);
And in the server:
BinaryReader reader = new BinaryReader(clientSocket.GetStream());
Console.WriteLine(reader.ReadString());
When using BinaryReader or BinaryWriter on the same stream, and you have .NET framework version 4.5 or above, be sure to leave the underlying stream open by using the overload:
using (var w = new BinaryWriter(stream, Encoding.UTF8, true)) {}
I got a system of console applications written in C# running on different machines. I use MSMQ.
My questions is, how do I make my console applications communicate to each other?
I'm asking because I want to create a new console application that can be queried by other applications to know the number of messages in MSMQ.
Edit 1:
Thanks for the replies and comments!
About the requirements, I'm estimating maybe about 10-50/sec of queries
You need to use a pipe to achieve this: see Named pipe and anonymous pipe
A pipe works like this:
The host application (the one launching the console application) has to create a pipe to catch the concole application's std output and an other one to write to the console application's std input.
There is plenty of code example in the link I gave you
Also here is a code example (using existing pipes StandardInput and StandardOutput): it starts a cmd.exe console but it is a layer over: not the actual console...see for yourself:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
private static StreamReader reader;
static void Main(string[] args)
{
Process cmd = new Process();
cmd.StartInfo.FileName = "cmd.exe";
cmd.StartInfo.RedirectStandardInput = true;
cmd.StartInfo.RedirectStandardOutput = true;
cmd.StartInfo.UseShellExecute = false;
cmd.Start();
reader = cmd.StandardOutput;
StreamWriter writer = cmd.StandardInput;
Thread t = new Thread(new ThreadStart(writingThread));
t.Start();
//Just write everything we type to the cmd.exe process
while (true) writer.Write((char)Console.Read());
}
public static void writingThread()
{
//Just write everything cmd.exe writes back to our console
while (true) Console.Write((char)reader.Read());
}
}
}
You can achieve the same result by replacing the StreamReader and the StreamWriter by a port connection (socket) buffer for remote communication between two process
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.aspx
It is recommended to secure the communication to minimize intrusion possibility
Here is an example of communication through a sockets...now this is running in one program but everything is on separate threads and it would work if the communication was to be on two separate machines: the server is the one controlling the process cmd.exe and the client is a viewer/writer
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Net.Sockets;
using System.Net;
namespace ConsoleApplication1
{
class Program
{
private static StreamReader reader;
private static StreamWriter writer;
static void Main(string[] args)
{
//Server initialisation
Process cmdServer = new Process();
cmdServer.StartInfo.FileName = "cmd.exe";
cmdServer.StartInfo.RedirectStandardInput = true;
cmdServer.StartInfo.RedirectStandardOutput = true;
cmdServer.StartInfo.UseShellExecute = false;
cmdServer.Start();
reader = cmdServer.StandardOutput;
writer = cmdServer.StandardInput;
Thread t1 = new Thread(new ThreadStart(clientListener));
t1.Start();
Thread t2 = new Thread(new ThreadStart(clientWriter));
t2.Start();
Thread t3 = new Thread(new ThreadStart(serverListener));
t3.Start();
Thread t4 = new Thread(new ThreadStart(serverWriter));
t4.Start();
}
public static void clientWriter()
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Int32 size = 0;
Byte[] buff = new Byte[1024];
sock.Connect(IPAddress.Parse("127.0.0.1"), 4357);
Console.WriteLine("clientWriter connected");
while (true)
{
String line = Console.ReadLine();
line += "\n";
Char[] chars = line.ToArray();
size = chars.Length;
if (size > 0)
{
buff = Encoding.Default.GetBytes(chars);
//Console.WriteLine("Sending \"" + new String(chars, 0, size) + "\"");
sock.Send(buff, size, 0);
}
}
}
/// <summary>
/// Local client that listens to what the server sends on port 4356
/// </summary>
public static void clientListener()
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Bind(new IPEndPoint(IPAddress.Any, 4356));
sock.Listen(0);
Int32 size = 0;
Byte[] buff = new Byte[1024];
Char[] cbuff = new Char[1024];
while (true)
{
Console.WriteLine("clientListener Waiting for connection");
sock = sock.Accept();
Console.WriteLine("clientListener Connection accepted " + ((sock.Connected)?"Connected" : "Not Connected"));
while ((size = sock.Receive(buff)) > 0)
{
for (int i = 0; i < size; i++) cbuff[i] = (Char)buff[i];
Console.Write(cbuff, 0, size);
}
sock.Close();
}
}
/// <summary>
/// Remote server that listens to what the client sends on port 4357
/// </summary>
public static void serverListener()
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sock.Bind(new IPEndPoint(IPAddress.Any, 4357));
sock.Listen(0);
Int32 size = 0;
Byte[] buff = new Byte[1024];
Char[] cbuff = new Char[1024];
while (true)
{
Console.WriteLine("serverListener Waiting for connection");
sock = sock.Accept();
Console.WriteLine("serverListener Connection accepted " + ((sock.Connected) ? "Connected" : "Not Connected"));
while ((size = sock.Receive(buff)) > 0)
{
for (int i = 0; i < size; i++) cbuff[i] = (Char)buff[i];
//Console.WriteLine("Received \"" + new String(cbuff,0,size) + "\"");
writer.Write(cbuff, 0, size);
}
}
}
/// <summary>
/// Remote server that writes the output of the colsole application through the socket
/// </summary>
public static void serverWriter()
{
Socket sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Int32 size = 0;
Byte[] buff = new Byte[1024];
Char[] cbuff = new Char[1024];
sock.Connect(IPAddress.Parse("127.0.0.1"), 4356);
Console.WriteLine("serverWriter connected");
while (true)
{
size = reader.Read(cbuff, 0, 1024);
if (size > 0)
{
for (int i = 0; i < size; i++) buff[i] = (Byte)cbuff[i];
sock.Send(buff, 0, size, 0);
}
}
}
}
}
testable and extendable - can be easily changed to work between computers.
you have a few methods. "named pipes" can be achieved easily using WCF. its nice because its very testable.
best performance you can use memory mapped files http://weblogs.asp.net/gunnarpeipman/archive/2009/06/21/net-framework-4-0-using-memory-mapped-files.aspx
they have AMAZING performance. BUT less harder to test.
easiest - if you have very low traffic you can use the registry. theres a Regisrty class in C# its threadsafe and fast.
WCF. WCF, WCF, WCF, WCF.
Don't bother reinventing the wheel, just use WCF for communications, and let it worry about the details (whether using a pipe or some other mechanism).