C# Tcp Async Programming - c#

I try to learn and wrote some code for TCP connection.
This is my Server Class :
using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
namespace Tcp
{
public class Server
{
#region Constructor
public Server()
{
}
#endregion
#region Field
//Server Socket
public Socket SrvSocket;
//Server Port
private int _socketPort = 8080;
byte[] byteData = new byte[1024];
#endregion
#region Properties
/// <summary>
/// Socket Port Int Value
/// </summary>
public int SocketPort
{
get
{
return _socketPort;
}
set
{
_socketPort = value;
}
}
#endregion
#region Method
public void Close()
{
SrvSocket.Shutdown(SocketShutdown.Both);
}
/// <summary>
/// Open TCP Socket
/// </summary>
public void Connect()
{
try
{
SrvSocket = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any,_socketPort);
SrvSocket.Bind(ipEndPoint);
SrvSocket.Listen(4);
SrvSocket.BeginAccept(new AsyncCallback(OnAccept), null); //TODO : تست کنم State را یک بار سوکت بگذارم یکبار State خودم
}
catch (SocketException ex)
{
MessageBox.Show(#"Socket Exception trown : " + ex.Message);
}
catch (TimeoutException ex)
{
MessageBox.Show(#"Timeout Exception trown : " + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(#"Exception trown : " + ex.Message);
}
}
public void OnAccept(IAsyncResult ar)
{
try
{
Socket ClntSocket = SrvSocket.EndAccept(ar); // روند تایید انجام شد.
SrvSocket.BeginAccept(new AsyncCallback(OnAccept), null); // ممکنه کلاینت های دیگه هم بخواند وصل بشند
//SocketState state = new SocketState(); // وضعیت پورت تنظیم میکنیم
ClntSocket.BeginReceive(byteData, 0, byteData.Length
, SocketFlags.None,new AsyncCallback(OnReceive), ClntSocket); // شروع به دریافت میکنیم
}
catch (Exception ex)
{
MessageBox.Show(#"On Accept Exception trown : " + ex.Message);
}
}
#endregion
public void OnReceive(IAsyncResult ar)
{
try
{
Socket ClntSocket = (Socket)ar.AsyncState;
int byteReades = ClntSocket.EndReceive(ar);
if (byteReades > 0)
{
var collectedData = Encoding.ASCII.GetString(byteData, 0, byteReades);
Console.WriteLine(collectedData);
}
ClntSocket.BeginReceive(byteData, 0, byteData.Length, SocketFlags.None, new AsyncCallback(OnReceive), ClntSocket);
}
catch (Exception ex)
{
MessageBox.Show(#"On receive Exception trown : " + ex.Message);
}
}
public void Send(string data)
{
//var sendData = Encoding.ASCII.GetBytes(data);
//IPEndPoint ConToSocket = new IPEndPoint(IPAddress.Parse("192.168.1.101"), 8080);
//TcpClient Client = new TcpClient(ConToSocket);
//Client.
}
public void OnSend(IAsyncResult ar)
{
}
}
public class SocketState
{
public Socket TransferSocket = null;
/// <summary>
/// Buffer Size
/// </summary>
public const int bufferSize = 1024;
/// <summary>
/// Recieved byte
/// </summary>
public byte[] buffer = new byte[bufferSize];
/// <summary>
/// Offset
/// </summary>
public int offset = 0;
}
}
First question: Why can I only connect to the server once?
I use telnet to connect server on local pc.when i open more telnet no stop all sending !
And this is my Client Class :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Windows.Forms;
namespace Tcp
{
class Client
{
Socket ClientSocket = null;
public void Connect(string RemoteIp, int RemotePort)
{
ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint RemoteSrv = new IPEndPoint(IPAddress.Parse(RemoteIp), RemotePort);
ClientSocket.BeginConnect(RemoteSrv, new AsyncCallback(OnConnect), null);
}
public void OnConnect(IAsyncResult ar)
{
try
{
ClientSocket.EndConnect(ar);
}
catch (Exception ex)
{
MessageBox.Show("Exp Thrown OnConnect : " + ex.Message);
}
}
public void Send(string str)
{
byte[] data = Encoding.ASCII.GetBytes(str);
ClientSocket.BeginSend(data,0,data.Length, SocketFlags.None, new AsyncCallback(OnSend), null);
}
public void OnSend(IAsyncResult ar)
{
try
{
ClientSocket.EndSend(ar);
}
catch (Exception ex )
{
MessageBox.Show("Exp Thrown OnSend : " + ex.Message);
}
}
}
}
When i Connect to server and see socket state in break point connected socket is not 8080 ! Is it wrong ?
And server can not return received data in Console.Writeline , Where is my issue ?
var collectedData = Encoding.ASCII.GetString(byteData, 0, byteReades);
Console.WriteLine(collectedData);
Why i can not Receive form my Client Class !
Finally i need solution to know best way to Send/Receive Communication between my computer and Device via TCP async.
Thank you.

Related

TCP async client with connection lost detection and autoreconnecting

Here is my many-years many times modified code for TCP asynchronous client.
It is able to detect connection loss (thanks to using keep alive values).
But now, I need to reconnect it to server automatically after any connection loss detection (any communication error or Disconnect() call).
It works fine with some simple SW TCP servers, when I stop them listening or disconnect my client from them. But, when I connect to some real devices and start to simulate possible errors, problems start.
For example, I disconnect client PC from network, then after some time of "reconnecting", application goes to connection state loop and hangs, specifically method OnDataReceived throws SocketException: ConnectionReset on iRx = stateObject.Socket.EndReceive(asyn); call.
As I am not adept at async code, I believe I do something very bad
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace SharpLib.Tcp
{
public enum ConnectionState
{
Connected, Disconnected
};
public delegate void ConnectionStateChangedEventHandler(object sender, ConnectionStateEventArgs args);
public class ConnectionStateEventArgs : EventArgs
{
public ConnectionState ConnectionState { get; set; }
public ConnectionStateEventArgs(ConnectionState state)
{
this.ConnectionState = state;
}
}
/// <summary>
/// Structure of received data
/// </summary>
public class StateObject
{
public byte[] DataBuffer { get; set; }
public Socket Socket { get; set; }
public StateObject(Socket socket)
{
this.DataBuffer = new byte[128];
this.Socket = socket;
}
}
/// <summary>
/// TCP client with asynchronous connecting and data receiving
/// </summary>
public class TcpAsyncClient
{
protected string address;
protected int port;
private Socket socket;
private int keepAliveTime;
private int keepAliveInterval;
private int connectTimeout;
private bool autoReconnect;
private AsyncCallback callback;
private static ManualResetEvent connectDone = new ManualResetEvent(false);
public event MessageEventHandler DataReceived = delegate { };
public event ExceptionEventHandler ExceptionCaught = delegate { };
public event ConnectionStateChangedEventHandler ConnectionStateChanged = delegate { };
public bool Connected
{
get
{
if (socket == null)
return false;
return socket.Connected;
}
}
public TcpAsyncClient(string address, int port, int keepAliveTime = 1000, int keepAliveInterval = 1000, int connectTimeout = 1000, bool autoReconnect = false)
{
this.address = address;
this.port = port;
this.keepAliveInterval = keepAliveInterval;
this.keepAliveTime = keepAliveTime;
this.connectTimeout = connectTimeout;
this.autoReconnect = autoReconnect;
ConnectionStateChanged(this, new ConnectionStateEventArgs(ConnectionState.Disconnected));
}
/// <summary>
/// Connect to tcp server - async
/// </summary>
public void Connect()
{
try
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipEnd = FindIpEndPoint(address, port);
socket.BeginConnect(ipEnd, new AsyncCallback(ConnectCallback), new StateObject(socket));
connectDone.WaitOne(500);
}
catch (SocketException ex)
{
OnError(ex);
}
}
/// <summary>
/// Connect done callback
/// </summary>
/// <param name="ar"></param>
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Complete the connection.
((StateObject)ar.AsyncState).Socket.EndConnect(ar);
// Signal that the connection has been made.
connectDone.Set();
WaitForData();
SetKeepAlive(true, Convert.ToUInt32(keepAliveTime), Convert.ToUInt32(keepAliveInterval));
ConnectionStateChanged(this, new ConnectionStateEventArgs(ConnectionState.Connected));
}
catch (SocketException ex)
{
OnError(ex);
}
}
/// <summary>
/// Disconnect from tcp server
/// </summary>
public void Disconnect()
{
try
{
// MSDN recommends to Shutdown() before Disconnect()
socket.Shutdown(SocketShutdown.Both);
socket.Disconnect(true);
}
catch { }
ConnectionStateChanged(this, new ConnectionStateEventArgs(ConnectionState.Disconnected));
if (autoReconnect)
{
Connect();
}
}
/// <summary>
/// Send string message to tcp server
/// </summary>
/// <param name="message"></param>
public void Send(string message)
{
// because of this, we can Send from client imidiately after Connect() call
DateTime start = DateTime.Now;
if (!Connected)
{
ConnectionStateChanged(this, new ConnectionStateEventArgs(ConnectionState.Disconnected));
return;
}
// make return on the end of line
message += "\r";
int sent = 0; // how many bytes is already sent
do
{
try
{
sent += socket.Send(System.Text.Encoding.UTF8.GetBytes(message), sent, message.Length - sent, SocketFlags.None);
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.WouldBlock ||
ex.SocketErrorCode == SocketError.IOPending ||
ex.SocketErrorCode == SocketError.NoBufferSpaceAvailable)
{
// socket buffer is probably full, wait and try again
Thread.Sleep(30);
}
else
{
OnError(ex);
break;
}
}
}
while (sent < message.Length);
}
/// <summary>
/// Start receiving data from tcp server
/// </summary>
public void WaitForData()
{
try
{
StateObject stateObject = new StateObject(socket);
IAsyncResult result = socket.BeginReceive(stateObject.DataBuffer, 0, 128, SocketFlags.None, new AsyncCallback(OnDataReceived), stateObject);
}
catch (SocketException ex)
{
OnError(ex);
}
}
/// <summary>
/// Data received callback
/// </summary>
/// <param name="asyn"></param>
public void OnDataReceived(IAsyncResult asyn)
{
try
{
StateObject stateObject = (StateObject)asyn.AsyncState;
if (!stateObject.Socket.Connected)
return;
int iRx = stateObject.Socket.EndReceive(asyn);
// Server probably stopped listening
if (iRx == 0)
{
Disconnect();
ConnectionStateChanged(this, new ConnectionStateEventArgs(ConnectionState.Disconnected));
return;
}
char[] chars = new char[iRx];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(stateObject.DataBuffer, 0, iRx, chars, 0);
string szData = new string(chars);
DataReceived(this, new MessageEventArgs(szData));
WaitForData();
}
catch (SocketException ex)
{
OnError(ex);
}
}
/// <summary>
/// Socket exception during connecting or communication with server
/// </summary>
/// <param name="ex"></param>
private void OnError(Exception ex)
{
ExceptionCaught(this, new ExceptionEventArgs(ex));
Disconnect();
}
/// <summary>
/// Set KeepAlive timer for socket
/// </summary>
/// <param name="on"></param>
/// <param name="time"></param>
/// <param name="interval"></param>
private void SetKeepAlive(bool on, uint time, uint interval)
{
int size = Marshal.SizeOf(new uint());
var inOptionValues = new byte[size * 3];
BitConverter.GetBytes((uint)(on ? 1 : 0)).CopyTo(inOptionValues, 0);
BitConverter.GetBytes((uint)time).CopyTo(inOptionValues, size);
BitConverter.GetBytes((uint)interval).CopyTo(inOptionValues, size * 2);
socket.IOControl(IOControlCode.KeepAliveValues, inOptionValues, null);
}
/// <summary>
/// Create ip address from known host name
/// </summary>
/// <param name="hostName"></param>
/// <param name="port"></param>
/// <returns></returns>
private IPEndPoint FindIpEndPoint(string hostName, int port)
{
var addresses = System.Net.Dns.GetHostAddresses(hostName);
if (addresses.Length == 0)
{
throw new ArgumentException(
"Unable to retrieve address from specified host name.",
"hostName"
);
}
return new IPEndPoint(addresses[0], port);
}
}
}

