Unity 3D Communication between 2 editors - unity3d

I am trying to stream some data between 2 editors using a simple tcp client/server setup:
Server:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class TCPTestServer : MonoBehaviour {
#region private members
/// <summary>
/// TCPListener to listen for incomming TCP connection
/// requests.
/// </summary>
private TcpListener tcpListener;
/// <summary>
/// Background thread for TcpServer workload.
/// </summary>
private Thread tcpListenerThread;
/// <summary>
/// Create handle to connected tcp client.
/// </summary>
private TcpClient connectedTcpClient;
#endregion
// Use this for initialization
void Start () {
// Start TcpServer background thread
tcpListenerThread = new Thread (new ThreadStart(ListenForIncommingRequests));
tcpListenerThread.IsBackground = true;
tcpListenerThread.Start();
}
// Update is called once per frame
void Update () {
SendMessage();
}
/// <summary>
/// Runs in background TcpServerThread; Handles incomming TcpClient requests
/// </summary>
private void ListenForIncommingRequests () {
try {
// Create listener on localhost port 8052.
tcpListener = new TcpListener(IPAddress.Parse("myip"), 65535);
tcpListener.Start();
Debug.Log("Server is listening");
Byte[] bytes = new Byte[1024];
while (true) {
using (connectedTcpClient = tcpListener.AcceptTcpClient()) {
// Get a stream object for reading
using (NetworkStream stream = connectedTcpClient.GetStream()) {
int length;
// Read incomming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
var incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string clientMessage = Encoding.ASCII.GetString(incommingData);
Debug.Log("client message received as: " + clientMessage);
}
}
}
}
}
catch (SocketException socketException) {
Debug.Log("SocketException " + socketException.ToString());
}
}
/// <summary>
/// Send message to client using socket connection.
/// </summary>
private void SendMessage() {
if (connectedTcpClient == null) {
return;
}
try {
// Get a stream object for writing.
NetworkStream stream = connectedTcpClient.GetStream();
if (stream.CanWrite) {
string serverMessage = this.gameObject.transform.position.ToString();
// Convert string message to byte array.
byte[] serverMessageAsByteArray = Encoding.ASCII.GetBytes(serverMessage);
// Write byte array to socketConnection stream.
stream.Write(serverMessageAsByteArray, 0, serverMessageAsByteArray.Length);
Debug.Log("Server sent his message - should be received by client");
}
}
catch (SocketException socketException) {
Debug.Log("Socket exception: " + socketException);
}
}
void OnApplicationQuit()
{
tcpListenerThread.Abort();
connectedTcpClient.Close ();
}
}
Client:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using UnityEngine;
public class TCPTestClient : MonoBehaviour {
#region private members
private TcpClient socketConnection;
private Thread clientReceiveThread;
#endregion
// Use this for initialization
void Start () {
ConnectToTcpServer();
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.Space)) {
SendMessage();
}
}
/// <summary>
/// Setup socket connection.
/// </summary>
private void ConnectToTcpServer () {
try {
clientReceiveThread = new Thread (new ThreadStart(ListenForData));
clientReceiveThread.IsBackground = true;
clientReceiveThread.Start();
}
catch (Exception e) {
Debug.Log("On client connect exception " + e);
}
}
/// <summary>
/// Runs in background clientReceiveThread; Listens for incomming data.
/// </summary>
private void ListenForData() {
try {
socketConnection = new TcpClient("myip", 65535);
Byte[] bytes = new Byte[1024];
while (true) {
// Get a stream object for reading
using (NetworkStream stream = socketConnection.GetStream()) {
int length;
// Read incomming stream into byte arrary.
while ((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
var incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string serverMessage = Encoding.ASCII.GetString(incommingData);
Debug.Log("server message received as: " + serverMessage);
}
}
}
}
catch (SocketException socketException) {
Debug.Log("Socket exception: " + socketException);
}
}
/// <summary>
/// Send message to server using socket connection.
/// </summary>
private void SendMessage() {
if (socketConnection == null) {
return;
}
try {
// Get a stream object for writing.
NetworkStream stream = socketConnection.GetStream();
if (stream.CanWrite) {
string clientMessage = "This is a message from one of your clients.";
// Convert string message to byte array.
byte[] clientMessageAsByteArray = Encoding.ASCII.GetBytes(clientMessage);
// Write byte array to socketConnection stream.
stream.Write(clientMessageAsByteArray, 0, clientMessageAsByteArray.Length);
//Debug.Log("Client sent his message - should be received by server");
}
}
catch (SocketException socketException) {
Debug.Log("Socket exception: " + socketException);
}
}
void OnApplicationQuit()
{
clientReceiveThread.Abort();
socketConnection.Close ();
}
}
This works in local but wont work if i run the server and client seperately in two different computers. Moreover, i triend ping.eu and my port seems closed even if i forwarded from my firewall settings. What am I doing wrong?

