The code below creates socket server and client
I start the server and if I start one after the other the clients it works fine
If I start three clients immediately, then for one or more clients the BeginAccept event is not fired
The results bellow are after executing the code bellow
Server Started
Server is waiting for a connection...
Client 0.0.0.0:6352 requests connection
Client 0.0.0.0:6353 requests connection
Client 127.0.0.1:6351 requests connection
Client 127.0.0.1:6351 connected
Client 127.0.0.1:6352 connected
Client 127.0.0.1:6353 connected
ServerOnClientConnection Client: 127.0.0.1:6351
Server is waiting for a connection...
ServerOnClientConnection Client: 127.0.0.1:6353
code follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace Test {
public class TestSockets {
#region server
Socket serverSocket;
bool serverIsAlive;
public ManualResetEvent waitForConnection = new ManualResetEvent(false);
private Encoding encod = Encoding.Unicode;
public void ServerStartInThread() {
byte[] bytes = new Byte[1024];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5500);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket = socket;
try {
socket.Bind(localEndPoint);
socket.Listen(100);
Thread pollThread = new Thread(delegate () {
serverIsAlive = true; // needs if reopen
SendMessage("Server Started");
while (serverIsAlive) {
try {
SendMessage("Server is waiting for a connection...");
socket.BeginAccept(new AsyncCallback(ServerOnClientConnection), socket);
waitForConnection.Reset();
waitForConnection.WaitOne();
}
catch (Exception ex) {
SendMessage("Server: " + ex.ToString());
}
}
SendMessage("Server Stopped");
socket.Close();
}) {
Name = "SocketServer"
};
pollThread.Start();
}
catch (Exception ex) {
SendMessage("Server: " + ex.ToString());
}
}
public void ServerOnClientConnection(IAsyncResult ar) {
try {
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar);
SendMessage("ServerOnClientConnection Client: " + clientSocket.RemoteEndPoint.ToString());
StateObject state = new StateObject() {
socket = clientSocket
};
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ServerReceiveCallback), state);
waitForConnection.Set();
}
catch (Exception ex) {
SendMessage("ServerOnClientConnection: " + ex.ToString());
}
}
public void ServerReceiveCallback(IAsyncResult ar) {
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
try {
if (socket == null) return;
if (!socket.Connected) {
return;
}
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0) {
state.sb.Append(encod.GetString(state.buffer, 0, bytesRead));
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ServerReceiveCallback), state);
}
}
catch (Exception ex) {
SendMessage("ServerReceiveCallback: " + ex.ToString());
}
}
#endregion
#region client
private Socket client;
private bool isAlive = false;
private ManualResetEvent connectDone = new ManualResetEvent(false);
public void StartInThread() {
try {
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5500);
Thread pollThread = new Thread(delegate () {
isAlive = true;
while (isAlive) {
try {
if (client != null && client.Connected) {
continue;
}
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(remoteEP, new AsyncCallback(ClientConnectCallback), client);
SendMessage(string.Format("Client {0} requests connection", client.LocalEndPoint.ToString()));
connectDone.Reset();
connectDone.WaitOne(3000, false);
if (client.Connected) {
StateObject state = new StateObject() {
socket = client
};
SendMessage(string.Format("Client {0} connected", client.LocalEndPoint.ToString()));
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ClientReceiveCallback), state);
}
}
catch (Exception ex) {
SendMessage("ClientStartInThread1: " + ex.ToString());
}
}
SendMessage("Client Disconnected");
}) {
Name = "ClientThread"
};
pollThread.Start();
}
catch (Exception ex) {
SendMessage("ClientStartInThread2: " + ex.ToString());
}
}
private void ClientConnectCallback(IAsyncResult ar) {
try {
Socket socket = (Socket)ar.AsyncState;
socket.EndConnect(ar);
connectDone.Set();
}
catch (Exception ex) {
SendMessage("ClientConnectCallback: " + ex.ToString());
}
}
private void ClientReceiveCallback(IAsyncResult ar) {
StateObject state = (StateObject)ar.AsyncState;
Socket socket = state.socket;
if (socket == null || !socket.Connected) return;
try {
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0) {
state.sb.Append(encod.GetString(state.buffer, 0, bytesRead));
socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ClientReceiveCallback), state);
}
else {
socket.Close();
}
}
catch (Exception ex) {
SendMessage("ClientReceiveCallback: " + ex.ToString());
socket.Close();
}
}
#endregion
private void SendMessage(string v) {
System.Diagnostics.Debug.WriteLine(v);
}
public static void Start() {
TestSockets server = new TestSockets();
server.ServerStartInThread();
TestSockets c1 = new TestSockets();
c1.StartInThread();
TestSockets c2 = new TestSockets();
c2.StartInThread();
TestSockets c3 = new TestSockets();
c3.StartInThread();
}
}
public class StateObject {
public Socket socket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
}
}
You have a race condition in your code that results in the waitForConnection event handle being set twice, with the second call to Set() having no effect, before the main server thread has a chance to proceed past the BeginAccept() and reset the handle. This causes it to miss the second set.
One way to fix it would be to switch to a semaphore object. For example:
#region server
Socket serverSocket;
bool serverIsAlive;
SemaphoreSlim waitForConnection = new SemaphoreSlim(0);
private Encoding encod = Encoding.Unicode;
public void ServerStartInThread()
{
byte[] bytes = new Byte[1024];
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5500);
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket = socket;
try
{
socket.Bind(localEndPoint);
socket.Listen(100);
Thread pollThread = new Thread(delegate () {
serverIsAlive = true; // needs if reopen
SendMessage("Server Started");
while (serverIsAlive)
{
try
{
SendMessage("Server is waiting for a connection...");
socket.BeginAccept(new AsyncCallback(ServerOnClientConnection), socket);
waitForConnection.Wait();
}
catch (Exception ex)
{
SendMessage("Server: " + ex.ToString());
}
}
SendMessage("Server Stopped");
socket.Close();
})
{
Name = "SocketServer"
};
pollThread.Start();
}
catch (Exception ex)
{
SendMessage("Server: " + ex.ToString());
}
}
public void ServerOnClientConnection(IAsyncResult ar)
{
try
{
Socket listener = (Socket)ar.AsyncState;
Socket clientSocket = listener.EndAccept(ar);
SendMessage("ServerOnClientConnection Client: " + clientSocket.RemoteEndPoint.ToString());
StateObject state = new StateObject()
{
socket = clientSocket
};
clientSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ServerReceiveCallback), state);
waitForConnection.Release();
}
catch (Exception ex)
{
SendMessage("ServerOnClientConnection: " + ex.ToString());
}
}
This will allow the ServerOnClientConnection() method to increment the semaphore count, so that the main server thread can continue to loop until all of the accepted connections have been observed.
However, frankly, the MSDN examples that use these event handles (which is what I'm assuming your code is based on, either directly or indirectly) are IMHO simply broken. They introduce thread synchronization complexities where none is actually needed, unnecessarily complicating the code and making it harder to get the code to work correctly.
A more idiomatic approach would be to not have the extra thread at all, call BeginAccept() once in the ServerStartInThread() method (which you'd probably rename to just ServerStart()) and call BeginAccept() in the ServerOnClientConnection() method after handling the currently accepted client. I.e. just like you handle the BeginReceive() now.
That said, IMHO even the idiomatic approach is outdated. It worked very well when the API was first designed, but .NET has come a long way since then and has much better mechanisms for dealing with asynchronous operations like this. I posted in this answer an example of a simple chat server that shows how you can use async/await to implement this sort of thing in a much simpler, easier-to-read way. You may want to look at that for ideas on how to apply the same techniques to your own code.
Related
I have a console application which acts as a socket server. It should accept data 24/7 from a number of clients, but issue is that the clients cannot establish connection after sometime (not constant). after closing & opening the connection works & it continues to next point of time.
Server
public static void ExecuteServer()
{
int portNumber = 11111;
string _responseMessageToClient = "";
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, portNumber);
// Creation TCP/IP Socket using
// Socket Class Costructor
Socket listener = new Socket(ipAddr.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
bool doBroadCast = false;
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
try`enter code here`
{
Socket clientSocket = listener.Accept();
// Data buffer
byte[] bytes = new Byte[1024*2];//2048
string data = null;
while (true)
{
try
{
if (clientSocket.Connected)
{
int numByte = clientSocket.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,
0, numByte);
if (data.IndexOf("!") > -1)
break;
}
else
{
Console.WriteLine("Disconnected {0}", clientSocket.LocalEndPoint);
break;
}
}
catch (Exception e)
{
//ErrorLogProvider.Save(e);
Console.WriteLine(e.ToString());
break;
}
}
Console.WriteLine("Text received -> {0} ", data);
if (clientSocket.Connected)
{
clientSocket.Send(message);
}
clientSocket.Shutdown(SocketShutdown.Both);
clientSocket.Close();
}
catch (Exception e)
{
}
}
}
catch (Exception e)
{
}
}
This server has to be running continuously - Client code given below
static void ExecuteClient()
{
try
{
// Establish the remote endpoint
// for the socket. This example
// uses port 11111 on the local
// computer.
int portNumber = 11111;
IPHostEntry ipHost = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddr = ipHost.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddr, portNumber);
// Creation TCP/IP Socket using
// Socket Class Costructor
Socket sender = new Socket(ipAddr.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
long i = 0;
try
{
//while (i < 10)
//{
// Connect Socket to the remote
// endpoint using method Connect()
sender.Connect(localEndPoint);
// We print EndPoint information
// that we are connected
Console.WriteLine("Socket connected to -> {0} ",
sender.RemoteEndPoint.ToString());
// Creation of messagge that
// we will send to Server
byte[] messageSent = Encoding.ASCII.GetBytes("^check!");
int byteSent = sender.Send(messageSent);
// Data buffer
byte[] messageReceived = new byte[1024];
// We receive the messagge using
// the method Receive(). This
// method returns number of bytes
// received, that we'll use to
// convert them to string
int byteRecv = sender.Receive(messageReceived);
Console.WriteLine("Message from Server -> {0}",
Encoding.ASCII.GetString(messageReceived,
0, byteRecv));
//}
// Close Socket using
// the method Close()
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
// Manage of Socket's Exceptions
catch (ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch (SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch (Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
I've got this code somewhere from SO if I remember that correctly.
LoopClients just checks for new clients and handles them by spawning a new thread.
class Server {
private TcpListener _server;
private Boolean _isRunning = true;
private int m_Port = 12001;
private Thread m_ServerThread;
public Server (int p_Port) {
_server = new TcpListener(IPAddress.Any, m_Port);
_server.Start( );
m_ServerThread = new Thread(new ThreadStart(LoopClients));
m_ServerThread.Start( );
}
public void ShutdownServer() {
_isRunning = false;
}
public void LoopClients ( ) {
while ( _isRunning ) {
// wait for client connection
TcpClient newClient = _server.AcceptTcpClient( );
// client found.
// create a thread to handle communication
Thread t = new Thread(new ParameterizedThreadStart(HandleClient));
t.Start(newClient);
}
}
public void HandleClient (object obj) {
try {
// retrieve client from parameter passed to thread
TcpClient client = (TcpClient) obj;
// sets two streams
StreamWriter sWriter = new StreamWriter(client.GetStream( ), Encoding.ASCII);
StreamReader sReader = new StreamReader(client.GetStream( ), Encoding.ASCII);
// you could use the NetworkStream to read and write,
// but there is no forcing flush, even when requested
String sData = null;
while ( client.Connected ) {
sData = sReader.ReadToEnd( );
if ( sData != "" )
break;
}
try {
sWriter.WriteLine("test");
} catch(Exception ex) {
Console.WriteLine(ex.Message);
}
sWriter.Dispose( );
sReader.Dispose( );
sWriter = null;
sReader = null;
} catch ( IOException ioe ) {
}
}
}
Client is somewhat shorter. I've got to shorten the code a bit here.
Client:
private void sendDataViaTCP () {
TcpClient l_Client = new TcpClient();
l_Client.Connect(IP, Port);
Stream l_Stream = l_Client.GetStream( );
StreamWriter l_SW = new StreamWriter(l_Stream);
StreamReader l_SR = new StreamReader(l_SW.BaseStream);
try {
l_SW.WriteLine(Msg);
l_SW.Flush( );
String l_IncomingData;
while ( ( l_IncomingData = l_SR.ReadToEnd()) != "") {
AddLineToLog(l_IncomingData);
}
} finally {
l_SW.Close( );
}
}
I have a basic C#.NET UDP server and client code and I am trying to port it to UWP. For UWP, I experimented with DatagramSocket and regular Socket class. I am seeing almost 40% packet drops on incoming UDP packets on UWP Server using DatagramSocket class. If I use UWP Sockets, I see the packet loss of around 70%. The old .NET code shows 0% packet loss.
I am thinking maybe I am not using the UWP APIs correctly and hence I am getting poor performance. Could someone guide me on how to improve UWP server performance?
Right now, all the tests are done using loop-back. UWP doesn't allow loop-back by default so I am followed the instructions mentioned here to enable loop-back.
The server listens for packet on 50000 port and Client code sends packets of around 60 bytes to server from 50001.
The C#.NET client code is below:
try
{
byte[] buffer = new byte[1024];
IPEndPoint localEP = new IPEndPoint(IPAddress.Any, 50001);
IPAddress remoteIp = System.Net.IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(remoteIp, 50000);
Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
try
{
sender.Bind(localEP);
for(int i = 0; i < 10000; i++)
{
//Thread.Sleep(1);
// Encode the data string into a byte array.
string ClientReq = "Client Request:: " + i.ToString() + " "+ Guid.NewGuid().ToString();
byte[] msg = Encoding.ASCII.GetBytes(ClientReq);
// Send the data through the socket.
int sentBytes = sender.SendTo(msg, remoteEP);
Console.WriteLine("{0}::{1} Client Request ({2} bytes):: {3}.",
remoteEP.Address.ToString(),
remoteEP.Port.ToString(),
sentBytes,
ClientReq
);
}
// Release the socket.
sender.Close();
//Console.ReadKey();
}
catch(ArgumentNullException ane)
{
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
}
catch(SocketException se)
{
Console.WriteLine("SocketException : {0}", se.ToString());
}
catch(Exception e)
{
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
C#.NET Server Code:
byte[] buffer = new Byte[1024];
IPAddress LocalIp = IPAddress.Any; //System.Net.IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(LocalIp, 50000);
// Create a UDP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
{
listener.Bind(localEndPoint);
Console.WriteLine("Bind Complete");
int messagesReceived = 0;
while(true)
{
EndPoint receiveEP = new IPEndPoint(IPAddress.Any, 0);
int receivedBytes = listener.ReceiveFrom(buffer, ref receiveEP);
messagesReceived++;
IPEndPoint receiveIPEP = receiveEP as IPEndPoint;
Console.WriteLine("{0}::{1}::{2} Client Request ({3} bytes):: {4}.",
messagesReceived,
receiveIPEP.Address.ToString(),
receiveIPEP.Port.ToString(),
receivedBytes,
System.Text.Encoding.UTF8.GetString(buffer, 0, receivedBytes));
}
}
catch(Exception e)
{
Console.WriteLine(e.ToString());
}
With this above code, i see all the 10000 packets are received at server.
UWP DatagramSocket Code:
DgSocket = new DatagramSocket();
DgSocket.MessageReceived += SocketListener_MessageReceived;
await DgSocket.BindServiceNameAsync("50000");
private async void SocketListener_MessageReceived(DatagramSocket sender, DatagramSocketMessageReceivedEventArgs args)
{
uint datalen = args.GetDataReader().UnconsumedBufferLength;
DataReader reader = args.GetDataReader();
byte[] dataBuffer = new byte[reader.UnconsumedBufferLength];
reader.ReadBytes(dataBuffer);
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
lock(_lockObject)
{
DgPackets++;
DgPacketList.Add(Encoding.ASCII.GetString(dataBuffer));
}
});
}
UWP Socket Code:
public void SetupSimpleSocketListener()
{
try
{
IPAddress LocalIp = IPAddress.Any;
IPEndPoint localEndPoint = new IPEndPoint(LocalIp, 50000);
SimpleSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
byte[] buffer = new Byte[1024];
SimpleSocket.Bind(localEndPoint);
Debug.WriteLine("Bind Complete");
SocketAsyncEventArgs sockarg = new SocketAsyncEventArgs();
sockarg.Completed += Sockarg_Completed;
sockarg.RemoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
sockarg.SetBuffer(buffer, 0, buffer.Length);
if(!SimpleSocket.ReceiveFromAsync(sockarg))
{
Sockarg_Completed(this, sockarg);
}
}
catch(Exception e)
{
Debug.WriteLine(e.ToString());
}
}
private async void Sockarg_Completed(object sender, SocketAsyncEventArgs e)
{
await this.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
lock(_lockObject)
{
SimpleSocketPackets++;
SimpleSocketPacketList.Add(Encoding.ASCII.GetString(e.Buffer, 0, e.BytesTransferred));
}
});
if(e.SocketError == System.Net.Sockets.SocketError.Success)
{
if(!SimpleSocket.ReceiveFromAsync(e))
{
Sockarg_Completed(this, e);
}
}
}
I have posted the full source code on github:
I used to write socket programs in C and can't understand why the above is happening.
My server blocks at a Receive call, when it returns 0, I break out of the while loop and shutdown the thread.
public class MyServer {
public MyServer() {
}
public void Init() {
ThreadPool.QueueUserWorkItem(StartListening);
while (true) {
Console.Read();
}
}
public void StartListening(Object state) {
// Establish the local endpoint for the socket.
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try {
// Bind the socket to the local endpoint and listen for incoming connections.
listener.Bind(localEndPoint);
listener.Listen(100);
while (true) {
Console.WriteLine("Waiting for a connection...");
// get connection
Socket client = listener.Accept();
// push client to another thread
ThreadPool.QueueUserWorkItem(HandleClient, client);
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
private void HandleClient(Object obj) {
// Get the socket that handles the client request.
Socket client = (Socket)obj;
// Create the state object.
StateObject state = new StateObject();
state.workSocket = client;
try {
while (true) {
int bytesRead = client.Receive(state.buffer);
Console.WriteLine("bytesRead=" + bytesRead);
// remote dc.
if (bytesRead == 0)
break;
String content = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}", content.Length, content);
client.Send(state.buffer, 0, state.buffer.Length, 0);
}
} catch (SocketException e) {
Console.WriteLine("SocketException : {0}", e.ToString());
}
client.Shutdown(SocketShutdown.Both);
client.Close();
}
private void Send(Socket handler, String data) {
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
//handler.BeginSend(byteData, 0, byteData.Length, 0, new AsyncCallback(SendCallback), handler);
}
}
However, when I click on the close button ("x") of the client, server's Receive call throws a SocketException. According to MSDN's Remarks section, this shouldn't happen because I've satisfied both the connection-oriented part (see above) and client shutdown part(see below) conditions.
Client.cs (pseudo):
public class MyClient {
public void Init() {
byte[] bytes = new byte[1024];
Socket sender = null;
try {
IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 11000);
sender = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
while (true) {
// Encode the data string into a byte array.
String input = Console.ReadLine();
byte[] msg = Encoding.ASCII.GetBytes(input);
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes, 0, bytesRec));
}
} catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}", ane.ToString());
} catch (SocketException se) {
Console.WriteLine("SocketException : {0}", se.ToString());
} catch (Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
} finally {
sender.Shutdown(SocketShutdown.Both);
sender.Close();
}
}
}
My shallow understanding of finally blocks is that it will always execute. But it doesn't seem to be the case here.
SO, what did I do wrong here? Should I just catch the exception, close the client socket on the server side and just move on, ignoring it? But I would prefer if an exception were not thrown at all.
I have a TCP server which constantly receives TCP streams from different sources. I have an external event that triggers a stop, and when that happens, the TCP port need to be released. The code below works properly, except for the closure. The close is not releasing the port, and the TCP port is stuck in the listening state. How can I fix this?
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Windows.Forms;
namespace TestTest
{
public class tcpserver
{
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 2097152;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousSocketListener
{
public Form10 m_parent;
Socket parentlistener;
// Incoming data from client.
public static string data = null;
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public void StartListening(Form10 frm10)
{
m_parent = frm10;
try
{
// Data buffer for incoming data.
byte[] bytes = new Byte[2097152];
int port = Convert.ToInt32(m_parent.textBox2.Text.Trim());
IPAddress ipv4 = IPAddress.Parse(m_parent.comboBox1.SelectedItem.ToString().Trim());
IPEndPoint localEndPoint = new IPEndPoint(ipv4, port);
// Create a TCP/IP socket.
parentlistener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
parentlistener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, false);
LingerOption lo = new LingerOption(false, 0);
parentlistener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, lo);
// Setting the array to have this ip and port
m_parent.m_parent.setUsedIPport(
m_parent.comboBox1.SelectedItem.ToString().Trim() +
":" + m_parent.textBox2.Text.Trim());
// Bind the socket to the local endpoint and
// listen for incoming connections.
try
{
parentlistener.Bind(localEndPoint); // THIS IS THE PORT I WOULD LIKE
// TO RELEASE ON AN EXTERNAL TRIGGER
parentlistener.Listen(100);
while (m_parent.getStopState() == false)
{
//MessageBox.Show("L");
allDone.Reset();
//// Start an asynchronous socket to listen for connections.
parentlistener.BeginAccept(
new AsyncCallback(AcceptCallback), parentlistener);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
catch (Exception) {
MessageBox.Show("Error binding to tcp port", "ERROR"); return;
}
}
public void AcceptCallback(IAsyncResult ar)
{
try
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
LingerOption lo = new LingerOption(false, 0);
handler.SetSocketOption(SocketOptionLevel.Socket,
SocketOptionName.Linger,
lo);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize,
0, new AsyncCallback(ReadCallback), state);
}
catch (Exception er) {
//MessageBox.Show(er.ToString());
}
}
public void ReadCallback(IAsyncResult ar)
{
try
{
String line = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
string temporaryString = "";
// Read data from the client socket.
int bytesRead = handler.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));
line = state.sb.ToString(); // This goes into an external
// store, and code is not here
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize,
0, new AsyncCallback(ReadCallback), state);
}
}
}
catch (Exception er) {
//MessageBox.Show(er.ToString());
}
}
public void stopListener()
{
try
{
parentlistener.Shutdown(SocketShutdown.Both);
//parentlistener.Disconnect(true);
parentlistener.Close(); // PROBLEM !!! The code is not releasing
// the port, the tcp port continues to
// remain in the listening state.
parentlistener.Dispose();
}
catch (Exception Ex) {
//MessageBox.Show(Ex.ToString());
}
}
}
}
}
We had this exact problem just a few days ago. In our case we had to set the Linger mode to TRUE (you have it set to false) with a timeout of 0 (which you already have).
It's a bit counter-intuitive, but it worked.
I have a TCP server (implemented as a windows service) for listening to GPS devices in a vehicle tracking application, after random period of time from its operation I got the following error : "Only one usage of each socket address (protocol/network address/port) is normally permitted." While I am sure that I am closing every socket after using it. so can anyone tell me what is the problem here I have the MaxUserPort value in windows server 2008 registry with (65534) and the TCPTimeWaitDelay value with (30 seconds) ?
Here is the code:
1) The Main Thread :
private void MainThread() {
byte[] bytes = new Byte[1024];
IPEndPoint localEndPoint = new IPEndPoint(0, this.port);
Socket listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp );
// Addedd on [20/03/2012] by Sherif Mosaad for handling socket exceptions ...
//listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, (int)1);
try {
listener.Bind(localEndPoint);
listener.Listen(100);
while (active) {
mainDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback),listener);
while (active)
if (mainDone.WaitOne(100, true))
break;
}
listener.Shutdown(SocketShutdown.Both);
listener.Close();
Thread.Sleep(2000);
} catch (Exception e) {
if (OnError != null)
OnError(this, e.ToString());
LogManager.LogError(e, "TCPSimpleServer MainThread");
}
}
2) The AcceptCallback handler:
private void AcceptCallback(IAsyncResult ar) {
mainDone.Set();
Socket listener = (Socket)ar.AsyncState;
Socket handler = null;
try
{
handler = listener.EndAccept(ar);
}
catch
{
try
{
listener.Shutdown(SocketShutdown.Both);
listener.Close();
Thread.Sleep(2000);
}
catch { return; }
}
if (OnConnect != null)
OnConnect(this, handler);
StateObject state = new StateObject();
state.workSocket = handler;
state.endPoint = (IPEndPoint)handler.RemoteEndPoint;
stateObjectDictionary.Add(state, state.workSocket);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
3) The ReadCallback Handler:
private void ReadCallback(IAsyncResult ar) {
String content = String.Empty;
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
int bytesRead = 0;
try
{
bytesRead = handler.EndReceive(ar);
}
catch (Exception e)
{
// Connection closed by client
if (OnDisconnect != null)
OnDisconnect(this, state.endPoint);
return;
}
if (bytesRead > 0)
{
string data = Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
if (OnDataAvailable != null)
OnDataAvailable(this, handler, data);
try
{
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
catch (Exception e)
{
// Connection closed by client
if (OnDisconnect != null)
OnDisconnect(this, state.endPoint);
return;
}
}
else
{
// Connection closed by peer
if (OnDisconnect != null)
OnDisconnect(this, state.endPoint);
}
}
Finally the state object :
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
public IPEndPoint endPoint;
}
Any help please?
There's a race condition. You call mainDone.Set which allows another thread to proceed to BeginAccept while the current thread moves towards EndAccept. Which will get there first? If you start accepting before finishing the previous accept, I suspect this error might pop up.
Fix? You need to set mainDone event after you call EndAccept
Even better, follow a simpler pattern without synchronization primitives. I outline one here.