Socket disconnections and gracefully reconnect C#

I am building a tcp port forwarding application. The client connects to the server on a particular port and internally the request is routed in the server to a remote port and response is passed back to the client. Below is my code.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace BBGRouter
{
class Router
{
#region log4net
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
#endregion //log4net
bool isShutdown = false;
private Socket router = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public event EventHandler OnRestartNeeded;
//only one time
Thread thRouterTh;
public Router()
{
thRouterTh = new Thread(new ParameterizedThreadStart(RouterProc));
}
IPEndPoint local, remote;
public void Start(IPEndPoint local, IPEndPoint remote)
{
if (log.IsInfoEnabled) { log.Info("Listening on " + local); }
this.local = local;
this.remote = remote;
router.Bind(local);
router.Listen(10);
thRouterTh.Name = "router thread";
thRouterTh.Start();
}
void RouterProc(object obj)
{
while (!isShutdown)
{
try
{
var source = router.Accept();
if (log.IsInfoEnabled) { log.Info("Creating new session...."); }
var destination = new Router();
var state = new State(source, destination.router);
destination.Connect(remote, source);
source.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, OnDataReceive, state);
}
catch (Exception ex)
{
if (log.IsErrorEnabled) { log.Error("Exception in Router thread", ex); }
if (isShutdown) { if (log.IsInfoEnabled) { log.Info("Shutting down..."); } }
}
}
}
public void Join()
{
if (thRouterTh != null)
thRouterTh.Join();
}
private void StopAndFireRestart(EventArgs e)
{
Stop();
log.Info("Stopped router");
EventHandler handler = OnRestartNeeded;
if (handler != null)
{
log.Info("Firing the restart event now");
handler(this, e);
}
}
public void Stop()
{
try
{
isShutdown = true;
if (log.IsInfoEnabled) { log.Info("Stopping router thread"); }
router.Shutdown(SocketShutdown.Both);
//router.Shutdown(SocketShutdown.Receive);
}
catch (Exception ex)
{
if (log.IsErrorEnabled) { log.Error("Exception while stopping", ex); }
}
finally
{
thRouterTh.Interrupt();
router.Dispose();
}
}
private void Connect(EndPoint remoteEndpoint, Socket destination)
{
if (log.IsInfoEnabled) { log.InfoFormat("connecting session at {0}", remoteEndpoint.ToString()); }
var state = new State(router, destination);
try
{
router.Connect(remoteEndpoint);
router.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, OnDataReceive, state);
}
catch (SocketException e)
{
if (log.IsErrorEnabled) { log.Error(string.Format("SocketException while connect: Exception: {0}, ErrorCode: {1}", e, e.ErrorCode)); }
// Stop the service
StopAndFireRestart(new EventArgs());
}
catch (Exception ex)
{
if (log.IsErrorEnabled) { log.Error("exception while connect {0}", ex); }
}
}
private void OnDataReceive(IAsyncResult result)
{
var state = (State)result.AsyncState;
try
{
var bytesRead = state.SourceSocket.EndReceive(result);
if (bytesRead > 0)
{
log.Info(string.Format("Bytes read: {0}", bytesRead));
state.DestinationSocket.Send(state.Buffer, bytesRead, SocketFlags.None);
state.SourceSocket.BeginReceive(state.Buffer, 0, state.Buffer.Length, 0, OnDataReceive, state);
}
}
catch (Exception e)
{
if (log.IsErrorEnabled) { log.Error("Exception receiving the data, Closing source/destination sockets", e); }
//state.DestinationSocket.Close();
//state.SourceSocket.Close();
//StopAndFireRestart(new EventArgs());
}
}
private class State
{
public Socket SourceSocket { get; private set; }
public Socket DestinationSocket { get; private set; }
public byte[] Buffer { get; private set; }
public State(Socket source, Socket destination)
{
SourceSocket = source;
DestinationSocket = destination;
Buffer = new byte[8192];
}
}
}
}
The problem happens when suddenly the client gets disconnected from the remote port randomly after 4-5 hrs. How can I reconnect the client gracefully so that there is no change in the client code ?
Why don't you solve this issue with netsh?
netsh interface portproxy add v4tov4 listenport=LOCALPORT listenaddress=localhost connectport=REMOTEPORT connectaddress=REMOTEADDRESS
or
netsh interface portproxy add v4tov4 listenport=LOCALPORT connectport=REMOTEPORT connectaddress=REMOTEADDRESS
More information on netsh available on MSDN.