Related

WebSocket sending fails unless I use InvokeRepeating

I've implemented a socket connection module according to the instructions here
https://github.com/endel/NativeWebSocket
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using NativeWebSocket;
public class Connection : MonoBehaviour
{
WebSocket websocket;
public bool SpamSend;
public float spamEvery = 3f;
public string uri = "ws://localhost:2567";
[TextArea] public string message;
private string CurrectData;
// Start is called before the first frame update
async void Start()
{
CurrectData = message;
websocket = new WebSocket(uri);
InitilizeWebSocket();
}
async void InitilizeWebSocket()
{
websocket.OnOpen += () =>
{
Debug.Log("Connection open!");
};
websocket.OnError += (e) =>
{
Debug.Log("Error! " + e);
};
websocket.OnClose += (e) =>
{
Debug.Log("Connection closed!");
};
websocket.OnMessage += (bytes) =>
{
Debug.Log("OnMessage!");
//Debug.Log(bytes);
// getting the message as a string
var message = System.Text.Encoding.UTF8.GetString(bytes);
Debug.Log("OnMessage! " + message);
};
if(SpamSend)
// Keep sending messages at every 0.3s
InvokeRepeating("SendWebSocketMessage", 0.0f, spamEvery);
// waiting for messages
await websocket.Connect();
}
void Update()
{
#if !UNITY_WEBGL || UNITY_EDITOR
websocket.DispatchMessageQueue();
#endif
}
async void SendWebSocketMessage()
{
if (websocket.State == WebSocketState.Open)
{
// Sending bytes
// await websocket.Send(new byte[] { 10, 20, 30 });
// Sending plain text
await websocket.SendText(CurrectData);
CancelInvoke("SendWebSocketMessage");
}
}
private async void OnApplicationQuit()
{
await websocket.Close();
}
}
you may now notice the oddity of "invokeRepeating" and CancelInvoke.
this is where I've encountered a problem.
when I tried to just Invoke, I received no response from the server as if it was never sent.
nor when I tried a coroutine - with or without waitForSeconds.
nor when I simply tried SendWebSocketMessage().
What did I miss that only the invokeRepeating made it through?

NodeMCU Unity Connection, using UDP

