I am trying to learn to play with named pipes for communication. The following code project does a great job showing what an example with a raw string.
https://www.codeproject.com/Tips/492231/Csharp-Async-Named-Pipes
I am wrestling with changing the sending of a raw string to send an object instead.
Can someone demonstrate how to send an Order instead of a string?
I have some code to send an object but having issues combining the code project with this idea..
Here is my pipeClient
public class Order
{
public string ProductName { get; set; }
public int Quantity { get; set; }
public string CustomerName { get; set; }
public string Address { get; set; }
}
class PipeClient
{
public void Send(string SendStr, string PipeName, int TimeOut = 1000)
{
try
{
NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", "orders", PipeDirection.Out, PipeOptions.Asynchronous);
// The connect function will indefinitely wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
Order order = new Order()
{
Address = SendStr,
CustomerName = "John",
ProductName = "Visual Studio 2015",
Quantity = 1
};
string serialised = Json.Net.JsonNet.Serialize(order);
pipeStream.Connect(TimeOut);
Debug.WriteLine("[Client] Pipe connection established");
byte[] _buffer = Encoding.UTF8.GetBytes(serialised);
pipeStream.BeginWrite(_buffer, 0, _buffer.Length, AsyncSend, pipeStream);
}
catch (TimeoutException oEX)
{
Debug.WriteLine(oEX.Message);
}
}
private void AsyncSend(IAsyncResult iar)
{
try
{
// Get the pipe
NamedPipeClientStream pipeStream = (NamedPipeClientStream)iar.AsyncState;
// End the write
pipeStream.EndWrite(iar);
pipeStream.Flush();
pipeStream.Close();
pipeStream.Dispose();
}
catch (Exception oEX)
{
Debug.WriteLine(oEX.Message);
}
}
}
My code breaks here --> pipeStream.Connect(TimeOut);
Here is my server edits
private void WaitForConnectionCallBack(IAsyncResult iar)
{
try
{
// Get the pipe
NamedPipeServerStream pipeServer = (NamedPipeServerStream)iar.AsyncState;
// End waiting for the connection
pipeServer.EndWaitForConnection(iar);
StringBuilder messageBuilder = new StringBuilder();
string messageChunk = string.Empty;
byte[] buffer = new byte[255];
do
{
pipeServer.Read(buffer, 0, buffer.Length);
messageChunk = Encoding.UTF8.GetString(buffer);
messageBuilder.Append(messageChunk);
buffer = new byte[buffer.Length];
}
while (!pipeServer.IsMessageComplete);
//Order order = Json.Net.JsonNet.Deserialize<Order>(messageBuilder.ToString());
PipeMessage.Invoke(messageBuilder.ToString());
// Read the incoming message
//pipeServer.Read(buffer, 0, 255);
// Convert byte buffer to string
//string stringData = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
//Debug.WriteLine(stringData + Environment.NewLine);
// Pass message back to calling form
//PipeMessage.Invoke(stringData);
// Kill original sever and create new wait server
pipeServer.Close();
pipeServer = null;
pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous);
// Recursively wait for the connection again and again....
pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
}
catch
{
return;
}
}
.
.
. Server Form
private void PipesMessageHandler(string message)
{
try
{
if (this.InvokeRequired)
{
this.Invoke(new NewMessageDelegate(PipesMessageHandler), message);
}
else
{
Order order = Json.Net.JsonNet.Deserialize<Order>(message);
txtOutput.Text = txtOutput.Text +
Environment.NewLine +
String.Format("Address: {0}" +
"Customer: {1}" +
"Product: {2}" +
"Quantity: {3}", order.Address, order.CustomerName, order.ProductName, order.Quantity.ToString());
//txtMessage.Text = message;
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
Related
I have two application which is Cashier.exe and Payment.exe
I want to pass the data for PosWindows.retrieveOrder from Cashier.exe to Payment.exe
PosWindows.retrieveOrder contains lots of data such as OrderId, OrderCode and more (which means its not single data)
I'm using this code but it does not send the data. is it because it cannot send a whole data like that ?
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:/Project/Application/Payment/Payment.exe";
psi.Arguments = "\"" + PosWindows.totalAmount.ToString() + "\"\"" + PosWindows.retrieveOrder + "\"";
var p = Process.Start(psi);
If I only send PosWindows.totalAmount.ToString().
which is something like this
ProcessStartInfo psi = new ProcessStartInfo();
psi.FileName = "C:/Project/Application/Payment/Payment.exe";
psi.Arguments = "\""+ PosWindows.totalAmount.ToString() + "\"";
var p = Process.Start(psi);
its working fine. but when I add PosWindows.retrieveOrder its not working.
does it impossible to send the PosWindows.retrieveOrder ?
I don't know if this problem come from this code below (because I don't declare for retrieveOrder)
This one at Payment.exe
private void app_Startup(object sender, StartupEventArgs e)
{
var args = e.Args;
if (args != null && args.Count() > 0)
{
foreach (var arg in args)
{
PaymentView.globalTotalAmount = decimal.Parse(arg);
}
}
}
if yes what will I do ? I means what should I put to replace this part decimal.Parse(arg) for retrieveOrder ?
You can use NamedPipeServerStream class.
https://learn.microsoft.com/en-us/dotnet/api/system.io.pipes.namedpipeserverstream?view=netframework-4.7.2
Take one of your apps as client, and the other as server. You can handle an async communication and parse your message when listening is completed.
Also you can check out Example of Named Pipes
Edit for solution example:
At client app, lets call the class PipeClient.cs
public void Send(string SendStr, string PipeName, int TimeOut = 1000)
{
try
{
NamedPipeClientStream pipeStream = new NamedPipeClientStream(".", PipeName, PipeDirection.Out, PipeOptions.Asynchronous);
// The connect function will indefinitely wait for the pipe to become available
// If that is not acceptable specify a maximum waiting time (in ms)
pipeStream.Connect(TimeOut);
Debug.WriteLine("[Client] Pipe connection established");
byte[] _buffer = Encoding.UTF8.GetBytes(SendStr);
pipeStream.BeginWrite(_buffer, 0, _buffer.Length, AsyncSend, pipeStream);
}
catch (Exception ex)
{
Debug.WriteLine("Pipe Send Exception: " + ex);
}
}
private void AsyncSend(IAsyncResult iar)
{
try
{
// Get the pipe
NamedPipeClientStream pipeStream = (NamedPipeClientStream)iar.AsyncState;
// End the write
pipeStream.EndWrite(iar);
pipeStream.Flush();
pipeStream.Close();
pipeStream.Dispose();
}
catch (Exception oEX)
{
Debug.WriteLine(oEX.Message);
}
}
And after you initialize your class just send the message with:
_pipeClient.Send(pipeMsg, "PipeName", Timeout);
At server app, lets call the class PipeServer.cs
public void Listen(string PipeName)
{
try
{
// Set to class level var so we can re-use in the async callback method
_pipeName = PipeName;
// Create the new async pipe
NamedPipeServerStream pipeServer = new NamedPipeServerStream(PipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
// Wait for a connection
pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
}
catch (Exception oEX)
{
Debug.WriteLine(oEX.Message);
}
}
private void WaitForConnectionCallBack(IAsyncResult iar)
{
NamedPipeServerStream pipeServer = (NamedPipeServerStream)iar.AsyncState;
try
{
// End waiting for the connection
pipeServer.EndWaitForConnection(iar);
byte[] buffer = new byte[255];
// Read the incoming message
pipeServer.Read(buffer, 0, 255);
// Convert byte buffer to string
string stringData = Encoding.UTF8.GetString(buffer, 0, buffer.Length);
Debug.WriteLine(stringData + Environment.NewLine);
// Pass message back to calling form
PipeMessage.Invoke(stringData);
// Kill original server and create new wait server
pipeServer.Close();
pipeServer = null;
pipeServer = new NamedPipeServerStream(_pipeName, PipeDirection.In, 1, PipeTransmissionMode.Message, PipeOptions.Asynchronous);
// Recursively wait for the connection again and again....
pipeServer.BeginWaitForConnection(new AsyncCallback(WaitForConnectionCallBack), pipeServer);
}
catch (Exception ex)
{
string ctch = ex.ToString();
return;
}
}
For handling the pipestream message, delegate to a handler and parse the message:
_pipeServer.PipeMessage += new DelegateMessage(PipesMessageHandler);
at somewhere you need in your code:
_pipeServer.Listen("PipeName");
and parse for example:
private void PipesMessageHandler(string message)
{
if (this.Dispatcher.CheckAccess())
{
this.Dispatcher.Invoke(new NewMessageDelegate(PipesMessageHandler), message);
}
else
{
string pipeMessage = Convert.DateTime(message);
}
}
I am trying to understand the correct way of how should I make good multithreaded TCP server.
Here is what I have so far:
public class WorldServer
{
public List<ServerClient> clients = new List<ServerClient>();
public int port = 8080;
public TcpListener server;
private bool serverStarted;
private int connectionIncrementor;
private MySQLConnection mySQLConnection = new MySQLConnection();
private MySqlConnection mysqlConn = null;
static void Main(string[] args)
{
WorldServer serverInstance = new WorldServer();
Console.WriteLine("Starting World Server...");
try
{
serverInstance.mysqlConn = new MySqlConnection(serverInstance.mySQLConnection.mysqlConnectionString);
serverInstance.mysqlConn.Open();
Console.WriteLine("Connected to MySQL version: " + serverInstance.mysqlConn.ServerVersion + "\n");
}
catch (Exception e)
{
Console.WriteLine("MySQL Error: " + e.ToString());
}
finally
{
if (serverInstance.mysqlConn != null)
{
serverInstance.mysqlConn.Close();
}
}
serverInstance.clients = new List<ServerClient>();
try
{
serverInstance.server = new TcpListener(IPAddress.Any, serverInstance.port);
serverInstance.server.Start();
serverInstance.StartListening();
serverInstance.serverStarted = true;
Console.WriteLine("Server has been started on port: " + serverInstance.port);
}
catch (Exception e)
{
Console.WriteLine("Socket error: " + e.Message);
}
while (true)
{
serverInstance.Update();
}
}
private void Update()
{
//Console.WriteLine("Call");
if (!serverStarted)
{
return;
}
foreach (ServerClient c in clients.ToList())
{
//Check if TCP is not null
if (c.tcp == null)
return;
// Is the client still connected?
if (!IsConnected(c.tcp))
{
c.tcp.Close();
clients.Remove(c);
Console.WriteLine(c.connectionId + " has disconnected.");
continue;
//Console.WriteLine("Check for connection?\n");
}
else
{
// Check for message from Client.
NetworkStream s = c.tcp.GetStream();
if (s.DataAvailable)
{
string data = c.streamReader.ReadLine();
if (data != null)
{
if (ValidateJSON(data))
{
Thread incomingData = new Thread(() => OnIncomingData(c, data));
incomingData.Start();
}
}
}
//continue;
}
}
}
public bool ValidateJSON(string s)
{
try
{
JToken.Parse(s);
return true;
}
catch (JsonReaderException ex)
{
Trace.WriteLine(ex);
return false;
}
}
private void OnIncomingData(ServerClient c, string data)
{
dynamic json = JsonConvert.DeserializeObject(data);
string header = json.header;
//Console.WriteLine("HEADER ID:" + json.header);
string connId = json.connectionId;
int.TryParse(connId, out int connectionId);
int characterId = 0;
Dictionary<string, string> receivedData = new Dictionary<string, string>();
if (json.data != null)
{
receivedData = json.data.ToObject<Dictionary<string, string>>();
}
if (json.data["characterId"] != null)
{
characterId = json.data["characterId"];
}
string prefix = header.Substring(0, 2);
if (prefix != "1x")
{
Console.WriteLine("Unknown packet: " + data + "\n");
}
else
{
string HeaderPacket = header.Substring(2);
switch (HeaderPacket)
{
default:
Console.WriteLine("Unknown packet: " + data + "\n");
break;
case "004":
Console.WriteLine("Test Packet"); ;
break;
}
}
//Broadcast(null, data, clients);
//Console.WriteLine(c.clientName + " has sent the following message :" + data);
}
public bool IsConnected(TcpClient c)
{
try
{
if (c != null && c.Client != null && c.Client.Connected)
{
if (c.Client.Poll(0, SelectMode.SelectRead))
{
return !(c.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
}
return true;
}
else
{
return false;
}
}
catch
{
return false;
}
}
private void StartListening()
{
server.BeginAcceptTcpClient(OnConnection, server);
}
private void OnConnection(IAsyncResult ar)
{
connectionIncrementor++;
TcpListener listener = (TcpListener)ar.AsyncState;
clients.Add(new ServerClient(listener.EndAcceptTcpClient(ar)));
clients[clients.Count - 1].connectionId = connectionIncrementor;
StartListening();
//Send a message to everyone, say someone has connected!
Dictionary<string, object> SendDataBroadcast = new Dictionary<string, object>();
SendDataBroadcast.Add("connectionId", clients[clients.Count - 1].connectionId);
Broadcast("001", SendDataBroadcast, clients[clients.Count - 1].connectionId);
Console.WriteLine(clients[clients.Count - 1].connectionId + " has connected.");
}
public void Broadcast(string header, Dictionary<string, object> data, int cnnId = 0)
{
string jsonData = JsonConvert.SerializeObject(data, Formatting.Indented);
foreach (ServerClient c in clients)
{
try
{
if (header == null)
{
header = "000";
}
JsonData SendData = new JsonData();
SendData.header = "0x" + header;
SendData.data = JObject.Parse(jsonData);
SendData.connectionId = cnnId;
string JSonData = JsonConvert.SerializeObject(SendData);
//Console.WriteLine("SENDING: " + JSonData);
c.streamWriter.WriteLine(JSonData);
c.streamWriter.Flush();
}
catch (Exception e)
{
Console.WriteLine("Write error : " + e.Message + " to client " + c.connectionId);
}
}
}
public void Send(string header, Dictionary<string, object> data, int cnnId)
{
string jsonData = JsonConvert.SerializeObject(data, Formatting.Indented);
foreach (ServerClient c in clients.ToList())
{
if (c.connectionId == cnnId)
{
try
{
//Console.WriteLine("Sending...");
if (header == null)
{
header = "000";
}
JsonData SendData = new JsonData();
SendData.header = "0x" + header;
SendData.data = JObject.Parse(jsonData);
SendData.connectionId = cnnId;
string JSonData = JsonConvert.SerializeObject(SendData);
c.streamWriter.WriteLine(JSonData);
c.streamWriter.Flush();
//Console.WriteLine("Trying to send data to connection id: " + cnnId + " data:" + sendData);
}
catch (Exception e)
{
Console.WriteLine("Write error : " + e.Message + " to client " + c.connectionId);
}
}
}
}
}
public class ServerClient
{
public TcpClient tcp;
public StreamReader streamReader;
public StreamWriter streamWriter;
public int accountId;
public int connectionId;
public ServerClient(TcpClient clientSocket)
{
tcp = clientSocket;
streamReader = new StreamReader(tcp.GetStream(), false);
streamWriter = new StreamWriter(tcp.GetStream());
clientSocket.NoDelay = true;
}
}
The TCP server works. However I am really not sure if this is the best approach I can take.
Have I made the multi-threading well ? Probably not. I would like to receive advices where i can make it better.
Do I need to create a new thread on every OnIncomingData ?
Do I need to create new thread on every Send and Broadcast ?
Very often I receive error here foreach (ServerClient c in clients.ToList()). What can be the cause of it ?
What parts of the client is good to be multithreaded also aka the listening function for incoming data or the sending functions?
All advices are most welcome!
I wrote code for an OP last year that was a TCP Server and wrote to a SQL Server. I modified that code a few minutes ago to make it more general. The changes are not tested but original code worked very well. I used Asynchronous Send and Receive. I also used a fifo to send messages from the transport layer to the application layer. See code below
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Data;
using System.Data.SqlClient;
using System.Timers;
using System.Threading;
namespace TCP_Server
{
public class StateObject
{
public long connectionNumber = -1;
public Socket workSocket { get; set; }
public byte[] buffer { get; set; }
public int fifoCount { get; set; }
}
public enum PROCESS_STATE
{
ACCEPT,
READ,
PROCESS,
UNPACK
}
public enum UNPACK_STATUS
{
ERROR,
NOT_ENOUGH_BYTES,
BAD_CRC,
GOOD_MESSAGE,
DEFAULT
}
public enum PROTOCOL_NUMBER
{
LOGIN_MESSAGE,
NONE
}
class Program
{
const string IP = "127.0.0.1";
const int PORT = 8841;
const Boolean test = true;
static void Main(string[] args)
{
Server server = new Server(IP, PORT, test);
Console.WriteLine("Connection Ended");
}
}
public class Server
{
const int BUFFER_SIZE = 1024;
const string CONNECT_STRING = #"Data Source=.\SQLEXPRESS;Initial Catalog=MyDataTable;Integrated Security=SSPI;";
const string LOGIN_INSERT_COMMMAND_TEXT = "use MyTable INSERT INTO Login (TerminalID,Date) VALUES(#TerminalID,#Date)";
const string LOCATION_INSERT_COMMMAND_TEXT = "INSERT INTO MyTable (CurrTime, Message)" +
"VALUES (#CurrTime, #Message)";
static SqlConnection conn = null;
static SqlCommand cmdLogin = null;
static SqlCommand cmdLocation = null;
static long connectionNumber = 0;
//mapping of connection number to StateObject
static Dictionary<long, KeyValuePair<List<byte>, StateObject>> connectionDict = new Dictionary<long, KeyValuePair<List<byte>, StateObject>>();
//fifo contains list of connections number wait with receive data
public static List<long> fifo = new List<long>();
public static AutoResetEvent allDone = new AutoResetEvent(false);
public static AutoResetEvent acceptDone = new AutoResetEvent(false);
public enum DATABASE_MESSAGE_TYPE
{
LOGIN,
LOCATION
}
public class WriteDBMessage
{
public DATABASE_MESSAGE_TYPE message { get; set; }
}
public class WriteDBMessageLogin : WriteDBMessage
{
public DateTime date { get; set; }
public string message { get; set; }
}
public class WriteDBMessageLocation : WriteDBMessage
{
public DateTime currTime { get; set; }
public byte[] message { get; set; }
}
public static class WriteDBAsync
{
public enum Mode
{
READ,
WRITE
}
public static List<WriteDBMessage> fifo = new List<WriteDBMessage>();
public static System.Timers.Timer timer = null;
public static void WriteDatabase()
{
timer = new System.Timers.Timer(1000);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
public static WriteDBMessage ReadWriteFifo(Mode mode, WriteDBMessage message)
{
Object thisLock2 = new Object();
lock (thisLock2)
{
switch (mode)
{
case Mode.READ:
if (fifo.Count > 0)
{
message = fifo[0];
fifo.RemoveAt(0);
}
break;
case Mode.WRITE:
fifo.Add(message);
break;
}
}
return message;
}
static void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
timer.Enabled = false;
WriteDBMessage row = null;
int rowsAdded = 0;
uint number = 0;
try
{
while ((row = ReadWriteFifo(Mode.READ, null)) != null)
{
switch (row.message)
{
case DATABASE_MESSAGE_TYPE.LOGIN:
cmdLogin.Parameters["#Date"].Value = ((WriteDBMessageLogin)row).date;
rowsAdded = cmdLogin.ExecuteNonQuery();
break;
}
}
}
catch (Exception ex)
{
//Console.WriteLine("Error : '{0}'", ex.Message);
}
timer.Enabled = true;
}
}
public Server(string IP, int port, Boolean test)
{
try
{
conn = new SqlConnection(CONNECT_STRING);
conn.Open();
cmdLogin = new SqlCommand(LOGIN_INSERT_COMMMAND_TEXT, conn);
cmdLogin.Parameters.Add("#TerminalID", SqlDbType.NVarChar, 8);
cmdLogin.Parameters.Add("#Date", SqlDbType.DateTime);
cmdLocation = new SqlCommand(LOCATION_INSERT_COMMMAND_TEXT, conn);
cmdLocation.Parameters.Add("#IMEI", SqlDbType.NVarChar, 50);
cmdLocation.Parameters.Add("#TrackTime", SqlDbType.DateTime);
cmdLocation.Parameters.Add("#currTime", SqlDbType.DateTime);
cmdLocation.Parameters.Add("#Longitude", SqlDbType.NChar, 50);
cmdLocation.Parameters.Add("#Lattitude", SqlDbType.NVarChar, 50);
cmdLocation.Parameters.Add("#speed", SqlDbType.Float);
}
catch (Exception ex)
{
Console.WriteLine("Error : '{0}'", ex.Message);
//Console.ReadLine();
return;
}
try
{
//initialize the timer for writing to database.
WriteDBAsync.WriteDatabase();
StartListening(IP, port, test);
// Open 2nd listener to simulate two devices, Only for testing
//StartListening(IP, port + 1, test);
ProcessMessages();
}
catch (Exception ex)
{
Console.WriteLine("Error : '{0}'", ex.Message);
//Console.ReadLine();
return;
}
}
public void StartListening(string IP, int port, Boolean test)
{
try
{
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(IP); //Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
//IPAddress local = IPAddress.Parse(IP);
IPEndPoint localEndPoint = null;
if (test)
{
localEndPoint = new IPEndPoint(IPAddress.Any, port);
}
else
{
localEndPoint = new IPEndPoint(ipAddress, port);
}
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
allDone.Reset();
acceptDone.Reset();
listener.Bind(localEndPoint);
listener.Listen(100);
//login code, wait for 1st message
Console.WriteLine("Wait 5 seconds for login message");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
public void ProcessMessages()
{
UInt16 sendCRC = 0;
DateTime date;
int year = 0;
int month = 0;
int day = 0;
int hour = 0;
int minute = 0;
int second = 0;
KeyValuePair<List<byte>, StateObject> byteState;
KeyValuePair<UNPACK_STATUS, byte[]> status;
byte[] receiveMessage = null;
StateObject state = null;
byte[] serialNumber = null;
byte[] serverFlagBit = null;
byte[] stringArray = null;
string stringMessage = "";
byte lengthOfCommand = 0;
PROTOCOL_NUMBER protocolNumber = PROTOCOL_NUMBER.NONE;
try
{
Boolean firstMessage = true;
acceptDone.Set();
//loop forever
while (true)
{
allDone.WaitOne();
//read fifo until empty
while (true)
{
//read one connection until buffer doesn't contain any more packets
byteState = ReadWrite(PROCESS_STATE.PROCESS, null, null, -1);
if (byteState.Value.fifoCount == -1) break;
state = byteState.Value;
while (true)
{
status = Unpack(byteState);
if (status.Key == UNPACK_STATUS.NOT_ENOUGH_BYTES)
break;
if (status.Key == UNPACK_STATUS.ERROR)
{
Console.WriteLine("Error : Bad Receive Message, Data");
break;
}
//message is 2 start bytes + 1 byte (message length) + 1 byte message length + 2 end bytes
receiveMessage = status.Value;
int messageLength = receiveMessage[2];
Console.WriteLine("Status : '{0}', Receive Message : '{1}'", status.Key == UNPACK_STATUS.GOOD_MESSAGE ? "Good" : "Bad", BytesToString(receiveMessage.Take(messageLength + 5).ToArray()));
if (status.Key != UNPACK_STATUS.GOOD_MESSAGE)
{
break;
}
else
{
if (firstMessage)
{
if (receiveMessage[3] != 0x01)
{
Console.WriteLine("Error : Expected Login Message : '{0}'", BytesToString(receiveMessage));
break;
}
firstMessage = false;
}
//skip start bytes, message length. then go back 4 bytes (CRC and serial number)
serialNumber = receiveMessage.Skip(2 + 1 + messageLength - 4).Take(2).ToArray();
protocolNumber = (PROTOCOL_NUMBER)receiveMessage[3];
Console.WriteLine("Protocol Number : '{0}'", protocolNumber.ToString());
switch (protocolNumber)
{
case PROTOCOL_NUMBER.LOGIN_MESSAGE:
break;
} //end switch
}// End if
} //end while
}//end while fifo > 0
allDone.Reset();
}//end while true
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
static string BytesToString(byte[] bytes)
{
return string.Join("", bytes.Select(x => x.ToString("X2")));
}
static KeyValuePair<UNPACK_STATUS, byte[]> Unpack(KeyValuePair<List<byte>, StateObject> bitState)
{
List<byte> working_buffer = bitState.Key;
//return null indicates an error
if (working_buffer.Count() < 3) return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.NOT_ENOUGH_BYTES, null);
int len = working_buffer[2];
if (working_buffer.Count < len + 5) return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.NOT_ENOUGH_BYTES, null);
// check start and end bytes
// remove message fro workig buffer and dictionary
KeyValuePair<List<byte>, StateObject> byteState = ReadWrite(PROCESS_STATE.UNPACK, null, null, bitState.Value.connectionNumber);
if (byteState.Key.Count == 0) return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.ERROR, null);
List<byte> packet = byteState.Key;
//crc test
byte[] crc = packet.Skip(len + 1).Take(2).ToArray();
ushort crcShort = (ushort)((crc[0] << 8) | crc[1]);
//skip start bytes, crc, and end bytes
return new KeyValuePair<UNPACK_STATUS, byte[]>(UNPACK_STATUS.GOOD_MESSAGE, packet.ToArray());
}
static KeyValuePair<List<byte>, StateObject> ReadWrite(PROCESS_STATE ps, Socket handler, IAsyncResult ar, long unpackConnectionNumber)
{
KeyValuePair<List<byte>, StateObject> byteState = new KeyValuePair<List<byte>, StateObject>(); ;
StateObject stateObject = null;
int bytesRead = -1;
int workingBufferLen = 0;
List<byte> working_buffer = null;
byte[] buffer = null;
Object thisLock1 = new Object();
lock (thisLock1)
{
switch (ps)
{
case PROCESS_STATE.ACCEPT:
acceptDone.WaitOne();
acceptDone.Reset();
stateObject = new StateObject();
stateObject.buffer = new byte[BUFFER_SIZE];
connectionDict.Add(connectionNumber, new KeyValuePair<List<byte>, StateObject>(new List<byte>(), stateObject));
stateObject.connectionNumber = connectionNumber++;
stateObject.workSocket = handler;
byteState = new KeyValuePair<List<byte>, StateObject>(null, stateObject);
acceptDone.Set();
break;
case PROCESS_STATE.READ:
//catch when client disconnects
//wait if accept is being called
//acceptDone.WaitOne();
try
{
stateObject = ar.AsyncState as StateObject;
// Read data from the client socket.
bytesRead = stateObject.workSocket.EndReceive(ar);
if (bytesRead > 0)
{
byteState = connectionDict[stateObject.connectionNumber];
buffer = new byte[bytesRead];
Array.Copy(byteState.Value.buffer, buffer, bytesRead);
byteState.Key.AddRange(buffer);
}
//only put one instance of connection number into fifo
if (!fifo.Contains(byteState.Value.connectionNumber))
{
fifo.Add(byteState.Value.connectionNumber);
}
}
catch (Exception ex)
{
//will get here if client disconnects
fifo.RemoveAll(x => x == byteState.Value.connectionNumber);
connectionDict.Remove(byteState.Value.connectionNumber);
byteState = new KeyValuePair<List<byte>, StateObject>(new List<byte>(), null);
}
break;
case PROCESS_STATE.PROCESS:
if (fifo.Count > 0)
{
//get message from working buffer
//unpack will later delete message
//remove connection number from fifo
// the list in the key in known as the working buffer
byteState = new KeyValuePair<List<byte>, StateObject>(connectionDict[fifo[0]].Key, connectionDict[fifo[0]].Value);
fifo.RemoveAt(0);
//put a valid value in fifoCount so -1 below can be detected.
byteState.Value.fifoCount = fifo.Count;
}
else
{
//getting here is normal when there is no more work to be performed
//set fifocount to zero so rest of code know fifo was empty so code waits for next receive message
byteState = new KeyValuePair<List<byte>, StateObject>(null, new StateObject() { fifoCount = -1 });
}
break;
case PROCESS_STATE.UNPACK:
try
{
working_buffer = connectionDict[unpackConnectionNumber].Key;
workingBufferLen = working_buffer[2];
if ((working_buffer[0] != 0x78) && (working_buffer[1] != 0x78) && (working_buffer[workingBufferLen + 3] != 0x0D) && (working_buffer[workingBufferLen + 4] != 0x0A))
{
working_buffer.Clear();
return new KeyValuePair<List<byte>, StateObject>(new List<byte>(), null);
}
List<byte> packet = working_buffer.GetRange(0, workingBufferLen + 5);
working_buffer.RemoveRange(0, workingBufferLen + 5);
byteState = new KeyValuePair<List<byte>, StateObject>(packet, null);
}
catch (Exception ex)
{
int testPoint = 0;
}
break;
}// end switch
}
return byteState;
}
public static void AcceptCallback(IAsyncResult ar)
{
try
{
// Get the socket that handles the client request.
// Retrieve the state object and the handler socket
// from the asynchronous state object.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = ReadWrite(PROCESS_STATE.ACCEPT, handler, ar, -1).Value;
handler.BeginReceive(state.buffer, 0, BUFFER_SIZE, 0,
new AsyncCallback(ReadCallback), state);
}
catch (Exception ex)
{
int myerror = -1;
}
}
public static void ReadCallback(IAsyncResult ar)
{
try
{
StateObject state = ar.AsyncState as StateObject;
Socket handler = state.workSocket;
// Read data from the client socket.
KeyValuePair<List<byte>, StateObject> byteState = ReadWrite(PROCESS_STATE.READ, handler, ar, -1);
if (byteState.Value != null)
{
allDone.Set();
handler.BeginReceive(state.buffer, 0, BUFFER_SIZE, 0,
new AsyncCallback(ReadCallback), state);
}
else
{
int testPoint = 0;
}
}
catch (Exception ex)
{
int myerror = -1;
}
// Signal the main thread to continue.
allDone.Set();
}
}
}
I'm trying to implement wrapper class which will simply connect to TCP server and wait for data. Once data submitted from server - I will receive this data and pass it onto subscribers of my class.
All this works. Now I want to add external functionality to "reset" this class on a timer (force reconnect every so often) to keep connection alive. My idea is that Init method can be called as many times as needed to get socket reset. However, I do get various exceptions with this.
Class code:
namespace Ditat.GateControl.Service.InputListener
{
using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class BaseTCPSocketListener : IInputListener
{
#region Events/Properties
public event EventHandler<Exception> OnError;
public event EventHandler<string> OnDataReceived;
private string host;
private int port;
private int delayToClearBufferSeconds = 5;
private TcpClient client;
private readonly byte[] buffer = new byte[1024];
/// <summary>
/// Will accumulate data as it's received
/// </summary>
private string DataBuffer { get; set; }
/// <summary>
/// Store time of last data receipt. Need this in order to purge data after delay
/// </summary>
private DateTime LastDataReceivedOn { get; set; }
#endregion
public BaseTCPSocketListener()
{
// Preset all entries
this.LastDataReceivedOn = DateTime.UtcNow;
this.DataBuffer = string.Empty;
}
public void Init(string config)
{
// Parse info
var bits = config.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
this.host = bits[0];
var hostBytes = this.host.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var hostIp = new IPAddress(new[] { byte.Parse(hostBytes[0]), byte.Parse(hostBytes[1]), byte.Parse(hostBytes[2]), byte.Parse(hostBytes[3]) });
this.port = int.Parse(bits[1]);
this.delayToClearBufferSeconds = int.Parse(bits[2]);
// Close open client
if (this.client?.Client != null)
{
this.client.Client.Disconnect(true);
this.client = null;
}
// Connect to client
this.client = new TcpClient();
if (!this.client.ConnectAsync(hostIp, this.port).Wait(2500))
throw new Exception($"Failed to connect to {this.host}:{this.port} in allotted time");
this.EstablishReceiver();
}
protected void DataReceived(IAsyncResult result)
{
// End the data receiving that the socket has done and get the number of bytes read.
var bytesCount = 0;
try
{
bytesCount = this.client.Client.EndReceive(result);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.DataReceived)));
this.RaiseOnErrorToClient(ex);
}
// No data received, establish receiver and return
if (bytesCount == 0)
{
this.EstablishReceiver();
return;
}
// Convert the data we have to a string.
this.DataBuffer += Encoding.UTF8.GetString(this.buffer, 0, bytesCount);
// Record last time data received
this.LastDataReceivedOn = DateTime.UtcNow;
this.RaiseOnDataReceivedToClient(this.DataBuffer);
this.DataBuffer = string.Empty;
this.EstablishReceiver();
}
private void EstablishReceiver()
{
try
{
// Set up again to get the next chunk of data.
this.client.Client.BeginReceive(this.buffer, 0, this.buffer.Length, SocketFlags.None, this.DataReceived, this.buffer);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.EstablishReceiver)));
this.RaiseOnErrorToClient(ex);
}
}
private void RaiseOnErrorToClient(Exception ex)
{
if (this.OnError == null) return;
foreach (Delegate d in this.OnError.GetInvocationList())
{
var syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(this, ex);
}
else
{
syncer.BeginInvoke(d, new object[] { this, ex });
}
}
}
private void RaiseOnDataReceivedToClient(string data)
{
if (this.OnDataReceived == null) return;
foreach (Delegate d in this.OnDataReceived.GetInvocationList())
{
var syncer = d.Target as ISynchronizeInvoke;
if (syncer == null)
{
d.DynamicInvoke(this, data);
}
else
{
syncer.BeginInvoke(d, new object[] { this, data });
}
}
}
}
}
Client code (under button click on form)
private void ListenBaseButton_Click(object sender, EventArgs e)
{
if (this.bsl == null)
{
this.bsl = new BaseTCPSocketListener();
this.bsl.OnDataReceived += delegate (object o, string s)
{
this.DataTextBox.Text += $"Base: {DateTime.Now} - {s}" + Environment.NewLine;
};
this.bsl.OnError += delegate (object o, Exception x)
{
this.DataTextBox.Text += $"Base TCP receiver error: {DateTime.Now} - {x.Message}" + Environment.NewLine;
};
}
try
{
this.bsl.Init("192.168.33.70|10001|10");
this.DataTextBox.Text += "BEGIN RECEIVING BSL data --------------------------" + Environment.NewLine;
}
catch (Exception exception)
{
this.DataTextBox.Text += $"ERROR CONNECTING TO BSL ------------{exception.Message}" + Environment.NewLine;
}
}
Exceptions I get. First exception when button clicked 2nd time in from handler in DataReceived
The IAsyncResult object was not returned from the corresponding
asynchronous method on this class.
On following clicks I get exception from handler in EstablishReceiver
A request to send or receive data was disallowed because the socket is
not connected and (when sending on a datagram socket using a sendto
call) no address was supplied
How do I properly ensure socket closed and re-opened?
The IAsyncResult object was not returned from the corresponding
asynchronous method on this class.
This is a well known problem that happens when data callback (DataReceived()) is called for previous socket. In this case you will call Socket.EndReceive() with incorrect instance of IAsyncResult which throws above exception.
Asynchronous Client Socket Example contains possible workaround for this problem: store socket on which BeginReceive() was called in state object which is then passed to DataReceived callback:
StateObject class
public class StateObject
{
public Socket Socket { get; set; }
public byte[] Buffer { get; } = new byte[1024];
public StateObject(Socket socket)
{
Socket = socket;
}
}
EstablishReceiver() method:
private void EstablishReceiver()
{
try
{
var state = new StateObject(client.Client);
// Set up again to get the next chunk of data.
this.client.Client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, this.DataReceived, state);
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.EstablishReceiver)));
this.RaiseOnErrorToClient(ex);
}
}
DataReceived() method:
protected void DataReceived(IAsyncResult result)
{
var state = (StateObject) result.AsyncState;
// End the data receiving that the socket has done and get the number of bytes read.
var bytesCount = 0;
try
{
SocketError errorCode;
bytesCount = state.Socket.EndReceive(result, out errorCode);
if (errorCode != SocketError.Success)
{
bytesCount = 0;
}
}
catch (Exception ex)
{
this.RaiseOnErrorToClient(new Exception(nameof(this.DataReceived)));
this.RaiseOnErrorToClient(ex);
}
if (bytesCount > 0)
{
// Convert the data we have to a string.
this.DataBuffer += Encoding.UTF8.GetString(state.Buffer, 0, bytesCount);
// Record last time data received
this.LastDataReceivedOn = DateTime.UtcNow;
this.RaiseOnDataReceivedToClient(this.DataBuffer);
this.DataBuffer = string.Empty;
this.EstablishReceiver();
}
}
A request to send or receive data was disallowed because the socket is
not connected and (when sending on a datagram socket using a sendto
call) no address was supplied
Above DataReceived() method also contains the fix for the second exception. Exception is caused by calling BeginReceive() (from EstablishReceiver()) on disconnected socket. You should not call BeginReceive() on a socket if previous read brought 0 bytes.
First of all, you're closing the socket being held by the TcpClient, but not disposing the client itself. Try the following:
// Close open client
this.client?.Close(); // Disposes and releases resources
this.client = null;
The issue is that DataReceived will be called when you close the client. You simply need to identify to the method that it should not do anything because you have deliberately ended the process. You could just add a bool:
private bool ignoreCallback;
public void Init(string config)
{
// Parse info
var bits = config.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
this.host = bits[0];
var hostBytes = this.host.Split(new[] { '.' }, StringSplitOptions.RemoveEmptyEntries);
var hostIp = new IPAddress(new[] { byte.Parse(hostBytes[0]), byte.Parse(hostBytes[1]), byte.Parse(hostBytes[2]), byte.Parse(hostBytes[3]) });
this.port = int.Parse(bits[1]);
this.delayToClearBufferSeconds = int.Parse(bits[2]);
// Close open client
if (this.client?.Client != null)
{
ignoreCallback = true;
this.client.Client.Disconnect(true);
this.client = null;
}
// Connect to client
this.client = new TcpClient();
if (!this.client.ConnectAsync(hostIp, this.port).Wait(2500))
throw new Exception($"Failed to connect to {this.host}:{this.port} in allotted time");
this.EstablishReceiver();
}
protected void DataReceived(IAsyncResult result)
{
if (ignoreCallback)
{
ignoreCallback = false;
return;
}
...
I am trying to make socket networking (using "BufferedOutputStream" on the Java part and "NetworkStream" on C# part) between a Unity3D application and Java (Jason) application. These two modules should communicate between each other. Here is the java part of the code:
public static void SendExecuteAction(String ag, Structure structure, Object tempObject, ClassEnv classEnv)
{
if(!agentThreadList.containsKey(ag))
{
AgentServiceThread ast = new AgentServiceThread(s, agentThreadList.size() - 1, ag, structure, tempObject, classEnv);
agentThreadList.put(ag, ast);
if(ast.getState() != Thread.State.BLOCKED)
ast.start();
try {
ast.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
{
agentThreadList.get(ag).start();
}
}
}
class AgentServiceThread extends Thread
{
Socket agentSocket;
int agentID = -1;
String agent;
Structure structure;
Object blockObject;
byte[] ba;
ClassEnv classEnv;
InputStream is;
BufferedOutputStream bos;
ToByteConvertHelper toBytes;
FromByteConvertHelper fromBytes;
AgentServiceThread(Socket s, int i, String ag, Structure structure, Object object, ClassEnv classEnv)
{
agentSocket = s;
agentID = i;
agent = ag;
this.structure = structure;
blockObject = object;
this.classEnv = classEnv;
try
{
toBytes = new ToByteConvertHelper();
fromBytes = new FromByteConvertHelper();
is = agentSocket.getInputStream();
bos = new BufferedOutputStream(agentSocket.getOutputStream());
}
catch (IOException e)
{
e.printStackTrace();
}
}
public void run()
{
VCActionRequest vcar;
List<String> termList = new ArrayList<String>();
List<Term> structureTermList = structure.getTerms();
for(int i = 0; i < structureTermList.size(); i++)
{
termList.add(structureTermList.get(i).toString());
}
vcar = new VCActionRequest(agent, structure.getFunctor(), (ArrayList<String>)termList);
vcar.requestEnum = RequestEnum.ExecuteActions.index();
System.out.println("agent: " + agent + " action: " + structure.getFunctor());
ba = toBytes.toByte(vcar);
try
{
bos.write(ba);
bos.flush();
}
catch (IOException e)
{
e.printStackTrace();
}
synchronized(blockObject)
{
try
{
ba = new byte[1000];
is.read(ba, 0, 1000);
#SuppressWarnings("unchecked")
ArrayList<VCPerception> result = (ArrayList<VCPerception>)fromBytes.fromByte(ba);
classEnv.UpdatePercepts(result);
}
catch (IOException e1)
{
System.out.println(e1.toString());
e1.printStackTrace();
}
}
}
}
"SendExecuteAction" method is called by another method and that method is invoked automatically in its interval by Jason architecture. The problem is, when I try to get the packages from inside Unity3D application, it seems that I miss some of the packages. Actually I get the first package from Unity but not the others. Should I use some different kind of communication? I need to read every message async. Here is the C# code that is used for reading data from network stream.
private IEnumerator CommunicateWithMAS()
{
while (!_ns.DataAvailable)
{
yield return null;
}
byte[] ba = new byte[1000];
AgentServiceThread ast = new AgentServiceThread(_tc, -1, this, ba);
Thread thread = new Thread(new ThreadStart(ast.Communicate));
thread.Start();
StartCoroutine(CommunicateWithMAS());
}
public class AgentServiceThread
{
VCSocketCommScript socketCommScript;
TcpClient client;
int id;
string agentName;
NetworkStream ns;
StreamWriter sw;
StreamReader sr;
string informationString;
string responseString;
FromByteConvertHelper fromBytes;
byte[] ba;
int byteArrayLength = 1000;
public AgentServiceThread(TcpClient client, int id, VCSocketCommScript vcscs, byte[] ba)
{
this.client = client;
this.id = id;
socketCommScript = vcscs;
//this.ba = ba;
fromBytes = new FromByteConvertHelper();
ns = client.GetStream();
}
public void Communicate()
{
byte[] ba = new byte[byteArrayLength];
Debug.Log(ns.DataAvailable);
ns.Read(ba, 0, byteArrayLength);
//Debug.Log(ba.Length);
VCActionRequest action = (VCActionRequest)fromBytes.fromByte(ba, 0, typeof(VCActionRequest));
Debug.Log(action.agentName + " " + action.functor);
socketCommScript.AddAction(action);
ns.Flush();
}
}
I am currently tyring to create a Multi threading and async tcp server that implements the Tcpl listener
Current the server is working as intended as i am able to send data to the server an transmit data to the client with out any problems
However after i have sent data to the server and then sent data back to the client, when the client sends data back to the server again the server is unabe to pick up the data
I have tried for days to find an answer to this problem however with no luck
Here is the code that i am currently using in the server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows.Forms;
using System.IO;
namespace MyTcpAsyncClass
{
public class StateObject
{
public TcpClient MyTcpClient = null;
public NetworkStream MyNetworkStream = null;
public const int MyBufferSize = 1024;
public byte[] MyBuffer = new byte[MyBufferSize];
public string RequestString = "";
public StringBuilder MyStringBuilder = new StringBuilder();
char[] RequestChars; // Char array of Request
const char STX = (char)0x02; // Start Character
const char FTX = (char)0x03; // Finish Character
public void Dispose()
{
try
{
MyTcpClient.Close();
MyNetworkStream.Close();
MyNetworkStream.Dispose();
}
catch (Exception ex)
{
MessageBox.Show("Message:\n" + ex.Message + "\n\nStacktrace:\n" + ex.StackTrace);
}
}
}
public static class AsyncServerFunctions
{
private static int mPort = 0;
private static ManualResetEvent MyManualResetEvent = new ManualResetEvent(false);
public static void StartListening()
{
//Catch to Tcp Client Connection
try
{
//Get the database connection
//MyReaderWriterLockSlim.EnterReadLock();
LoadSettings();
//MyReaderWriterLockSlim.ExitReadLock();
TcpListener MyTcpListener = new TcpListener(IPAddress.Any, mPort);
MyTcpListener.Start();
while (true)
{
//Set the event to nonsignaled state
MyManualResetEvent.Reset();
//Start an asynchronous TcpListener to listen for a connection
MyTcpListener.BeginAcceptTcpClient(AcceptTcpClientCallback, MyTcpListener);
//Wait until a connection is made before continuing
MyManualResetEvent.WaitOne();
}
MyTcpListener.Stop();
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
private static void AcceptTcpClientCallback(IAsyncResult result)
{
try
{
//BeginAcceptTcpClientCallback
//Signal the main thread to continue
MyManualResetEvent.Set();
//Get the TcpClientNetworkStream:
TcpListener MyTcpListener = (TcpListener)result.AsyncState;
//Finish Async Get Client Process
TcpClient MyTcpClient = MyTcpListener.EndAcceptTcpClient(result);
StateObject MyStateObject = new StateObject();
MyStateObject.MyTcpClient = MyTcpClient;
MyStateObject.MyNetworkStream = MyTcpClient.GetStream();
//Begin Async read from the NetworkStream
MyStateObject.MyNetworkStream.BeginRead(MyStateObject.MyBuffer, 0, StateObject.MyBufferSize, new AsyncCallback(BeginReadCallback), MyStateObject);
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
private static void BeginReadCallback(IAsyncResult result)
{
StateObject MyStateObject = (StateObject)result.AsyncState;
NetworkStream MyNetworkStream = MyStateObject.MyNetworkStream;
string MyRequestString = "";
try
{
//Get Request Data here
if (MyStateObject.MyBuffer.Length > 0)
{
//Store the data recived
MyStateObject.MyStringBuilder.Clear();
MyStateObject.MyStringBuilder.Append(Encoding.ASCII.GetString(MyStateObject.MyBuffer));
//Get the stored Request string
MyRequestString = MyStateObject.MyStringBuilder.ToString();
//Record the string recived
DatabaseFunctions.AddMessageLog("String Recived (BeginReadCallback): " + MyRequestString);
//Remove the first and last character
MyRequestString = CleanString(MyRequestString);
//Record the Request String
DatabaseFunctions.AddMessageLog("Request String Recived:" + MyRequestString);
//Get the Message Identifier
string MessageIdentifier = "";
MessageIdentifier = MyRequestString.Substring(0, 2);
switch (MessageIdentifier)
{
case "value":
SendResponse(MyStateObject, StartUp(MessageIdentifier, MyRequestString));
SendResponse(MyStateObject, SendTransactionStart(MessageIdentifier, MyAmount));
GetResponse(MyStateObject);
break;
default:
//***Default Case***
SendResponse(MyStateObject, DefaultCase(MyRequestString));
break;
}
//Dispose of the connection
MyStateObject.Dispose();
}
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
try
{
MyStateObject.Dispose();
}
catch
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
}
private static void SendResponse(StateObject pMyStateObject, string pResponseString)
{
try
{
//Send a response to the client
//Get bytes from string sent
byte[] MyResponseBytes = Encoding.ASCII.GetBytes(pResponseString);
//Get the network stream
NetworkStream MyNetworkStream = pMyStateObject.MyNetworkStream;
//Call SendResponseCallback
MyNetworkStream.BeginWrite(MyResponseBytes, 0, MyResponseBytes.Length, new AsyncCallback(SendResponseCallback), pMyStateObject);
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace);
}
}
private static void GetResponse(StateObject pStateObject)
{
//This will run a new AsyncCallback To get the response from the client
NetworkStream MyNetworkStream = pStateObject.MyNetworkStream;
pStateObject.MyBuffer = new byte[1024];
MyNetworkStream.BeginRead(pStateObject.MyBuffer, 0, pStateObject.MyBuffer.Length, new AsyncCallback(BeginReadCallback), pStateObject);
}
private static void SendResponseCallback(IAsyncResult result)
{
try
{
//End the send procedure
StateObject MyStateObject = (StateObject)result.AsyncState;
NetworkStream MyNetworkStream = MyStateObject.MyNetworkStream;
MyNetworkStream.Flush();
}
catch (Exception ex)
{
AddErrorLog(ex.Message, ex.StackTrace)
}
}
private static void ShowExceptionMessage(string pMessage, string pStacktrace)
{
MessageBox.Show("Message:\n" + pMessage + "\n\nStacktrace:\n" + pStacktrace);
}
private static void AddErrorLog(string pMessage, string pStackTrace)
{
DatabaseFunctions.AddMessageLog("Message:" + pMessage + "; Stacktrace:" + pStackTrace);
}
}
}
Thanks All
You should call BeginAcceptTcpClient in AcceptTcpClientCallback also. You don't accept any new connection after the first one.
In your BeginReadCallback function you dispose off the object you have used to invoke BeginRead try running the code without dispose function and you are only calling the GetRespone function in switch condition, try calling BeginRead in your BeginReadCallback function.