WinCE 6.0 connecting to PC via ActiveSync/Window Mobile Device Center C#

I am developing a WinCE application (.Net 3.5) which allow connection to terminal via TCPIP, Serial Port and USB.
TCPIP and Serial Port is done but USB is problematic. As the client need to see proof on USB can be done, we need to prove that we can send Hex command through ActiveSync.
I have google for some time and found that ActiveSync/WMDC will provide IP to allow connection with each other. The problem is i couldn't ping or connect via C# socket from PC to WinCE via ActiveSync/WMDC.
The only thing i know is that my WinCE IP when connecting to PC is:
IP Address : 192.168.55.101
Subnet Mask : 255.255.255.0
Default Gateway: 192.168.55.100
Primary DNS : 127.0.0.1
Below is my WinCE server code that i use to allow all connection from ActiveSync. I am reusing my TCPIP code to connect to ActiveSync.
_listener.Bind(new IPEndPoint(IPAddress.Any, _port));
_listener.Listen(100);
_listener.BeginAccept(ConnectionReady, null);
Is there anything that i have missed to allow connection with each other? Thanks in advance.
It seem that it is workable but not in a straight forward way.
Normally we will set the PC as Server while WinCE as Slave. In this case, it is in backwards. WinCE will be the host while PC will be the slave.
Below is my code that i have used to declare and start the connection:
private void SetUSBSerialPort()
{
try
{
usbSerialPort = new USBSerialPort(config.terminal_tcpip_port);
usbSerialPort.OnReceiveData += new USBSerialPort.EventOnReceiveData(usbSerialPort_OnReceiveData);
usbSerialPort.Start();
}
catch (Exception ex)
{
}
}
And below is the class that i used to connect PC and WinCE via ActiveSync:
public class ConnectionStateUSB
{
internal Socket _conn;
//internal TcpServiceProvider _provider;
internal byte[] _buffer;
/// <SUMMARY>
/// Tells you the IP Address of the remote host.
/// </SUMMARY>
public EndPoint RemoteEndPoint
{
get { return _conn.RemoteEndPoint; }
}
/// <SUMMARY>
/// Returns the number of bytes waiting to be read.
/// </SUMMARY>
public int AvailableData
{
get { return _conn.Available; }
}
/// <SUMMARY>
/// Tells you if the socket is connected.
/// </SUMMARY>
public bool Connected
{
get { return _conn.Connected; }
}
/// <SUMMARY>
/// Reads data on the socket, returns the number of bytes read.
/// </SUMMARY>
public int Read(byte[] buffer, int offset, int count)
{
try
{
if (_conn.Available > 0)
return _conn.Receive(buffer, offset, count, SocketFlags.None);
else return 0;
}
catch
{
return 0;
}
}
/// <SUMMARY>
/// Sends Data to the remote host.
/// </SUMMARY>
public bool Write(byte[] buffer, int offset, int count)
{
try
{
_conn.Send(buffer, offset, count, SocketFlags.None);
return true;
}
catch
{
return false;
}
}
/// <SUMMARY>
/// Ends connection with the remote host.
/// </SUMMARY>
public void EndConnection()
{
if (_conn != null && _conn.Connected)
{
_conn.Shutdown(SocketShutdown.Both);
_conn.Close();
}
}
}
class USBSerialPort
{
Socket newsock;
Socket client;
int port;
IPAddress ipaddress;
private AsyncCallback ConnectionReady;
private AsyncCallback AcceptConnection;
private AsyncCallback ReceivedDataReady;
private ConnectionStateUSB currentST;
public bool IsConnected = false;
public USBSerialPort(int _port)
{
port = _port;
//ConnectionReady = new AsyncCallback(ConnectionReady_Handler);
//AcceptConnection = new AsyncCallback(AcceptConnection_Handler);
//ReceivedDataReady = new AsyncCallback(ReceivedDataReady_Handler);
}
public void Start()
{
try
{
ipaddress = Dns.GetHostEntry("ppp_peer").AddressList[0];
newsock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint iep = new IPEndPoint(ipaddress, port);
newsock.BeginConnect(iep, new AsyncCallback(Connected), newsock);
}
catch (Exception ex)
{
throw ex;
this.Stop();
}
finally
{
//net_stream = null;
//tcp_client = null;
}
}
void Connected(IAsyncResult iar)
{
try
{
client = (Socket)iar.AsyncState;
client.EndConnect(iar);
ConnectionStateUSB st = new ConnectionStateUSB();
st._conn = client;
st._buffer = new byte[4];
//Queue the rest of the job to be executed latter
//ThreadPool.QueueUserWorkItem(AcceptConnection, st);
currentST = st;
//conStatus.Text = "Connected to: " + client.RemoteEndPoint.ToString();
if (client.Connected)
client.BeginReceive(st._buffer, 0, 0, SocketFlags.None,
new AsyncCallback(ReceiveData), st);
}
catch (SocketException e)
{
IsConnected = false;
//conStatus.Text = "Error connecting";
}
catch (Exception ex)
{
IsConnected = false;
}
}
void ReceiveData(IAsyncResult iar)
{
try
{
ConnectionStateUSB remote = (ConnectionStateUSB)iar.AsyncState;
remote._conn.EndReceive(iar);
try
{
this.OnReceiveData(remote);
IsConnected = true;
}
catch (Exception ex)
{
IsConnected = false;
}
//int recv = remote.EndReceive(iar);
//string stringData = Encoding.ASCII.GetString(data, 0, recv);
//results.Items.Add(stringData);
if (remote.Connected)
remote._conn.BeginReceive(remote._buffer, 0, 0, SocketFlags.None,
new AsyncCallback(ReceiveData), remote);
}
catch (Exception ex)
{
this.Stop();
}
}
public void SendData(byte[] data)
{
try
{
bool a = currentST.Write(data, 0, data.Length);
}
catch (Exception ex)
{
IsConnected = false;
MessageBox.Show("Error!\n" + ex.Message + "\n" + ex.StackTrace);
}
}
public void SendData(string data)
{
try
{
byte[] msg = Encoding.UTF8.GetBytes(data + Convert.ToChar(Convert.ToByte(3)));
bool a = currentST.Write(msg, 0, msg.Length);
msg = null;
}
catch (Exception ex)
{
IsConnected = false;
MessageBox.Show("Error!\n" + ex.Message + "\n" + ex.StackTrace);
}
}
/// <SUMMARY>
/// Shutsdown the server
/// </SUMMARY>
public void Stop()
{
//lock (this)
//{
if (newsock != null)
newsock.Close();
if (client != null)
client.Close();
if (currentST != null)
{
currentST._conn.Close();
currentST = null;
}
IsConnected = false;
//}
}
/// <SUMMARY>
/// Gets executed when the server accepts a new connection.
/// </SUMMARY>
public delegate void EventOnAcceptConnection(ConnectionStateUSB socket);
public event EventOnAcceptConnection OnAcceptConnection;
/// <SUMMARY>
/// Gets executed when the server detects incoming data.
/// This method is called only if OnAcceptConnection has already finished.
/// </SUMMARY>
public delegate void EventOnReceiveData(ConnectionStateUSB socket);
public event EventOnReceiveData OnReceiveData;
/// <SUMMARY>
/// Gets executed when the server needs to shutdown the connection.
/// </SUMMARY>
public delegate void EventOnDropConnection(ConnectionStateUSB socket);
public event EventOnDropConnection OnDropConnection;
}
Hope this help.