I am trying to connect NodeMCU with unity for my university project.
My nodemcu receives data (tested with a UDP test tool application). I will leave the code below.
But I have problems with Unity. I tried to find a simple example or something like that.
The code I found recently is simple enough, but it makes Unity freeze. I found it here and edited it a bit.
NodeMCU code in Arduino IDE
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "Epic SSID";
const char* password = "EpicPassword";
WiFiUDP Udp;
unsigned int port = 25666;
char packet[255];
IPAddress ip(192, 168, 43, 20);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.hostname("YVRB-01");
WiFi.config(ip, gateway, subnet);
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("Connection Successful");
Udp.begin(port);
Serial.printf("Listener started at IP %s, at port %d", WiFi.localIP().toString().c_str(), port);
}
void loop()
{
int packetSize = Udp.parsePacket();
if (packetSize)
{
Serial.printf("Received %d bytes from %s, port %d", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(packet, 255);
if (len > 0)
{
packet[len] = 0;
}
Serial.printf("UDP packet contents: %s", packet);
Serial.println();
}
Udp.beginPacket (Udp.remoteIP(), Udp.remotePort());
Udp.write("Epic message");
Udp.endPacket();
delay(300);
}
When it worked, I took off my shirt and ran too kitchen.
My code in Unity
/*
C# Network Programming
by Richard Blum
Publisher: Sybex
ISBN: 0782141765
*/
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine;
public class udpsend : MonoBehaviour
{
Socket server;
IPEndPoint ipep;
void Start()
{
byte[] data = new byte[1024];
ipep = new IPEndPoint(
IPAddress.Parse("192.162.43.209"), 25666);
server = new Socket(AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp);
string welcome = "I am connected";
data = Encoding.ASCII.GetBytes(welcome);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
}
void Update()
{
string input, stringData;
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint Remote = (EndPoint)sender;
byte[] data = new byte[1024];
int recv = server.ReceiveFrom(data, ref Remote);
Console.WriteLine("Message received from {0}:", Remote.ToString());
Console.WriteLine(Encoding.ASCII.GetString(data, 0, recv));
//while (true)
//{
// input = Console.ReadLine();
// if (input == "exit")
// break;
// server.SendTo(Encoding.ASCII.GetBytes(input), Remote);
// data = new byte[1024];
// recv = server.ReceiveFrom(data, ref Remote);
// stringData = Encoding.ASCII.GetString(data, 0, recv);
// Console.WriteLine(stringData);
//}
Console.WriteLine("Stopping client");
server.Close();
}
public void SendData(string message)
{
byte[] data = new byte[1024];
data = Encoding.ASCII.GetBytes(message);
server.SendTo(data, data.Length, SocketFlags.None, ipep);
}
}
I'm just saying that I don't fully understand, but I edited a little bit.
Any fixes or code examples will be appreciated. I just want a method that I can call like SendData("Never gonna give you up!").
I can now transfer information from the Unity app to NodeMCU and from NodeMCU to Unity!
All the code is below.
I used the code and edited the a bit.
To receive data, I used this code right here.
To send information, I used this code and like a "mash up" this code together to create one program that can send and receive.
The reason I have done this is that there were a conflict, because there were one client and multiple codes trying to access it.
For Node MCU I used this code which is pretty much the same as I wrote in question above.
I also made manager code using which I can send message and do other stuff.
It is also important to close all the ports or else Unity will freeze (a very annoying thing).
Nodemcu code in the Arduino IDE:
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
const char* ssid = "YVRB";
const char* password = "YGreater";
WiFiUDP Udp;
unsigned int port = 25666;
char packet[255];
IPAddress ip(192, 168, 43, 20);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);
void setup()
{
Serial.begin(115200);
Serial.println();
WiFi.hostname("YVRB-01");
WiFi.config(ip, gateway, subnet);
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("Connection Successful");
Udp.begin(port);
Serial.printf("Listener started at IP %s, at port %d", WiFi.localIP().toString().c_str(), port);
Serial.println();
}
void loop()
{
int packetSize = Udp.parsePacket();
if (packetSize)
{
Serial.printf("Received %d bytes from %s, port %d", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(packet, 255);
if (len > 0)
{
packet[len] = 0;
}
Serial.printf("UDP packet contents: %s", packet);
Serial.println();
}
Udp.beginPacket (Udp.remoteIP(), Udp.remotePort());
Udp.write("Important data");
Udp.endPacket();
delay(300);
}
File UDPSend.cs code which receives as well:
// Inspired by this thread: https://forum.unity.com/threads/simple-udp-implementation-send-read-via-mono-c.15900/
// Thanks OP la1n
// Thanks MattijsKneppers for letting me know that I also need to lock my queue while enqueuing
// Adapted during projects according to my needs
using UnityEngine;
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
public class UDPSend
{
public string IP { get; private set; }
public int sourcePort { get; private set; } // Sometimes we need to define the source port, since some devices only accept messages coming from a predefined sourceport.
public int remotePort { get; private set; }
IPEndPoint remoteEndPoint;
Thread receiveThread;
// udpclient object
UdpClient client;
// public
// public string IP = "127.0.0.1"; default local
public int port = 25666; // define > init
// Information
public string lastReceivedUDPPacket = "";
public string allReceivedUDPPackets = ""; // Clean up this from time to time!
public bool newdatahereboys = false;
public void init(string IPAdress, int RemotePort, int SourcePort = -1) // If sourceport is not set, its being chosen randomly by the system
{
IP = IPAdress;
sourcePort = SourcePort;
remotePort = RemotePort;
remoteEndPoint = new IPEndPoint(IPAddress.Parse(IP), remotePort);
if (sourcePort <= -1)
{
client = new UdpClient();
Debug.Log("Sending to " + IP + ": " + remotePort);
}
else
{
client = new UdpClient(sourcePort);
Debug.Log("Sending to " + IP + ": " + remotePort + " from Source Port: " + sourcePort);
}
receiveThread = new Thread(
new ThreadStart(ReceiveData));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void ReceiveData()
{
//client = sender.client;
while (true)
{
try
{
// Bytes empfangen.
IPEndPoint anyIP = new IPEndPoint(IPAddress.Any, 0);
byte[] data = client.Receive(ref anyIP);
// Bytes mit der UTF8-Kodierung in das Textformat kodieren.
string text = Encoding.UTF8.GetString(data);
// Den abgerufenen Text anzeigen.
Debug.Log(text);
newdatahereboys = true;
//PlayerPrefs.SetString("ReceivedData", text);
// Latest UDPpacket
lastReceivedUDPPacket = text;
// ....
allReceivedUDPPackets = allReceivedUDPPackets + text;
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
}
// sendData in different ways. Can be extended accordingly
public void sendString(string message)
{
try
{
byte[] data = Encoding.UTF8.GetBytes(message);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public void sendInt32(Int32 myInt)
{
try
{
byte[] data = BitConverter.GetBytes(myInt);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public void sendInt32Array(Int32[] myInts)
{
try
{
byte[] data = new byte[myInts.Length * sizeof(Int32)];
Buffer.BlockCopy(myInts, 0, data, 0, data.Length);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public void sendInt16Array(Int16[] myInts)
{
try
{
byte[] data = new byte[myInts.Length * sizeof(Int16)];
Buffer.BlockCopy(myInts, 0, data, 0, data.Length);
client.Send(data, data.Length, remoteEndPoint);
}
catch (Exception err)
{
Debug.Log(err.ToString());
}
}
public string getLatestUDPPacket()
{
allReceivedUDPPackets = "";
return lastReceivedUDPPacket;
}
public void ClosePorts()
{
Debug.Log("closing receiving UDP on port: " + port);
if (receiveThread != null)
receiveThread.Abort();
client.Close();
}
}
File manager.cs:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class manager : MonoBehaviour {
public int Remoteport = 25666;
public UDPSend sender = new UDPSend();
public string datafromnode;
void Start()
{
sender.init("192.168.43.209", Remoteport, 25666);
sender.sendString("Hello from Start. " + Time.realtimeSinceStartup);
Application.targetFrameRate = 60;
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyUp(KeyCode.Return))
sender.sendString("This should be delivered");
if (sender.newdatahereboys)
{
datafromnode = sender.getLatestUDPPacket();
}
}
public void OnDisable()
{
sender.ClosePorts();
}
public void OnApplicationQuit()
{
sender.ClosePorts();
}
}
Success! See justlookatem.

C# Server Load balancer works only when break-point is set in VS debugger?

The Load balancer accepts incoming requests, re-sends them to multiple servers, and returns the answers from the servers to the awaiting clients.
// Dispatcher.cs
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace LoadBallancer {
public class Dispatcher
{
// set the TcpListener on port 8890
int port = 8890;
TcpListener server;
List<CoreComm> processors = new List<CoreComm>();
static void Main()
{
var dispatcher = new Dispatcher();
dispatcher.ListenForRequests();
}
public Dispatcher()
{
server = new TcpListener(IPAddress.Any, port);
}
public void ListenForRequests()
{
server.Start();
while (true)
{
try
{
// Start listening for client requests
// Enter the listening loop
Console.Write("Waiting for a connection... ");
lock(server)
{
// Perform a blocking call to accept requests.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected.");
ThreadPool.QueueUserWorkItem(ThreadProc, client);
}
}
catch (Exception e)
{
Console.WriteLine("Exception: {0}", e);
}
}
}
private static void ThreadProc(object obj)
{
var processor = new CoreComm((TcpClient)obj);
processor.ReSendRequest(null);
}
}
}
// CoreComm.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Configuration;
using System.Threading;
namespace LoadBallancer
{
public class IamServer
{
public string Url { get; set; }
public int Port { get; set; }
public string Type { get; set; }
}
public class CoreComm
{
// Buffer for reading data
int bufSize = 1024;
static List<IamServer> servers = new List<IamServer>();
protected TcpClient acceptorSocket;
NetworkStream acceptorStream;
protected TcpClient clientSocket;
protected List<KeyValuePair<int, byte[]>> requestPackets = new List<KeyValuePair<int, byte[]>>();
static CoreComm()
{
// reading config for servers' parameters
}
public CoreComm(TcpClient socket)
{
acceptorSocket = socket;
// Get a stream object for reading and writing
acceptorStream = acceptorSocket.GetStream();
}
private void ReadFromAcceptorStream()
{
// Loop to receive all the data sent by the client.
while (acceptorStream.DataAvailable)
{
byte[] requestBuffer = new byte[bufSize];
int i = acceptorStream.Read(requestBuffer, 0, requestBuffer.Length);
requestPackets.Add(new KeyValuePair<int, byte[]>(i, requestBuffer));
}
}
public void ReSendRequest(Object threadContext)
{
ReadFromAcceptorStream();
var servers = GetDestinationServers(null);
if (servers.Count == 0)
acceptorStream.Write(ErrMessage, 0, ErrMessage.Length);
else
// for debug only send the first in the list
SendRequestToServer(servers[0]);
// Shutdown and end connection
acceptorSocket.Close();
}
public void SendRequestToServer(IamServer server)
{
clientSocket = new TcpClient();
clientSocket.Connect(server.Url, server.Port);
NetworkStream clientStream = clientSocket.GetStream();
foreach (var packet in requestPackets)
clientStream.Write(packet.Value, 0, packet.Key);
var requestBuffer = new byte[bufSize];
while (clientStream.DataAvailable)
{
int i = clientStream.Read(requestBuffer, 0, requestBuffer.Length);
acceptorStream.Write(requestBuffer, 0, i);
}
clientSocket.Close();
}
// Mock up of the real load balancing algorithm
static int lastServerAnswered = 0;
public List<IamServer> GetDestinationServers(string requestData)
{
// processing to determine the query destinations
lock(servers)
{
// patch
int currentServerNum = lastServerAnswered;
lastServerAnswered ++ ;
if (lastServerAnswered > servers.Count - 1)
lastServerAnswered = 0;
return new List<IamServer> { servers[currentServerNum] };
}
}
}
}
So it works right when I set break-point in the code and does not work otherwise.
Any ideas?
The problem was found to be in the code:
while (clientStream.DataAvailable)
{
int i = clientStream.Read(requestBuffer, 0, requestBuffer.Length);
acceptorStream.Write(requestBuffer, 0, i);
}
Actually it happened that for some packets clientStream.DataAvailable was false even if there was still remaining data to be received. The solution is based on the application level protocol for which the Load Balancer had been developed that sends in the first 4 bytes of the stream the number of the total bytes that are sent.The code becomes as follows:
var responseBuffer = new byte[bufSize];
int numTotalBytesStreamed = clientStream.Read(responseBuffer, 0, responseBuffer.Length);
int numBytesToStream = GetNumBytesInTheStream(responseBuffer);
acceptorStream.Write(responseBuffer, 0, numTotalBytesStreamed);
while (numBytesToStream > numTotalBytesStreamed)
{
while (!clientStream.DataAvailable)
Thread.Sleep(1);
int numMoreBytesStreamed = clientStream.Read(responseBuffer, 0, responseBuffer.Length);
acceptorStream.Write(responseBuffer, 0, numMoreBytesStreamed);
numTotalBytesStreamed += numMoreBytesStreamed;
}
acceptorStream.Flush();
clientSocket.Close();
The solution works and is extremely stable for continuous loads of hundreds of requests per second.

.NET 4.5 ASync TCP Server Memory Leak - BeginReceive/BeginSend

We needed a Windows Service that supported TCP communications with a number of clients. So I based it on the MSDN Async Example The thing with the Microsoft example is that the client sends one message to the server, the server then resends the message then closes. Great!
So having blindly deployed this to our prod and customer site we got reports that it had crashed. Looking at Prod we noticed that after 1 day, the memory usage grew to just under 1GB before throwing an OutOfMemoryException. Lots of testing here!
This happened with 1 client connected. It sends an XML based message that is quite large ~1200 bytes every second. Yes, every second.
The service then does some processing and sends a return XML message back to the client.
I've pulled the TCP Client/Server communications into a simple set of Console applications to replicate the issue - mainly to eliminate other managed/unmanaged resources. Now I've been looking at this for a number of days now and have pulled all of my hair and teeth out.
In my example I am focusing on the following classes:
B2BSocketManager (Server Listener, Sender, Receiver)
NOTE I have changed the code to return the whoopsy readonly byte array - not the sent message. I've also removed the new AsyncCallback(delegate) from the BeginReceive/BeginSend calls.
namespace Acme.OPC.Service.Net.Sockets
{
using Acme.OPC.Service.Logging;
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
public class B2BSocketManager : ISocketSender
{
private ManualResetEvent allDone = new ManualResetEvent(false);
private IPEndPoint _localEndPoint;
private readonly byte[] whoopsy = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
public B2BSocketManager(IPAddress address, int port)
{
_localEndPoint = new IPEndPoint(address, port);
}
public void StartListening()
{
StartListeningAsync();
}
private async Task StartListeningAsync()
{
await System.Threading.Tasks.Task.Factory.StartNew(() => ListenForConnections());
}
public void ListenForConnections()
{
Socket listener = new Socket(_localEndPoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
Log.Instance.Info("B2BSocketManager Listening on " + _localEndPoint.Address.ToString() + ":" + _localEndPoint.Port.ToString());
try
{
listener.Bind(_localEndPoint);
listener.Listen(100);
while (true)
{
allDone.Reset();
Log.Instance.Info("B2BSocketManager Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(ConnectCallback), listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Log.Instance.Info(e.ToString());
}
}
public void ConnectCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
handler.DontFragment = false;
handler.ReceiveBufferSize = ClientSocket.BufferSize;
Log.Instance.Info("B2BSocketManager Client has connected on " + handler.RemoteEndPoint.ToString());
ClientSocket state = new ClientSocket();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, ClientSocket.BufferSize, 0, new AsyncCallback(ReadCallback), state); // SocketFlags.None
}
public void ReadCallback(IAsyncResult ar)
{
String message = String.Empty;
ClientSocket state = (ClientSocket)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
Console.WriteLine("Received " + bytesRead + " at " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
message = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
if (!string.IsNullOrEmpty(message))
{
Send(handler, message);
}
handler.BeginReceive(state.buffer, 0, ClientSocket.BufferSize, 0, ReadCallback, state);
}
}
public void Send(Socket socket, string data)
{
// just hard coding the whoopse readonly byte array
socket.BeginSend(whoopsy, 0, whoopsy.Length, 0, SendCallback, socket);
}
private void SendCallback(IAsyncResult ar)
{
Socket state = (Socket)ar.AsyncState;
try
{
int bytesSent = state.EndSend(ar);
}
catch (Exception e)
{
Log.Instance.ErrorException("", e);
}
}
}
}
ClientSender (Client Sender)
The client sends an xml string to the server every 250 milliseconds. I wanted to see how this would perform. The xml is slightly smaller than what we send on our live system and is just created using a formatted string.
namespace TestHarness
{
using System;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
class ClientSender
{
private static ManualResetEvent connectDone = new ManualResetEvent(false);
private static ManualResetEvent receiveDone = new ManualResetEvent(false);
private static ManualResetEvent sendDone = new ManualResetEvent(false);
private static void StartSpamming(Socket client)
{
while(true)
{
string message = #"<request type=""da"">{0}{1}</request>" + Environment.NewLine;
Send(client, string.Format(message, "Be someone" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), String.Concat(Enumerable.Repeat("<test>Oooooooops</test>", 50))));
Thread.Sleep(250);
}
}
public static void Connect(EndPoint remoteEP)
{
Socket listener = new Socket(remoteEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), listener);
connectDone.WaitOne();
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}", client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
System.Threading.Tasks.Task.Factory.StartNew(() => StartSpamming(client));
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(SendCallback), client);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), bytesSent);
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Receive(Socket client)
{
try
{
StateObject state = new StateObject();
state.workSocket = client;
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
else
{
if (state.sb.Length > 1)
{
string response = state.sb.ToString();
}
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
State Class
All I wanted was a read buffer to strip the message out of and try and load into XML. But this has been removed from this cut down version to see the issues with just the sockets.
using System;
using System.Linq;
using System.Net.Sockets;
namespace Acme.OPC.Service.Net.Sockets
{
public class ClientSocket
{
public Socket workSocket = null;
public const int BufferSize = 4096;
public readonly byte[] buffer = new byte[BufferSize];
}
}
I've shared my code here:
Explore One Drive Share
I've been profiling things using my Telerik JustTrace Profiler. I just start the server app then start the client app. This is on my Windows 7 64-bit VS2013 development environment.
Run 1
I see Memory Usage is around 250KB with the Working Set at around 20MB. The time seems to tick along nicely, then all of a sudden the memory usage will step up after around 12 minutes. Though things vary.
It would also appear that after the ~16:45:55 (Snapshot) when I Force GC, the memory starts going up each time I press it as opposed to leaving it running and upping automatically which might be an issue with Telerik.
Run 2
Then if I am creating the array of bytes within the Send with (which is more of what the service does - sends an appropriate response string to the client):
public void Send(Socket socket, string data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
socket.BeginSend(byteData, 0, byteData.Length, 0, SendCallback, socket);
}
We can see the memory going up more:
Which brings me to what is being retained in memory. I see a log of System.Threading.OverlappedData and I have noticed ExecutionContexts in there. The OverlappedData has a reference to a byte array this time.
With Roots Paths to GC
I am running the profiling overnight so will hopefully get to add more info to this in the morning. Hopefully somebody can point me in the right direction before that - if I'm doing something wrong and I am too blind/silly to see it.
And here are the results of running overnight:

Using SSL Stream with Asynchronous System.Net.Sockets

My server is now running using Asynchronous System.Net.Sockets but i want to use SSL stream with it. i am pretty new to using SSL so here is my server code if someone can help me with it
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
public class Wrapper
{
public byte[] buffer;
public Socket _socket;
public object connector;
}
public class WinSocket
{
private Dictionary<string, byte> Connections;
public event Action<Wrapper> AnnounceNewConnection;//Event Handlers
public event Action<Wrapper> AnnounceDisconnection;
public event Action<byte[], Wrapper> AnnounceReceive;
private Socket _socket;
public int MAX_USER_CONNECTIONS = 2;//Max User Connections
public WinSocket(ushort port)
{
try
{
Connections = new Dictionary<string, byte>();
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(IPAddress.Any, port));
_socket.Listen(500);
_socket.BeginAccept(AcceptConnections, new Wrapper());
}
catch (Exception e)
{
Console.WriteLine(e);//write an exception
}
}
private void AcceptConnections(IAsyncResult result)
{
try
{
Wrapper wr = result.AsyncState as Wrapper;
wr._socket = _socket.EndAccept(result);
#region Invisible
string IP = wr._socket.RemoteEndPoint.ToString().Split(':')[0].ToString();//Get user ip
if (!Connections.ContainsKey(IP))
Connections.Add(IP, 1);
else
if (Connections[IP] <= MAX_USER_CONNECTIONS)//Maximum Connections Per IP
{
byte connections = Connections[IP];
Connections.Remove(IP);//Limit exceeded
Connections.Add(IP, (byte)(connections + 1));
}
else
{
wr._socket.Disconnect(false);
_socket.BeginAccept(AcceptConnections, new Wrapper());
return;
}
#endregion
wr.buffer = new byte[65535];
wr._socket.BeginReceive(wr.buffer, 0, 65535, SocketFlags.None, ReceiveData, wr);
AnnounceNewConnection.Invoke(wr);
_socket.BeginAccept(AcceptConnections, new Wrapper());
}
catch (Exception e)
{
Console.WriteLine(e);//write an exception
}
}
private void ReceiveData(IAsyncResult result)//Receiving Data
{
try
{
Wrapper wr = result.AsyncState as Wrapper;
string IP = wr._socket.RemoteEndPoint.ToString().Split(':')[0].ToString();//Get UIP
if (Connections.ContainsKey(IP))
{
SocketError error = SocketError.Disconnecting;
int size = wr._socket.EndReceive(result, out error);
if (error == SocketError.Success && size != 0)
{
byte[] buffer = new byte[size];
Buffer.BlockCopy(wr.buffer, 0, buffer, 0, size);
AnnounceReceive.Invoke(buffer, wr);//The delegate
if (wr._socket.Connected)//Make sure socket is connected
wr._socket.BeginReceive(wr.buffer, 0, 65535, SocketFlags.None, ReceiveData, wr);//Start Receiving Data
}
else
{
if (wr._socket.Connected)
{
wr._socket.Disconnect(true);//Disconnect the client
}
byte connections = Connections[IP];
Connections.Remove(IP);
Connections.Add(IP, (byte)(connections - 1));
try
{
AnnounceDisconnection.Invoke(wr);
}
catch { }
}
}
}
catch (Exception e)
{
Console.WriteLine(e);//write an exception
}
}
}
So my question again clearly is : How to use SSL Stream with socket class like the ABOVE code
Replace the Stream class with the System.Net.SslStream class. In addition to the above code, call AuthenticateAsServer and pass the server SSL certificate in the WinSocket constructor.