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.
Related
We have a project that we should send message to a huge number of sim cards (more than 1 Million) and receive and handle answers.
For testing this, I am using Selenium SMPPSim to simulate sending a message.
this is work fine for sending messages. and with enabling callback server I can receive messages that I send on another port.
But my question is how can I send back a message to SMPP server?
I am using EasySMPP library for connecting to smpp server
My SMPP Server Code:
private SMPPClient _client;
private readonly object _lockObject = new object();
public SMPPClient GetClient()
{
if (_client != null)
{
return _client;
}
lock (_lockObject)
{
_client = new SMPPClient();
var smsc = new SMSC
{
Host = "127.0.0.1",
Port = 2775,
SystemId = "smppclient1",
Password = "password",
SourceTon = 5,
SourceNpi = 1,
AddrTon = 1,
AddrNpi = 1,
SystemType = "8945",
};
_client.OnDeliverSm += Client_OnDeliverSm;
Console.WriteLine("Client_OnDeliverSm added");
_client.OnSubmitSmResp += Client_OnSubmitSmResp;
Console.WriteLine("OnSubmitSmResp added");
_client.AddSMSC(smsc);
if (!_client.Connect())
throw new Exception($"Can not connect to smpp link: {smsc.Host} : {smsc.Port}");
return _client;
}
}
public void SendByCampaignItemId()
{
var smppClient = GetClient();
lock (smppClient)
{
var msgId = smppClient.SubmitSM(1, 1, "339123456789", 1, 1, "339632587436",
0x40, // EsmClass.UdhIndicator
0x7f, // protocol identifier
0, // priority flag level 0
DateTime.MinValue,
DateTime.MinValue,
// DateTime.Now.AddMinutes(10),
//DateTime.Now.AddHours(3),
(byte)DeliveryReportType.AlwaysSendDeliveryReport,
0x00, //replace if present
0xf6, // data coding
0, // default msg id
new byte[] { 0x02,0x70,0x00,0x34,0x77,0x88,0x99,0xAA,0xBB,0xCC,0xDD,0xEE,0xFF});
}
}
private void Client_OnSubmitSmResp(SubmitSmRespEventArgs e)
{
Console.WriteLine("Submit Received");
}
private void Client_OnDeliverSm(DeliverSmEventArgs e)
{
Console.WriteLine("Deliver Received");
}
And here is my code which listens to port 3333:
static void Main(string[] args)
{
TcpListener server = null;
try
{
Int32 port = 3333;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
server = new TcpListener(localAddr, port);
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection... ");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
data = null;
NetworkStream stream = client.GetStream();
int i;
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, msg.Length);
//WHAT SHOULD I DO HERE SO THAT I CAN SEND BACK A MESSAGE (DELIVER SM) TO SMPP SIM??!!!
Console.WriteLine("Sent: {0}", data);
}
client.Close();
}
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
And my SMPPSIM Config file :
SMPP_PORT=2775
SMPP_CONNECTION_HANDLERS=10
CONNECTION_HANDLER_CLASS=com.seleniumsoftware.SMPPSim.StandardConnectionHandler
PROTOCOL_HANDLER_CLASS=com.seleniumsoftware.SMPPSim.StandardProtocolHandler
LIFE_CYCLE_MANAGER=com.seleniumsoftware.SMPPSim.LifeCycleManager
MESSAGE_STATE_CHECK_FREQUENCY=5000
MAX_TIME_ENROUTE=10000
DELAY_DELIVERY_RECEIPTS_BY=0
PERCENTAGE_THAT_TRANSITION=75
PERCENTAGE_DELIVERED=90
PERCENTAGE_UNDELIVERABLE=6
PERCENTAGE_ACCEPTED=2
PERCENTAGE_REJECTED=2
DISCARD_FROM_QUEUE_AFTER=60000
HTTP_PORT=88
HTTP_THREADS=1
DOCROOT=www
AUTHORISED_FILES=/css/style.css,/index.htm,/inject_mo.htm,/favicon.ico,/images/logo.gif,/images/dots.gif,/user-guide.htm,/images/homepage.gif,/images/inject_mo.gif
INJECT_MO_PAGE=/inject_mo.htm
SYSTEM_IDS=smppclient1,smppclient2
PASSWORDS=password,password
OUTBIND_ENABLED=false
OUTBIND_ESME_IP_ADDRESS=127.0.0.1
OUTBIND_ESME_PORT=2776
OUTBIND_ESME_SYSTEMID=smppclient1
OUTBIND_ESME_PASSWORD=password
DELIVERY_MESSAGES_PER_MINUTE=0
DELIVER_MESSAGES_FILE=deliver_messages.csv
LOOPBACK=TRUE
ESME_TO_ESME=false
OUTBOUND_QUEUE_MAX_SIZE=1000
INBOUND_QUEUE_MAX_SIZE=1000
DELAYED_INBOUND_QUEUE_PROCESSING_PERIOD=60
DELAYED_INBOUND_QUEUE_MAX_ATTEMPTS=100
DECODE_PDUS_IN_LOG=true
CAPTURE_SME_BINARY=false
CAPTURE_SME_BINARY_TO_FILE=sme_binary.capture
CAPTURE_SMPPSIM_BINARY=false
CAPTURE_SMPPSIM_BINARY_TO_FILE=smppsim_binary.capture
CAPTURE_SME_DECODED=false
CAPTURE_SME_DECODED_TO_FILE=sme_decoded.capture
CAPTURE_SMPPSIM_DECODED=false
CAPTURE_SMPPSIM_DECODED_TO_FILE=smppsim_decoded.capture
CALLBACK=true
CALLBACK_ID=SIM1
CALLBACK_TARGET_HOST=localhost
CALLBACK_PORT=3333
DELIVER_SM_INCLUDES_USSD_SERVICE_OP=false
DELIVERY_RECEIPT_OPTIONAL_PARAMS=true
DELIVERY_RECEIPT_TLV=1403/0A/34343132333435363738
SMSCID=SMPPSim
SIMULATE_VARIABLE_SUBMIT_SM_RESPONSE_TIMES=false
And another question:
If SMPPSim is not a good choice for my work, what else can i use?
UPDATE 1:
I look a little more and I think I find a simpler question.
assume that i have to SMPPSims.
How can I send message from a SMPPSim to another one?
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.
I have two win socket apps, server and client. The server app is at my virtual and client at host machine and the communication is OK. I am sending a ISO file (700MB) through that socket and I came across the error that received bytes are corrupt. When my file come to virtual machine, it has the original size, but the content is not OK. At the client side, I am using this code:
public class ProgramClient
{
public static void StartClient()
{
// Data buffer for incoming data.
byte[] msg;
try
{
IPAddress ipAd = IPAddress.Parse("192.168.137.71");
IPEndPoint remoteEP = new IPEndPoint(ipAd, 1234);
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sender.Connect(remoteEP);
Console.WriteLine("Client connected to {0}", sender.RemoteEndPoint.ToString());
Console.WriteLine("Sending file...");
msg = GetBinaryFile(#"C:\TCPIP\test_big.iso");
byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
int msgLength = BitConverter.ToInt32(msgLengthBytes, 0);
Console.WriteLine("int: {0}", msgLength);
Console.WriteLine("msgL size: {0}", msgLengthBytes.Length);
//join arrays, file size info, TCP header
byte[] result = new byte[msgLengthBytes.Length + msgLength];
Buffer.BlockCopy(msgLengthBytes, 0, result, 0, msgLengthBytes.Length);
Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);
//file extension info, TCP Header
byte extension = 2; //file extension code
byte[] newArray = new byte[result.Length + 1];
result.CopyTo(newArray, 1);
newArray[0] = extension;
result = newArray;
int bytesSent = sender.Send(result);
Console.WriteLine("result size: {0}", result.Length);
sender.Shutdown(SocketShutdown.Both);
sender.Close();
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
private static byte[] GetBinaryFile(string filename)
{
byte[] bytes;
using (FileStream file = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
return bytes;
}
public static void Main(String[] args)
{
StartClient();
}
}
At the server side I have the following code:
class ProgramServer
{
public static void Main(String[] args)
{
try
{
StartListening();
}
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
public static void StartListening()
{
byte[] bytes = new Byte[1024];
while (true)
{
string outputPath = string.Empty;
outputPath = #"C:\output\output";
Console.WriteLine("Waiting for a connection...");
Socket handler = SocketInstance().Accept();
data = null;
//for the TCP header, get file extension
bytes = new byte[1];
int bytesReceivedExtension = handler.Receive(bytes);
string extension = GetExtension(bytes[0]);
outputPath = outputPath + extension;
//for the TCP header, get file size information
bytes = new byte[4];
int bytesReceived = handler.Receive(bytes);
int Lenght = BitConverter.ToInt32(bytes, 0);
Console.WriteLine("msg length: " + Lenght);
int TotalReceivedBytes = 0;
while (TotalReceivedBytes < Lenght)
{
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes);
}
Console.WriteLine("Bytes received total: " + TotalReceivedBytes);
Console.WriteLine(File.Exists(outputPath) ? "File received." : "File not received.");
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
private static Socket SocketInstance()
{
IPAddress ipAd = IPAddress.Parse("192.168.137.71");
IPEndPoint localEndPoint = new IPEndPoint(ipAd, 1234);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(10);
return listener;
}
public static void AppendAllBytes(string path, byte[] bytes)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bytes.Length);
}
}
public static string GetExtension(byte extOfFile)
{
switch (extOfFile)
{
case 0:
return ".txt";
case 1:
return ".png";
case 2:
return ".iso";
default:
return "";
}
}
}
So, how can I be sure that my byte[] is OK? Because when I open that ISO file at the received side, its content is not OK. IS there some alternative for any type of file to binary conversion?
Thanks.
The framing protocol you made up seems to work like this:
0 1 2 3 4 ... N
[L][L][L][L][D][...][D]
Where L represents an 32-bit integer (in which endianness?) indicating the lenght of the Data.
First, you're sending the wrong file length:
byte[] msgLengthBytes = BitConverter.GetBytes(msg.Length-3);
Why do you subtract 3? You shouldn't. This causes the last 3 bytes to be chopped off the file.
Then when filling the message buffer, you start writing at byte 3, or the last byte of L:
Buffer.BlockCopy(msg, 3, result, msgLengthBytes.Length, msgLength);
This will cause the reader to interpret an incorrect data length. You should start at byte 4.
Third, when writing the file, you shouldn't append the entire buffer, but only the bytes that Receive() actually wrote in the buffer:
bytes = new byte[1024];
int bytesRec = handler.Receive(bytes);
TotalReceivedBytes = TotalReceivedBytes + bytesRec;
AppendAllBytes(outputPath, bytes, bytesRec);
Then in that method:
public static void AppendAllBytes(string path, byte[] bytes, int bufferLength)
{
using (var stream = new FileStream(path, FileMode.Append))
{
stream.Write(bytes, 0, bufferLength);
}
}
And this is why you shouldn't write your own protocol and socket code if you don't know very well what you're doing. Leverage existing protocols and libraries instead.
How can I use if condition in asynchronous socket programming.
For example if client sends "hello" then server response is "hi" and if client send "how r u" then server send "i am fine".
I have this code and I am trying to do that, but it does not work.
Please tell where i need to change my code.
Thanks in Advance
Here is server code
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
byte[] bytes = new Byte[1024];
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 8888);
Socket listener = new Socket(AddressFamily.InterNetwork,SocketType.Stream, ProtocolType.Tcp);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
allDone.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
allDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,new AsyncCallback(ReadCallback), state);
}
public static void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
if (content == "hello")
{
Console.WriteLine(content);
Send(handler, content);
}
else if (content == "How r u")
{
Console.WriteLine(content);
Send2(handler, content);
}
}
else
{
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data)
{
data = "Hi";
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0,new AsyncCallback(SendCallback), handler);
}
private static void Send2(Socket handler, String data)
{
data = "fine";
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
content == "How r u" and content == "hello" check the object equality by comparing there references. content and your const strings are not in the same memory (not the same objects).
To compare there content call content.compareTo("How r u")==0.
I solved it. I just have to put < eof > at the end of 'hello' like "hello< eof >" and same to how r u. Its work now.
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.