Out of memory exception on server, but most troubling; events not being called unless I debug

I have this very weird error. Basically, as soon as I add the line of code Connections.Add(handler); my program goes haywire. I'm also getting the error:
System.OutOfMemoryException: Exception of type
'System.OutOfMemoryException' was thrown. at
System.Threading.ExecutionContext.CreateCopy() at
System.Net.ContextAwareResult.CaptureOrComplete(ExecutionContext&
cachedContext, Boolean returnContext)
What happens is, when I add this code, connections are still being accepted, but nothing is being logged on my log richtextbox control. This is very weird, and I have no idea whats going on. However, removing that Connections.Add(handler) line in my accept event solves all problems. But I need to keep track of sockets somehow so I can implement pinging to keep them alive
Here is my code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Concurrent;
namespace SpybotServer
{
public partial class Server : Form
{
public void log(String text)
{
logs.InvokeEx(a => a.Text += (text +Environment.NewLine));
}
public Server()
{
InitializeComponent();
}
private void Server_Load(object sender, EventArgs e)
{
Thread serverThread = new Thread(delegate()
{
Listener.StartListening(9001);
});
serverThread.Start();
heartbeat.Start();
}
private void Server_FormClosed(object sender, FormClosedEventArgs e)
{
Listener.looping = false;
}
private void heartbeat_Tick(object sender, EventArgs e)
{
Listener.heartbeat();
}
}
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 Listener
{
public static Boolean looping = true;
private static List<Socket> Connections = new List<Socket>();
public static void heartbeat()
{
Program.MainForm.log("Sending ping...");
}
public static void StartListening(int port)
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 9001);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Program.MainForm.log("Listening on port " + port);
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (looping)
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
}
catch (Exception e)
{
Program.MainForm.log(e.ToString());
}
}
public static void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject state = new StateObject();
state.workSocket = handler;
IPEndPoint ip = handler.RemoteEndPoint as IPEndPoint;
Program.MainForm.log("Accepted connection from " + ip.Address);
//Connections.Add(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;
try
{
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_END>#!") > -1)
{
Program.MainForm.log(content);
}
else
{
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}*/
}
}
catch (Exception e)
{
Program.MainForm.log(e.ToString());
}
}
private static void Send(Socket handler, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private static void SendCallback(IAsyncResult ar)
{
Socket handler = (Socket)ar.AsyncState;
try
{
int bytesSent = handler.EndSend(ar);
if (bytesSent <= 0)
{
Program.MainForm.log("Socket has been closed.");
}
}
catch (Exception e)
{
Program.MainForm.log(e.ToString());
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
}
}
InvokeEx:
using System;
using System.Collections.Generic;
using System.ComponentModel;
namespace SpybotServer
{
static class ISynchronizeInvokeExtensions
{
public static void InvokeEx<T>(this T #this, Action<T> action) where T : ISynchronizeInvoke
{
if (#this.InvokeRequired)
{
#this.Invoke(action, new object[] { #this });
}
else
{
action(#this);
}
}
}
}
Since this callback:
public static void AcceptCallback(IAsyncResult ar)
is inside this loop:
while (looping)
{
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
}
I'm more than 90% certain that you are adding the same Socket to the Connections list over and over and just growing the size of the list at an alarming rate. Change the add to this:
if (Connections.Contains(handler))
{
Connections.Add(handler);
}
Michael is on the right track, but not with the right solution.
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
Is (unlike Accept) not going to block and weird things are going to happen if you call it this way. Instead take your BeginAccept out of a loop and call it again from AcceptCallback so that you can accept a new connection after you have accepted a first.

Asynchronous SSL Socket

Recently I was creating an asynchronous ssl socket class. I finished it, and it authenticated with the client successfully but it did not receive the message sent by client correctly.
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.IO;
public class Wrapper
{
public byte[] buffer;
public SslStream sslStream;
public object connector;
}
public class Sock
{
private Dictionary<string, byte> Connections;
public event Action<Wrapper> AnnounceNewConnection;
public event Action<Wrapper> AnnounceDisconnection;
public event Action<byte[], Wrapper> AnnounceReceive;
private Socket _sock;
private X509Certificate certificate = X509Certificate.CreateFromCertFile("exportedcertificate.cer");
public Sock(int port)
{
try
{
Connections = new Dictionary<string, byte>();
_sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_sock.Bind(new IPEndPoint(IPAddress.Any, port));
_sock.Listen(500);
_sock.BeginAccept(AcceptConnections, new Wrapper());
}
catch (Exception e)
{
Console.WriteLine(e);
}
}
private void AcceptConnections(IAsyncResult result)
{
Wrapper wr = (Wrapper)result.AsyncState;
try
{
wr.sslStream = new SslStream(new NetworkStream(_sock.EndAccept(result), true));
wr.sslStream.BeginAuthenticateAsServer(certificate, EndAuthenticate, wr);
_sock.BeginAccept(AcceptConnections, new Wrapper());
}
catch (Exception e) { Console.WriteLine(e); }
}
private void EndAuthenticate(IAsyncResult result)
{
Wrapper wr = (Wrapper)result.AsyncState;
try
{
wr.sslStream.EndAuthenticateAsServer(result);
if (wr.sslStream.IsAuthenticated == true)
{
wr.buffer = new byte[65535];
wr.sslStream.BeginRead(wr.buffer, 0, wr.buffer.Length, ReceiveData, wr);
AnnounceNewConnection.Invoke(wr);
}
}
catch (Exception e) { Console.WriteLine(e); }
}
private void ReceiveData(IAsyncResult result)
{
Wrapper wr = (Wrapper)result.AsyncState;
try
{
int size = wr.sslStream.EndRead(result);
byte[] buffer = new byte[size];
Buffer.BlockCopy(wr.buffer, 0, buffer, 0, size);
AnnounceReceive.Invoke(wr.buffer, wr);
if (wr.sslStream.IsAuthenticated)
wr.sslStream.BeginRead(wr.buffer, 0, wr.buffer.Length, ReceiveData, wr);
}
catch (Exception e) { Console.WriteLine(e); AnnounceDisconnection.Invoke(wr); }
}
}
So in the code above when I call BeginRead and try to use
Console.WriteLine(Encoding.ASCII.GetString(arg1));,
I only get alot of empty lines [Note I use the ssl client from the MSDN example to test my server]
I really want to know why it does not correctly receive the message!

Categories

Resources