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.
Related
I am trying to make a dedicated server for my new game using UDP sockets. I am using Socket.BeginSendTo() and Socket.BeginReceiveFrom() methods in order to send my data.
I am receiving the callbacks from both the methods, but when I am trying to Encoding.ASCII.GetString(buffer) it is not showing me any strings. I am not sure if there is a problem while sending, or if there is a problem while receiving.
I know that UDP does not guarantee the transmission, that's why I tried to send my data more then twice more like 10 times. Each time, I receive a callback that the data is sent on the client side and the data is received on the server side. But, as I said, when I am trying to read the data using Encoding, it shows nothing. I tried to do a string null or empty check while receiving the data. It said that the string is not empty, but when I try to Console.WriteLine(), it showed nothing in the console.
Here is the client code, where I am sending the data to the server:
public void SendMessage(Activity activityCode, String inputedString) //I am changed this
{
byte[] data = readMessage.WriteData(activityCode, inputedString);
if(data != null)
{
Debug.Log(data.Length); //this returned 11
clientSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, serverEndpoint, new AsyncCallback(OnSend), null);
}
Array.Clear(readMessage.data, 0, readMessage.data.Length);
}
private void OnSend(IAsyncResult ar)
{
Debug.Log("sent"); //I am getting this callback in my console
}
Here is my server code, where I am receiving the data:
private void StartReceiveingData()
{
try
{
if (!serverSocket.IsBound)
{
serverSocket.Bind(localServerIPEndPoint);
}
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
//The epSender identifies the incoming clients
EndPoint epSender = (EndPoint)ipeSender;
serverSocket.BeginReceiveFrom(StaticTest.byteData, 0, StaticTest.byteData.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void OnReceive(IAsyncResult ar)
{
StaticTest.printDData();
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint)ipeSender;
serverSocket.EndReceiveFrom(ar, ref epSender);
StartReceiveingData();
}
And here is where I am reading the data:
static public class StaticTest
{
static public byte[] byteData = new byte[1024];
public static void printDData()
{
Console.WriteLine("Reding the received data" + Encoding.UTF8.GetString(byteData));
}
}
UPDATE: I tried this code, but it still does not work:
private void StartReceiveingData()
{
try
{
if (!serverSocket.IsBound)
{
serverSocket.Bind(localServerIPEndPoint);
}
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
//The epSender identifies the incoming clients
EndPoint epSender = (EndPoint)ipeSender;
serverSocket.BeginReceiveFrom(byteData, 0, byteData.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void OnReceive(IAsyncResult ar)
{
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint)ipeSender;
int numData = serverSocket.EndReceiveFrom(ar, ref epSender);
if (!clientList.ContainsKey(epSender))
{
Client client = new Client(epSender);
clientList.Add(epSender, client);
}
if(clientList.TryGetValue(epSender, out Client client1))
{
string _receivedData = Encoding.UTF8.GetString(byteData, 0, numData);
Console.WriteLine(_receivedData + " Data that came");
//client1.RecieveDataFromMyGameObject(_receivedData);
}
StartReceiveingData();
}
And here is where I am reading the data:
public string TakeActions(string _recivedData)
{
int activityInput = Convert.ToInt32(_recivedData.Substring(0,1)); //there is an error
ActivityRequest activity = (ActivityRequest)activityInput;
Console.WriteLine("Current activity Number : " + activity);
if(activity == ActivityRequest.SetupClient)
{
SetupClientDataActivity.setupClientData(client,_recivedData.Substring(1,_recivedData.Length-1));
}
else if(activity == ActivityRequest.MatchMaking)
{
Console.WriteLine("Asking Room manager to get into a room");
// roomManager.AddAClientToARoom(client);
}
return null;
}
Your OnSend callback needs to call Socket.EndSendTo() to finish the send operation and tell you whether the operation was successful or not.
Your OnReceive callback is calling Socket.EndReceiveFrom(), but you are ignoring its result, and you are trying to print the byteData before calling EndReceiveFrom() to finish the read operation and tell you how many bytes were actually written into byteData.
Try this instead:
public void SendMessage(Activity activityCode, String inputedString)
{
byte[] data = readMessage.WriteData(activityCode, inputedString);
if (data != null)
{
Debug.Log($"sending {data.Length} bytes");
try
{
clientSocket.BeginSendTo(data, 0, data.Length, SocketFlags.None, serverEndpoint, new AsyncCallback(OnSend), null);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
Array.Clear(readMessage.data, 0, readMessage.data.Length);
}
private void OnSend(IAsyncResult ar)
{
try
{
int numBytes = clientSocket.EndSendTo(ar);
Debug.Log($"sent {numBytes} bytes");
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void StartReceiveingData()
{
try
{
if (!serverSocket.IsBound)
{
serverSocket.Bind(localServerIPEndPoint);
}
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint)ipeSender;
serverSocket.BeginReceiveFrom(StaticTest.byteData, 0, StaticTest.byteData.Length, SocketFlags.None, ref epSender, new AsyncCallback(OnReceive), epSender);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
private void OnReceive(IAsyncResult ar)
{
try
{
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint)ipeSender;
int numBytes = serverSocket.EndReceiveFrom(ar, ref epSender);
StaticTest.printDData(numBytes);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
StartReceiveingData();
}
static public class StaticTest
{
static public byte[] byteData = new byte[1024];
public static void printDData(int numBytes)
{
Console.WriteLine("Received data: {0}", Encoding.UTF8.GetString(byteData, 0, numBytes));
}
}
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?
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.
I am attempting to utilize MSDN's Asynchronous Client Socket code sample to connect and control some home equipment. As I understand, the sample code's ReceiveCallback method uses an instance of the EventWaitHandle ManualResetEvent and the method receiveDone.WaitOne() to hold processing of the current thread until the thread receives a signal that all of the socket's data has been transmitted from the remote device. After all of the socket's data has been transmitted (the socket's data is empty and bytesRead = 0), the Waithandle is removed and the application continues processing.
Unfortunately, by stepping-through the execution of the code, it appears that after the last time that the client returns data from the remote device, ReceiveCallback never returns to see if the data-queue is empty (i.e. bytesRead = 0), and thus never enters the "else" condition in ReceiveCallback where the state of the ManualResetEvent would have been reset and the application would have continued to process. Thus, since it never enters the "else" condition, ManualResetEvent is never reset and the application freezes.
Although I can remove the "receiveDone.WaitOne()" method from the code - permitting execution without waiting for the ManualResetEvent's notification that all of the data has been received; this returns a data-string from the equipment that is typically incomplete.
Am I using this code sample incorrectly? Has anyone seen this before or had any experience on how to work-around this issue?
7/14/2012 - UPDATE: After further testing of the MSDN's Asynchronous Client Socket Example, it became clear that ReceiveCallback actually re-polls the port and the "bytesRead = 0" condition is satisfied only when the socket is released (i.e. client.Shutdown(SocketShutdown.Both); client.Close(); ). If I understand this correctly, this means that the connection has to be closed to get past the receiveDone.WaitOne() method. If the connection is closed to satisfy the WaitOne() Waithandle, it totally defeats the purpose of the application in that I had been hoping to leave the connection open so that the application could listen for equipment updates, which happen continually.
7/16/2012 - UPDATE: I have written to Microsoft Tech Support who have responded that "We're doing research on this issue. It might take some time before we get back to you." As such, it seems that it doesn't appear that this challenge can be resolved at this time through massaging this code.
Without the availability of the Asynchronous Client Socket example code as a foundation for writing asynchronous communication procedures, may I ask if anyone can please suggest a replacement routine that is more reliable? There are three pieces of equipment, each with it's own ip-address and port number. Thus, it would be ideal if a class could be utilized, where an instance could be created for each device. Additionally, the port must remain open to receive spontaneous updates continually sent by the equipment. Lastly, the updates do not have a end character or defined length signalling that the transmission of the message is complete, thus the routine must continually poll the port for available data. Any advice or suggestions would be greatly appreciated.
7/18/2012 - WORKAROUND: After spending a considerable amount of time attempting to get the MSDN's Asynchronous Client Socket code sample working, it became clear that I would have to look elsewhere to get the device responses continuously recognized by the program. In the hope to save someone else the brain-damage, I have included the work-around that I used which seems to work well to this point. If anyone has any suggestions, please don't hesitate to add to this question!
//
// ORIGINAL CODE ATTEMPT
//
public static Socket LutronClient;
public static String LutronResponse = String.Empty;
private const int LutronPort = 4999;
private const string LutronIP = "192.168.1.71";
private static ManualResetEvent LutronConnectDone = new ManualResetEvent(false);
private static ManualResetEvent LutronSendDone = new ManualResetEvent(false);
private static ManualResetEvent LutronReceiveDone = new ManualResetEvent(false);
private static void StartLutronClient()
{
try
{
var lutronIPAddress = IPAddress.Parse(LutronIP);
var lutronRemoteEP = new IPEndPoint(lutronIPAddress, LutronPort);
LutronClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
LutronClient.BeginConnect(lutronRemoteEP, LutronConnectCallback, LutronClient);
LutronConnectDone.WaitOne();
LutronSend(LutronClient, "sdl,14,100,0,S2\x0d");
LutronSendDone.WaitOne();
LutronReceive(LutronClient);
LutronReceiveDone.WaitOne(new TimeSpan(5000));
MessageBox.Show("Response received from Lutron: " + LutronResponse);
txtBoxLutron.Text = LutronResponse;
LutronClient.Shutdown(SocketShutdown.Both);
LutronClient.Close();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
private static void LutronConnectCallback(IAsyncResult lutronAr)
{
try
{
var lutronClient = (Socket)lutronAr.AsyncState;
lutronClient.EndConnect(lutronAr);
LutronConnectDone.Set();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
private static void LutronReceive(Socket lutronClient)
{
try
{
var lutronState = new LutronStateObject { LutronWorkSocket = lutronClient };
lutronClient.BeginReceive(lutronState.LutronBuffer, 0, LutronStateObject.BufferSize, 0, new AsyncCallback(LutronReceiveCallback), lutronState);
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
private static void LutronReceiveCallback(IAsyncResult lutronAR)
{
try
{
var lutronState = (LutronStateObject)lutronAR.AsyncState;
var lutronClient = lutronState.LutronWorkSocket;
var bytesRead = lutronClient.EndReceive(lutronAR);
if (bytesRead > 0)
{
lutronState.LutronStringBuilder.AppendLine(Encoding.ASCII.GetString(lutronState.LutronBuffer, 0, bytesRead));
lutronClient.BeginReceive(lutronState.LutronBuffer, 0, LutronStateObject.BufferSize, 0, new AsyncCallback(LutronReceiveCallback), lutronState);
}
else
{
if (lutronState.LutronStringBuilder.Length > 0) { LutronResponse = lutronState.LutronStringBuilder.ToString(); }
LutronReceiveDone.Set();
}
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
public static void LutronSend(Socket client, String data)
{
var byteData = Encoding.ASCII.GetBytes(data);
client.BeginSend(byteData, 0, byteData.Length, 0, LutronSendCallback, client);
}
private static void LutronSendCallback(IAsyncResult ar)
{
try
{
var client = (Socket)ar.AsyncState;
var bytesSent = client.EndSend(ar);
LutronSendDone.Set();
}
catch (Exception e) { MessageBox.Show(e.ToString()); }
}
public class LutronStateObject
{
public Socket LutronWorkSocket;
public const int BufferSize = 256;
public byte[] LutronBuffer = new byte[BufferSize];
public StringBuilder LutronStringBuilder = new StringBuilder();
}
}
This is the work-around I used:
//
// WORK-AROUND
//
using System;
using System.Windows.Forms;
namespace _GlobalCacheInterface
{
public partial class GlobalCacheDataScreen : Form
{
//Interface objects
private static GC_Interface _lutronInterface;
private const int LutronPort = 4999;
private const string LutronIP = "192.168.1.71";
delegate void ThreadSafeLutronCallback(string text);
private static GC_Interface _elanInterface;
private const int ElanPort = 4998;
private const string ElanIP = "192.168.1.70";
delegate void ThreadSafeElanCallback(string text);
private static GC_Interface _tuneSuiteInterface;
private const int TuneSuitePort = 5000;
private const string TuneSuiteIP = "192.168.1.70";
delegate void ThreadSafeTuneSuiteCallback(string text);
public GlobalCacheDataScreen()
{
InitializeComponent();
_lutronInterface = new GC_Interface(LutronIP, LutronPort);
_elanInterface = new GC_Interface(ElanIP, ElanPort);
_tuneSuiteInterface = new GC_Interface(TuneSuiteIP, TuneSuitePort);
// Create event handlers to notify application of available updated information.
_lutronInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxLutron(_lutronInterface._returnString);
_elanInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxElan(_elanInterface._returnString);
_tuneSuiteInterface.DataAvailable += (s, e) => ThreadSafeTxtBoxTuneSuite(_tuneSuiteInterface._returnString);
_lutronInterface.Connected += (s, e) => UpdateUI();
_elanInterface.Connected += (s, e) => UpdateUI();
_tuneSuiteInterface.Connected += (s, e) => UpdateUI();
UpdateUI();
}
private void UpdateUI()
{
_buttonConnectToLutron.Enabled = !_lutronInterface._isConnected;
_buttonConnectToElan.Enabled = !_elanInterface._isConnected;
_buttonConnectToTuneSuite.Enabled = !_tuneSuiteInterface._isConnected;
_buttonDisconnectFromLutron.Enabled = _lutronInterface._isConnected;
_buttonDisconnectFromElan.Enabled = _elanInterface._isConnected;
_buttonDisconnectFromTuneSuite.Enabled = _tuneSuiteInterface._isConnected;
string connectLutronStatus = _lutronInterface._isConnected ? "Connected" : "Not Connected";
string connectElanStatus = _elanInterface._isConnected ? "Connected" : "Not Connected";
string connectTuneSuiteStatus = _tuneSuiteInterface._isConnected ? "Connected" : "Not Connected";
_textBoxLutronConnectStatus.Text = connectLutronStatus;
_textBoxElanConnectStatus.Text = connectElanStatus;
_textBoxTuneSuiteConnectStatus.Text = connectTuneSuiteStatus;
}
private void ThreadSafeTxtBoxLutron(string message) { if (_lutronRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeLutronCallback(ThreadSafeTxtBoxLutron); _lutronRichTextRxMessage.Invoke(d, new object[] { message }); } else { _lutronRichTextRxMessage.Text = message; } }
private void ThreadSafeTxtBoxElan(string message) { if (_elanRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeElanCallback(ThreadSafeTxtBoxElan); _elanRichTextRxMessage.Invoke(d, new object[] { message }); } else { _elanRichTextRxMessage.Text = message; if (message.EndsWith("\r")) { MessageBoxEx.Show(message, "Message from Lutron Elan", 1000); } } }
private void ThreadSafeTxtBoxTuneSuite(string message) { if (_tuneSuiteRichTextRxMessage.InvokeRequired) { var d = new ThreadSafeTuneSuiteCallback(ThreadSafeTxtBoxTuneSuite); _tuneSuiteRichTextRxMessage.Invoke(d, new object[] { message }); } else { _tuneSuiteRichTextRxMessage.Text = message; if (message.EndsWith("\r")) { MessageBoxEx.Show(message, "Message from TuneSuite", 1000); } } }
private void _buttonConnectToLutron_Click(object sender, EventArgs e) { _lutronInterface.Connect(); }
private void _buttonDisconnectFromLutron_Click(object sender, EventArgs e) { _lutronInterface.Disconnect(); }
private void _buttonConnectToElan_Click(object sender, EventArgs e) { _elanInterface.Connect(); }
private void _buttonDisconnectFromElan_Click(object sender, EventArgs e) { _elanInterface.Disconnect(); }
private void _buttonConnectToTuneSuite_Click(object sender, EventArgs e) { _tuneSuiteInterface.Connect(); }
private void _buttonDisconnectFromTuneSuite_Click(object sender, EventArgs e) { _tuneSuiteInterface.Disconnect(); }
private void _buttonLutronSendMessage_Click(object sender, EventArgs e) { _lutronInterface.SendCommand(_lutronRichTextTxMessage.Text); }
private void _buttonElanSendMessage_Click(object sender, EventArgs e) { _elanInterface.SendCommand(_elanRichTextTxMessage.Text); }
private void _buttonTuneSuiteSendMessage_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand(_elanRichTextTxMessage.Text); }
private void _buttonLightOn_Click(object sender, EventArgs e) { _lutronInterface.SendCommand("sdl,14,100,0,S2"); }
private void _buttonLightOff_Click(object sender, EventArgs e) { _lutronInterface.SendCommand("sdl,14,0,0,S2"); }
private void _buttonStereoOnOff_Click(object sender, EventArgs e) { _elanInterface.SendCommand("sendir,4:3,1,40000,4,1,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,181,21,800"); }
private void _button30_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x33\x30\x00\x30\x21\xB8"); }
private void _button31_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x33\x31\x00\x30\x21\xB8"); }
private void _button26_Click(object sender, EventArgs e) { _tuneSuiteInterface.SendCommand("\xB8\x4D\xB5\x32\x36\x00\x30\x21\xB8"); }
}
}
and the GC_Interface class:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows.Forms;
namespace _GlobalCacheInterface
{
class GC_Interface
{
// Declare an event handler to notify when updates are available.
public event EventHandler<EventArgs> DataAvailable;
public string _returnString = "";
// Declare an event handler to notify status of connection.
public event EventHandler<EventArgs> Connected;
public bool _isConnected;
public AsyncCallback ReceiveCallback;
public Socket Client;
private string _ipAddress;
private int _port;
private bool _waitForEndCharacter;
private byte _endCharacter;
byte[] m_DataBuffer = new byte[10];
IAsyncResult m_Result;
public GC_Interface(string ipAddress, int port) { Init(ipAddress, port, false, 0); }
private void Init(string ipAddress, int port, bool waitForEndCharacter, byte endCharacter)
{
_ipAddress = ipAddress;
_port = port;
_waitForEndCharacter = waitForEndCharacter;
_endCharacter = endCharacter;
_isConnected = false;
}
public bool Connect()
{
try
{
// Create a TCP/IP socket.
Client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// Establish the remote endpoint for the socket.
var address = IPAddress.Parse(_ipAddress);
var remoteEP = new IPEndPoint(address, _port);
// Connect to the remote endpoint.
Client.Connect(remoteEP);
if (Client.Connected)
{
_isConnected = true;
ConnectedEventHandler();
WaitForData();
}
return true;
}
catch (SocketException se) { MessageBox.Show("\n connection failed, is the server running?\n" + se.Message ); return false; }
}
public bool SendCommand(string command)
{
try
{
// Convert the string data to byte data using ASCII encoding.
var byteData = Encoding.Default.GetBytes(command);
// Add a carraige-return to the end.
var newArray = new byte[byteData.Length + 1];
byteData.CopyTo(newArray, 0);
newArray[newArray.Length - 1] = 13;
if (Client == null) { return false; }
Client.Send(newArray);
return true;
}
catch (SocketException se) { MessageBox.Show(se.Message); return false; }
}
public void WaitForData()
{
try
{
if (ReceiveCallback == null) { ReceiveCallback = new AsyncCallback(OnDataReceived); }
var theSocPkt = new SocketPacket { thisSocket = Client };
m_Result = Client.BeginReceive(theSocPkt.DataBuffer, 0, theSocPkt.DataBuffer.Length, SocketFlags.None, ReceiveCallback, theSocPkt);
}
catch (SocketException se) { MessageBox.Show(se.Message); }
}
public class SocketPacket
{
public System.Net.Sockets.Socket thisSocket;
public byte[] DataBuffer = new byte[1];
}
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
var iRx = theSockId.thisSocket.EndReceive(asyn);
char[] Chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int CharLen = d.GetChars(theSockId.DataBuffer, 0, iRx, Chars, 0);
System.String szData = new System.String(Chars);
_returnString = _returnString + szData.Replace("\0", "");
// When an update is received, raise DataAvailable event
DataAvailableEventHandler();
WaitForData();
}
catch (ObjectDisposedException) { System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n"); }
catch (SocketException se) { MessageBox.Show(se.Message); }
}
public bool Disconnect()
{
try
{
if (Client == null) { return false; }
Client.Close();
Client = null;
_isConnected = false;
return true;
}
catch (Exception) { return false; }
}
protected virtual void DataAvailableEventHandler()
{
var handler = DataAvailable;
if (handler != null) { handler(this, EventArgs.Empty); }
}
protected virtual void ConnectedEventHandler()
{
var handler = Connected;
if (handler != null) { handler(this, EventArgs.Empty); }
}
}
}
I had the same issue, adding an Available check to the code fixed my problem. Below is the revised code.
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));
// Check if there is anymore data on the socket
if (client.Available > 0) {
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}
if (bytesRead == 0 || client.Available == 0) {
if (state.sb.Length > 1) {
response = state.sb.ToString();
}
receiveDone.Set();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
Hope that helps.
I'm sidestepping the question here. I try to answer what you need, not what you ask for:
Use synchronous code. It will be easier to understand, you don't need callbacks or events. Also, for low thread counts, it is likely to perform better.
You also avoid bugs that you have in your current code. If an exception occurs your computation never completes. Synchronous code does not have that problem.
Through a lot of learning and research, i wrote a server side program. But the problem with this program is that it doesn't accept multiple clients, and i also wanted to know how to send the output back to client side instead of displaying it on the server side. Can someone please help me out with the code? This is what I've tried till now -
class Program
{
private static Regex _regex = new Regex("not|http|console|application", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
static void Main(string[] args)
{
{
TcpListener serversocket = new TcpListener(8888);
TcpClient clientsocket = default(TcpClient);
serversocket.Start();
Console.WriteLine(">> Server Started");
clientsocket = serversocket.AcceptTcpClient();
Console.WriteLine("Accept Connection From Client");
try
{
using (var reader = new StreamReader(clientsocket.GetStream()))
{
string line;
int lineNumber = 0;
while (null != (line = reader.ReadLine()))
{
lineNumber += 1;
foreach (Match match in _regex.Matches(line))
{
Console.WriteLine("Line {0} matches {1}", lineNumber, match.Value);
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
clientsocket.Close();
serversocket.Stop();
Console.WriteLine(" >> exit");
Console.ReadLine();
}
}
}
You could change it to something like this.
static void Main(string[] args)
{
TcpListener serversocket = new TcpListener(8888);
TcpClient clientsocket = default(TcpClient);
serversocket.Start();
Console.WriteLine(">> Server Started");
while(true)
{
clientsocket = serversocket.AcceptTcpClient();
Console.WriteLine("Accept Connection From Client");
LineMatcher lm = new LineMatcher(clientsocket);
Thread thread = new Thread(new ThreadStart(lm.Run));
thread.Start();
Console.WriteLine("Client connected");
}
serversocket.Stop();
Console.WriteLine(" >> exit");
Console.ReadLine();
}
And then have this seperate class handling the linematching
public class LineMatcher{
private static Regex _regex = new Regex("not|http|console|application", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private TcpClient _client;
public LineMatcher(TcpClient client)
{
_client = client;
}
public void Run()
{
try
{
using (var reader = new StreamReader(_client.GetStream()))
{
string line;
int lineNumber = 0;
while (null != (line = reader.ReadLine()))
{
lineNumber += 1;
foreach (Match match in _regex.Matches(line))
{
Console.WriteLine("Line {0} matches {1}", lineNumber, match.Value);
}
}
}
}
catch (Exception ex)
{
Console.Error.WriteLine(ex.ToString());
}
Console.WriteLine("Closing client");
_client.Close();
}
}
This is purely a proof of concept and is no way stable code ;)
Please note that this doesn't manage the child-threads in any way.
There is also no correct way of shutting down the listener because of the while(true)