I'm creating a C# socket for UDP receive and send capabilities with Asynchronous callback functions for the receive. Simple, right! It took a while to get all the wrinkles ironed out, but it works... Well, as long as you hog the port! I need to allow other applications to use the same port number. No problem, right! There's an option for that, SetSocketOption(...) for ReuseAddress...
udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);
Why is it that when I set ReuseAddress to true, the callback function doesn't get hit anymore?
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using CSharpUtilityLibrary.Utilities;
namespace CSharpNIU.Sockets
{
public class PacketEventArgs : EventArgs {
public byte[] Bytes { get; set; }
public PacketEventArgs(byte[] bytes)
{
Bytes = bytes;
}
}
public delegate void PacketEventHandler(object sender, PacketEventArgs e);
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1553;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public class UDPSocket
{
// Thread signal.
public ManualResetEvent allDone = new ManualResetEvent(false);
public String ApplicationName { get; set; }
public Form ParentForm { get; set; }
public Network ApplicationNetwork { get; set; }
private ConfigGeneric Config { get; set; }
private Socket udpClient = null;
public UDPSocket(ConfigGeneric config, String applicationName)
{
Config = config;
ApplicationDetails appDetails = config.GetApplicationByName(applicationName);
if (appDetails == null)
return;
ApplicationNetwork = config.GetNetworkByName(appDetails._network);
if (ApplicationNetwork == null) return;
}
public void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._networkAddress);
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);
// Create a UDP Socket
udpClient = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
// Bind the socket to the local endpoint
try
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
allDone.Set();
StateObject stateObject = new StateObject();
stateObject.workSocket = udpClient;
//------> The line Below causes the begin receive to not call ReadCallback <-------//
udpClient.SetSocketOption(SocketOptionLevel.Udp, SocketOptionName.ReuseAddress, true);
//------> The line Above causes the begin receive to not call ReadCallback <-------//
udpClient.Bind(localEndPoint);
udpClient.BeginReceive(stateObject.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), stateObject);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
// Retrieve the state object and the handler socket from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
PacketEventArgs packetEventArgs = new PacketEventArgs(state.buffer);
OnRecevedPacket(packetEventArgs);
// There might be more data, so store the data received so far.
udpClient.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReadCallback), state);
}
}
// Event Handlers
public event PacketEventHandler ReceiveCallback;
protected virtual void OnRecevedPacket(PacketEventArgs e)
{
if (ReceiveCallback != null)
ReceiveCallback(this, e);
}
public void Send(byte[] bytes)
{
// Begin sending the data to the remote device.
IPAddress ipAddress = IPAddress.Parse(ApplicationNetwork._broadcastAddress);
IPEndPoint endPoint = new IPEndPoint(ipAddress, ApplicationNetwork._receivePort);
udpClient.SendTo(bytes, endPoint);
}
}
}
From what I can tell, you should be using UdpClient instead of going low level with Socket.
You also need to create UdpClient with the default constructor to be able to change settings like ExclusiveAddressUse.
This guy has a working example: http://social.msdn.microsoft.com/Forums/en-US/fe830c54-30ab-4ae6-a86a-7c2a9ccd11cf/udpclient-more-than-one-on-the-same-port
Related
I am trying to make a TCP Client in a UWP application.
I can create a client with no issues. The problem is I need to listen continuously to anything that remote device sends back such as a login prompt.
I did try to use Stream Socket also but that listens for incoming only.
The goal is to open a connection and send and receive to that remote device only for the connection.
I have tried many options I have found online with no luck.
Basics of the connection:
Connect to the remote device and stay connected.
Wait for prompts(which can be slow at times).
Send back login in information
Get logged in confirmation
Stay connected and send and receive data continuously.
Any help would be great.
I was able to get it working properly with this:
private TcpClient client;
private NetworkStream recieveData;
private Task rx;
public delegate void DataRecived(string data);
public event DataRecived OnDataRecived;
public delegate void ConnectionStatus(bool data);
public event ConnectionStatus clientConnected;
public delegate void LogStatus(bool data);
public event LogStatus loggedIn;
public delegate void ValueChanged(int value);
public event ValueChanged newLightValue;
public string Ip;
public int Port;
private bool auth;
public bool valueInChanging;
public Client()
{
client = new TcpClient();
rx = new Task(StartReading);
}
public async void Connect()
{
try
{
await client.ConnectAsync(Ip, Port);
clientConnected(client.Connected);
rx.Start();
}
catch (Exception ex)
{
OnDataRecived("Error Connecting" + ex.ToString());
}
}
private void StartReading()
{
while (true)
{
recieveData = client.GetStream();
byte[] bytes = new byte[1024];
Byte[] data = new Byte[256];
string responseData;
if (recieveData != null)
{
int bytesRead = recieveData.Read(bytes, 0, bytes.Length);
responseData = System.Text.Encoding.ASCII.GetString(bytes, 0, bytesRead);
if (!auth)
{
OnReceivedMessage(responseData);
}
else
{
Feedback(responseData);
}
}
}
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 7 years ago.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Improve this question
I've programmed a TCP/IP server with c# .NET Sockets. Using local network it works fine, but when i try to use it over the internet the client can't connect to the server.
I'm sure i've opened my port (14999) in the router and in windows firewall(both, client and server) and i also mapped my computer port 14999 to the one on the router.
Even with this i get "An existing co
nnection was forcibly closed by the remote host." When my client application try to connect over the internet to my server.
There is one thing i noticed .
When i have my server debugging with Visual Studio, and i use http://www.yougetsignal.com/tools/open-ports/ to check the 14999 port, the code hits a breakpoint.
I've been stucked with this ours, is there anybody who knows what can i do ?
Thanks a lot everyone!
Here is my client app 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.Threading;
using System.Web.Script.Serialization;
using System.Security.Cryptography;
using System.IO;
namespace ConsoleApplication1
{
public class Person
{
public string name;
public int age;
}
// State object for receiving data from remote device.
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousClient
{
// The port number for the remote device.
private const int port = 14999;
// ManualResetEvent instances signal completion.
private static ManualResetEvent connectDone =
new ManualResetEvent(false);
private static ManualResetEvent sendDone =
new ManualResetEvent(false);
private static ManualResetEvent receiveDone =
new ManualResetEvent(false);
// The response from the remote device.
private static String response = String.Empty;
private static void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
// The name of the
// remote device is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry("MY PUBLIC IP");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
Socket client = new Socket(AddressFamily.Unspecified,
SocketType.Stream, ProtocolType.Tcp);
for (;;)
{
// Create a TCP/IP socket.
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
User user = new User() { name = "asdfasdfasdf", adress = "asdfasdfas", country = "asdfasdf", email = "example#example.com", locality = "asdfasdf", pass = "asdfasdf", state = "aasdfasd", surname = "asdfasdfasdf", telfNum = 123123 };
loginPublic login = new loginPublic() { email = "example#example.com", pass = "asdfasdfasdfas" };
accion accion = new accion() { act = 2, data = login };
var die = new JavaScriptSerializer().Serialize(accion);
//string guy = SPHFS.EncryptStringAES(die, "HFSIsAwesome12#.");
string guy = die;
// Send test data to the remote device.
Send(client, guy);
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
respuesta Resp = new JavaScriptSerializer().Deserialize<respuesta>(response);
Console.WriteLine("Message : {0} and Result : {1}", Resp.Message, Resp.Result);
Thread.Sleep(100);
// Write the response to the console.
}
// Release the socket.
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
}
}
private static void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
}
}
private static void Receive(Socket client)
{
try
{
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
// Begin receiving the data from the remote device.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
ReceiveCallback, state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
}
}
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
// Retrieve the state object and the client socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket client = state.workSocket;
// Read data from the remote device.
int bytesRead = client.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, bytesRead));
// Get the rest of the data.
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
ReceiveCallback, state);
}
else
{
// All the data has arrived; put it in response.
if (state.sb.Length > 1)
{
response = state.sb.ToString();
}
// Signal that all bytes have been received.
receiveDone.Set();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
Console.ReadLine();
}
}
private static void Send(Socket client, String data)
{
for(;;)
{
try
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
client.BeginSend(byteData, 0, byteData.Length, 0,
SendCallback, client);
break;
}
catch
{
}
}
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
Console.WriteLine("Sent {0} bytes to server.", bytesSent);
// Signal that all bytes have been sent.
sendDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartClient();
return 0;
}
public class User
{
public string name { get; set; }
public string surname { get; set; }
public string adress { get; set; }
public string locality { get; set; }
public string country { get; set; }
public string state { get; set; }
public string email { get; set; }
public int telfNum { get; set; }
public string pass { get; set; }
public LicenceDAO licencia { get; set; }
}
public class LicenceDAO
{
public decimal payment;
public DateTime nextPayment;
public bool state;
public string administrator;
}
public class accion
{
public int act;
public string key;
public object data;
}
public class respuesta
{
public bool Result;
public string Message;
}
public class loginPublic
{
public string email;
public string pass;
}
}
}
You are having an issue because you are attempting to connect to a server on your local network via the external address using NAT (hairpinning). Normally you should connect to your server application using the internal address if available, external connections would still work using the external address through NAT. If this is just an issue for testing and your router does not support NAT hairpinning, NAT loopback, or NAT reflection, you can either look around for ways to get around the hairpin (usually by setting up your own DNS) or have someone help you test from an external connection.
I have asynchronous communication between client and server. When the client receives a response from the server (ReceiveCallback), the response is stored in public static string response in my NetworkHandler class. I am trying to use this field in my GameHandler class, but it says that response is empty.
I am sure that my buffer in NetworkHandler is not empty, because I checked it.
I think it happens because NetworkHandler.response is called before the response gets a value, but I am not sure and I don't know how to solve it...
See the comments in the code for more explanation...
Please take a look at this image to see the null value in GameHandler: http://i.imgur.com/BPVDlhf.png And here to see the correct value in NetworkHandler: http://i.imgur.com/vfY2IuD.png
class NetworkHandler
{
public static string response = String.Empty;
private static void ReceiveCallback(IAsyncResult AR)
{
Socket remote = (Socket)AR.AsyncState;
int received = remote.EndReceive(AR);
byte[] dataBuffer = new byte[received];
Array.Copy(_buffer, dataBuffer, received);
string serverData = Encoding.ASCII.GetString(dataBuffer);
response = serverData;
}
private static void SendCallback(IAsyncResult AR)
{
Socket remote = (Socket)AR.AsyncState;
int sent = remote.EndSend(AR);
remote.BeginReceive(_buffer, 0, _size, SocketFlags.None, new AsyncCallback(ReceiveCallback), remote);
}
public static void sendData(string data)
{
byte[] message = Encoding.ASCII.GetBytes(data);
_client.BeginSend(message, 0, message.Length, SocketFlags.None, new AsyncCallback(SendCallback), _client);
}
private static void ConnectCallback(IAsyncResult AR)
{
_client = (Socket)AR.AsyncState;
try
{
_client.EndConnect(AR);
_client.BeginReceive(_buffer, 0, _size, SocketFlags.None, new AsyncCallback(ReceiveCallback), _client);
}
catch (SocketException e)
{
Console.WriteLine(e.ToString());
}
}
}
class GameHandler
{
public void StartGame()
{
// SEND DATA USING BEGINSEND()
SendData("<sg>");
// THIS VALUE IS NULL!!! :(
_response = NetworkHandler.response;
// SO CODE INSIDE IF IS NOT EXECUTED :(
if (_response != null)
{
// If you are the drawer.
if (_response.Substring(0, 5) == "<dra>")
etc.........
}
}
public void SendData(string data)
{
NetworkHandler.sendData(data);
}
}
I am writing a TCP based client that need to send and receive data. I have used the Asynchronous Programming Model (APM) provided for Socket class by the .NET Framework.
After being connected to the socket, I start wait for data on the socket using BeginReceive.
Now, while I am waiting for the data on the Socket, I may need to send data over the socket. And the send method can be called multiple times,
So i have make sure that
All the bytes from previous Send call is entirely sent.
The way i am sending the Data is safe considering that, while a data send is in progress, any call to send data can be made.
This is my first work on socket, So is my approach right to send data ?
private readonly object writeLock = new object();
public void Send(NetworkCommand cmd)
{
var data = cmd.ToBytesWithLengthPrefix();
ThreadPool.QueueUserWorkItem(AsyncDataSent, data);
}
private int bytesSent;
private void AsyncDataSent(object odata)
{
lock (writeLock)
{
var data = (byte[])odata;
int total = data.Length;
bytesSent = 0;
int buf = Globals.BUFFER_SIZE;
while (bytesSent < total)
{
if (total - bytesSent < Globals.BUFFER_SIZE)
{
buf = total - bytesSent;
}
IAsyncResult ar = socket.BeginSend(data, bytesSent, buf, SocketFlags.None, DataSentCallback, data);
ar.AsyncWaitHandle.WaitOne();
}
}
}
How object is changed into byte[], sometimes the NetworkCommand can be as big as 0.5 MB
public byte[] ToBytesWithLengthPrefix()
{
var stream = new MemoryStream();
try
{
Serializer.SerializeWithLengthPrefix(stream, this, PrefixStyle.Fixed32);
return stream.ToArray();
}
finally
{
stream.Close();
stream.Dispose();
}
}
Complete class
namespace Cybotech.Network
{
public delegate void ConnectedDelegate(IPEndPoint ep);
public delegate void DisconnectedDelegate(IPEndPoint ep);
public delegate void CommandReceivedDelagate(IPEndPoint ep, NetworkCommand cmd);
}
using System;
using System.Net;
using System.Net.Sockets;
using Cybotech.Helper;
using Cybotech.IO;
namespace Cybotech.Network
{
public class ClientState : IDisposable
{
private int _id;
private int _port;
private IPAddress _ip;
private IPEndPoint _endPoint;
private Socket _socket;
private ForwardStream _stream;
private byte[] _buffer;
public ClientState(IPEndPoint endPoint, Socket socket)
{
Init(endPoint, socket);
}
private void Init(IPEndPoint endPoint, Socket socket)
{
_endPoint = endPoint;
_ip = _endPoint.Address;
_port = _endPoint.Port;
_id = endPoint.GetHashCode();
_socket = socket;
_stream = new ForwardStream();
_buffer = new byte[Globals.BUFFER_SIZE];
}
public int Id
{
get { return _id; }
}
public int Port
{
get { return _port; }
}
public IPAddress Ip
{
get { return _ip; }
}
public IPEndPoint EndPoint
{
get { return _endPoint; }
}
public Socket Socket
{
get { return _socket; }
}
public ForwardStream Stream
{
get { return _stream; }
}
public byte[] Buffer
{
get { return _buffer; }
set { _buffer = value; }
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_stream != null)
{
_stream.Close();
_stream.Dispose();
}
if (_socket != null)
{
_socket.Close();
}
}
}
public void Dispose()
{
Dispose(true);
}
}
}
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using Cybotech.Command;
using Cybotech.Network;
namespace ExamServer.Network
{
public class TcpServer : IDisposable
{
private Socket socket;
private bool secure;
private readonly Dictionary<IPEndPoint, ClientState> clients = new Dictionary<IPEndPoint, ClientState>();
//public events
#region Events
public event CommandDelegate CommandReceived;
public event ConnectedDelegate ClientAdded;
public event DisconnectedDelegate ClientRemoved;
#endregion
//event invokers
#region Event Invoke methods
protected virtual void OnCommandReceived(IPEndPoint ep, NetworkCommand command)
{
CommandDelegate handler = CommandReceived;
if (handler != null) handler(ep, command);
}
protected virtual void OnClientAdded(IPEndPoint ep)
{
ConnectedDelegate handler = ClientAdded;
if (handler != null) handler(ep);
}
protected virtual void OnClientDisconnect(IPEndPoint ep)
{
DisconnectedDelegate handler = ClientRemoved;
if (handler != null) handler(ep);
}
#endregion
//public property
public string CertificatePath { get; set; }
public TcpServer(EndPoint endPoint, bool secure)
{
StartServer(endPoint, secure);
}
public TcpServer(IPAddress ip, int port, bool secure)
{
StartServer(new IPEndPoint(ip, port), secure);
}
public TcpServer(string host, int port, bool secure)
{
StartServer(new IPEndPoint(IPAddress.Parse(host), port), secure);
}
private void StartServer(EndPoint ep, bool ssl)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Bind(ep);
socket.Listen(150);
this.secure = ssl;
socket.BeginAccept(AcceptClientCallback, null);
}
private void AcceptClientCallback(IAsyncResult ar)
{
Socket client = socket.EndAccept(ar);
var ep = (IPEndPoint) client.RemoteEndPoint;
var state = new ClientState(ep, client);
if (secure)
{
//TODO : handle client for ssl authentication
}
//add client to
clients.Add(ep, state);
OnClientAdded(ep);
client.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
//var thread = new Thread(ReceiveDataCallback);
//thread.Start(state);
}
private void ReceiveDataCallback(IAsyncResult ar)
{
ClientState state = (ClientState)ar.AsyncState;
try
{
var bytesRead = state.Socket.EndReceive(ar);
state.Stream.Write(state.Buffer, 0, bytesRead);
// check available commands
while (state.Stream.LengthPrefix > 0)
{
NetworkCommand cmd = NetworkCommand.CreateFromStream(state.Stream);
OnCommandReceived(state.EndPoint, cmd);
}
//start reading data again
state.Socket.BeginReceive(state.Buffer, 0, state.Buffer.Length, SocketFlags.None, ReceiveDataCallback, state);
}
catch (SocketException ex)
{
if (ex.NativeErrorCode.Equals(10054))
{
RemoveClient(state.EndPoint);
}
}
}
private void RemoveClient(IPEndPoint ep)
{
OnClientDisconnect(ep);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
//TODO : dispose all the client related socket stuff
}
}
public void Dispose()
{
Dispose(true);
}
}
}
The same client won't be able to send data to you unless he finishes sending the current bytes.
So on the server side, you will receive the completed data no interrupted by other new messages from that client, but take in consideration that not all the message sent will be received by one hit if it is too big, but still, it is one message in the end after receiving is finished.
As you are using TCP, the network protocol will ensure that packets are received in the same order as sent.
Regarding thread safety it depends a bit on the actual class which you are using for sending. The declaration part is missing in your provided code fragment.
Given by the name you seem to use Socket and this is thread-safe, so every send is actually atomic, if you use any flavor of Stream, then it is not thread-safe and you need some form of synchronization like a lock, which you are currently using anyway.
If you are sending large packets, then it is important to split the receiving and processing part into two different threads. The TCP buffer is actually a lot smaller than one would think and unfortunately it is not covered inside the logs when it is full as the protocol will keep performing resend until everything has been received.
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.