Multiple clients with Server Application more than 15 clients handling issue - c#

I have a Server Application written in C# .NET and running on Windows XP SP3.
I am using asynchronous sockets programming for handling around 500 clients.
But I got a problem to entertain more than 15 client connections.
My application got shut down when 1 more client connected after 15 clients; I am not
understanding whether the problem is with my OS or is a tcp connection limitation problem in Windows XP.
Please help to solve out this issue, please suggest any solution.
Update:
Here is my piece of code.
public const int MAX_CLIENTS = 200;
public AsyncCallback pfnWorkerCallBack;
private Socket[] m_workerSocket = new Socket[MAX_CLIENTS];
// class for worker socket & callback method & data buffer
private SocketPacket[] m_workerSocketPkt = new SocketPacket[MAX_CLIENTS];
// page Load
m_mainSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 4321);
// Bind to local IP Address...
m_mainSocket.Bind(ipLocal);
// Start listening...
m_mainSocket.Listen(MAX_CLIENTS);
m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
// called when client is connected
public void OnClientConnect(IAsyncResult asyn)
{
try
{
m_clientCount = setclient();
SocketPacket abc = new SocketPacket();
m_workerSocketPkt[m_clientCount] = abc; //assigning with SocketPacket class
m_workerSocketPkt[m_clientCount].m_currentSocket =
m_mainSocket.EndAccept(asyn); //transferring connection to other thread
m_workerSocketPkt[m_clientCount].m_clientCount = m_clientCount;
m_workerSocketPkt[m_clientCount].templist = abcde; //assigning Amj (list) class
m_workerSocket[m_clientCount] = m_workerSocketPkt[m_clientCount].m_currentSocket;
pfnWorkerCallBack = new AsyncCallback(m_workerSocketPkt[m_clientCount].OnDataReceived); //defining AsynCallBack function for the accepted socket
m_workerSocketPkt[m_clientCount].oldpfnWorkerCallBack = pfnWorkerCallBack;
m_workerSocketPkt[m_clientCount].data_rec = false;
m_workerSocketPkt[m_clientCount].data_sent = false;
m_workerSocketPkt[m_clientCount].m_currentSocket.BeginReceive(
m_workerSocketPkt[m_clientCount].dataBuffer, //assigning data buffer for receiving for the socket
0, //assigning data buffer offset for receiving for the socket
m_workerSocketPkt[m_clientCount].dataBuffer.Length, //assigning maximum data length for receiving for the socket
SocketFlags.None, //socket flags
pfnWorkerCallBack, //AysnCallBack delegate
m_workerSocketPkt[m_clientCount].m_currentSocket //state
);
m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null); //start invitation for other new sockets
}
The Max Client Value is here 200 and worker sockets also, so it should handle 200 clients but I think it's creating a problem in receiving data from more than 15 clients because every client that is connected is continuously connected and sends data to the server.

Increase the m_workerSocketPkt array (or m_workerSocket) to more than 15 or convert it to a List<>. (I'm guessing since you did not show it's declaration)

Your even the most basic Windows XP system should be able to handle 1000 connections. TCP is allows thousands of connection per client machine. (I wouldn't suggest more than 100K per server)
If your program is failing its likely to be a bug in your code. Is possible it producing an error your are ignoring? What is the error your program gets?

Related

Socket-Listener only works for the first time, at second time the connection gets refused

I am a C#/WPF developer and have not many experience in network-communication (socket/tcp) and just trying to get a simple working example for a TCP-Listener-project for exchanging messages between server and client.
I think Im nearly there where I want to come to, but have an open issue left: When I start the server and after that the client, the messages get exchanged like wanted. After that I close the client and restart it, the second connection gets refused (at "await client.ConnectAsync(ipEndPoint)") with following message (sorry, its translated from german to english):
"A connection could not be established because the target computer refused the connection"
Do you maybe have any hint for me, what I am doing wrong? I also tried closing clients connection in the client app, but same behaviour.
Server-code:
public async Task<bool> StartServer()
{
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, 8888);
using Socket listener = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
listener.Bind(ipEndPoint);
listener.Listen(100);
Socket client = await listener.AcceptAsync();
while (true)
{
var buffer = new byte[1_024];
var received = client.Receive(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
var eom = "<|EOM|>";
if (response.IndexOf(eom) > -1 /* is end of message */)
{
AddLogText($"Socket server received message: \"{response.Replace(eom, "")}\"");
var ackMessage = "Hallo Client!<|ACK|>";
var echoBytes = Encoding.UTF8.GetBytes(ackMessage);
await client.SendAsync(echoBytes, 0);
AddLogText($"Socket server sent acknowledgment: \"{ackMessage}\"");
break;
}
}
client.Shutdown(SocketShutdown.Both);
client.Close();
return true;
}
Client Code:
private async Task<bool> StartClient()
{
IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("127.0.0.1");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint ipEndPoint = new(ipAddress, 8888);
using Socket client = new(
ipEndPoint.AddressFamily,
SocketType.Stream,
ProtocolType.Tcp);
await client.ConnectAsync(ipEndPoint);
while (true)
{
var message = "Hallo Server?<|EOM|>";
var messageBytes = Encoding.UTF8.GetBytes(message);
_ = await client.SendAsync(messageBytes, SocketFlags.None);
Console.WriteLine($"Socket client sent message: \"{message}\"");
var buffer = new byte[1_024];
var received = await client.ReceiveAsync(buffer, SocketFlags.None);
var response = Encoding.UTF8.GetString(buffer, 0, received);
if (response.Contains("<|ACK|>"))
{
Console.WriteLine($"Socket client received acknowledgment: \"{response}\"");
break;
}
}
return true;
}
Your StartServer method returns after the first client socket finishes, disposing the listening socket.
Usually, you want to keep the listening socket open and listening, and call AcceptAsync in an infinite loop.
But I have to caution you: socket programming is extremely difficult. For example, your socket reading code is far too simplistic to properly handle message framing. I recommend self-hosting ASP.NET or something else that handles the protocol-level details for you.
You might have misunderstood how the server works. It should be like this:
Create a socket and call Bind and Listen. This part is okay.
Call Accept, which waits for a client to connect, and then returns a socket connected to that specific client.
Send and receive data from the client.
If you want to wait for another client, after you are done with the first one, then of course you need to call Accept again.
It is also common for servers to handle several clients at the same time, for example by using threads (or async). One thread just calls Accept over and over, and whenever a new client connects, it starts a new thread to handle that client. You don't need this for a toy program, that only handles one connection at a time. But you do need it for a real server, otherwise one client can connect, and be really slow, and your server won't handle any other clients while that is happening.
If you are not doing a "graceful close" there is no need to call Shutdown - you can just Close the client's socket to disconnect the client. When you Close the main server socket you stop accepting new connections. Shutdown doesn't apply to the main server socket.

C# SocketException Can not connect because the target machine has actively declined the connection

I'm trying to write a chat client/server in c# locally to get familiar with Sockets.
First I start the server with (very simplified) following code:
Server.cs
private readonly MessageManager _messageManager;
private readonly ChatServer _chatServer;
public ChatServerSkeleton()
{
_messageManager = new MessageManager();
_chatServer = new ChatServer();
Console.WriteLine("Server is running on: " + _messageManager.MyAddress);
}
Then I start the Client with +- same way, except I store the serveraddress in the client (I copied the server address into a prompt).
Client.cs
private readonly MessageManager _messageManager;
public ChatClient ChatClient { get; }
public ChatClientSkeleton(IPEndPoint serverAddress, string name)
{
_messageManager = new MessageManager();
ChatClient = new ChatClient(new ChatServerStub(serverAddress, _messageManager), name);
Console.WriteLine($"IPAddress of {name} is: {_messageManager.MyAddress}");
Console.WriteLine($"IPAddress of Server is: { serverAddress}");
}
MessageManager.cs
private readonly TcpListener _serverSocket;
public IPEndPoint MyAddress { get; }
public MessageManager()
{
try
{
//Create server socket on random port
_serverSocket = new TcpListener(IPAddress.Any, FindFreeTcpPort());
//Get host ip address
IPAddress[] localIps = Dns.GetHostAddresses(Dns.GetHostName());
IPAddress localhost = localIps.First(ip => ip.AddressFamily == AddressFamily.InterNetwork);
//Get port of serversocket
IPEndPoint ipEndPoint = _serverSocket.LocalEndpoint as IPEndPoint;
int port = ipEndPoint.Port;
//Create address
MyAddress = new IPEndPoint(localhost, port);
}
catch (Exception ex)
{
Console.Error.WriteLine("Something went wrong with the serversocket:");
Console.Error.WriteLine(ex);
}
}
FindFreeTcp port comes from here: https://stackoverflow.com/a/150974/5985593
Everything up till now seems to work. Let's say for example the server has now 192.168.0.219:51080 and the client 192.168.0.219:51085.
The problem occurs when I'm trying to send a message using this code in MessageManager.cs
public void Send(MethodCallMessage message, IPEndPoint address)
{
try
{
_serverSocket.Start();
TcpClient destination = new TcpClient(address.Address.ToString(), address.Port);
NetworkStream output = destination.GetStream();
MessageReaderWriter.Write(message, output);
destination.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine("Failed to write a message:");
Console.Error.WriteLine(ex);
}
finally
{
_serverSocket.Stop();
}
}
More specific on the _server.Start(); line.
Anyone knows what I'm doing wrong?
Thanks in advance!
EDIT: it runs fine 1 time, when registering the client on the server. But after that if I want to send a message I get the SocketException where target machine actively refused.
I do use AcceptTcpClient() here:
MessageManager.cs
public MethodCallMessage WReceive()
{
MethodCallMessage result = null;
try
{
//_serverSocket.Start();
TcpClient client = _serverSocket.AcceptTcpClient();
NetworkStream input = new NetworkStream(client.Client, true);
result = MessageReaderWriter.Read(input);
client.Close();
}
catch (Exception ex)
{
Console.Error.WriteLine("Failed to receive a message:");
Console.Error.WriteLine(ex);
}
finally
{
//_serverSocket.Stop();
}
return result;
}
This method is used in the ServerSkeleton & ClientSkeleton as follows:
public void Run()
{
while (true)
{
MethodCallMessage request = _messageManager.WReceive();
HandleRequest(request);
}
}
So the flow is basically as follows:
I start the server (instantiate new messagemanager, 3rd snippet
and run serverskeleton (last snippet)
Server prints IP in
console, i copy the ip & start the client
Instantiate client &
set server ip to what I copy pasted
Start client skeleton (last
snippet)
A TcpListener that has called Start() listens for incoming connections and then stacks them on a queue. Once that queue is full then a socket exception results. To remove connections from the queue you need to use the AcceptTcpClient or AcceptSocket methods of TcpListener. This then gives you a connection that you can send and receive data on.
What I am guessing may be happening is that you receive your first incoming client, but dont accept and remove it to send and receive data on, and your subsequent connections are refused as the pending queue list is full (this is just a guess).
There is an overloaded method ... TcpListener.Start(int backlog) ... that allows you to set the size of the pending queue list (so you can have 5, 10 or more connections waiting to be accepted in the TcpListener)
With a server TCP socket the process is that you set it listening on a local address and a port. Clients then try to connect to that endpoint. When they connect the TCP listening socket accepts the connection and then passes that to a socket which is the socket on which data is transfered. The listening socket carries on listening for new connections, it doesnt itself transmit data.
I hope that makes sense ?
So the server would behave more like this ...
_serverSocket.Start();
TcpClient myAcceptedConnection = _serverSocket.AcceptTcpClient();
// in synchronous blocking socket situation the program flow halts
// here til a connection is established
// once you have a connection ... do stuff with myAcceptedConnection
if you wished to avoid the blocking scenario you can use TcpListener.Pending() to see if you have any connections waiting in the queue
EDIT 1:
Ok so the only weird thing I see is that you call the _serverSocket.Start() method in the MessageSend method ? A server doesnt normally start by sending out a message ... it normally waits listening for a connection, receives and reads the connection and then replies (or it might send out a greeting or such on connection).
Personally I would separate the listening aspect of the server from the sending and receiving of data ... have it in its own separate method, after all you want your server to be listening for incoming connections until you close it down. When you detect an incoming connection (perhaps by checking Pending() in a loop), then you can accept it and send and receive on the new TcpClient. When you are finished with whatever data you are transmitting/receiving on that client you can close it down , if thats what you want ... you dont need to close and open a tcp connection every time you send a message, you can leave it open til you are finished with it, in fact opening and closing tcp connections generates a bit of overhead in the handshake protocol that they go through.
There are caveats though ... Tcp connections can become "half open" especially with wireless which can lead to issues. Its a bit complicated to get into here, but I recommend this stellar set of articles by Stephen Cleary as a good read through. Read the whole blog, as there is a ton of good info in there.
So, back to simple, I would have ...
A serverStart() method where you start your server listening.
A serverAccept() method where you check if you have any pending connections and accept them if they are there.
A clientConnect() method for your client where you connect to a server
Read() and Write() methods for the server and the client where you do the data transmission.
Normally the flow would be ...
Server Listens
Client Connects
Server Accepts
Client Sends
Server Receives
(then server sends/receives, client sends/receives)
everything closes and shuts down

Is there any way to improve TCP connection time?

I wrote a TCP server to use the BeginAccept/EndAccept pattern. With this, I coded up a simple UnitTest using a TcpClient, and measured each portion. All tests are localhost, so I am surprised to see that TCP connection is consistently taking 1 second. I have set the Socket.NoDelay = true although I believe this only affects Send/Receive. I am not receiving the first packet of data. Any help or ideas on speed this up are appreciated.
Note: I can not change the client side to keep the connection open, and I need to be able to handle a lot of requests per second if possible.
Server Side:
public void Start()
{
System.Net.IPHostEntry localhost = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
System.Net.IPEndPoint endpoint;
int port = Properties.Settings.Default.ListenPort;
//
// Setup the connection to listen on the first IP, and specified port
//
endpoint = new IPEndPoint(IPAddress.Any, port);
listenSocket = new Socket(endpoint.Address.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(endpoint);
listenSocket.NoDelay = true; // do not wait 200 milliseconds for new data to be buffered on the connection
listenSocket.Listen(int.MaxValue);
Console.WriteLine("Listening on {0}:{1}", localhost.AddressList[0], port);
//
// Post the accept. The accept method will continuously post a new accept as soon as a connection is made
//
while (true)
{
accepted.Reset();
Connection connection = connections.Pop();
listenSocket.BeginAccept(AcceptCallback, connection);
accepted.WaitOne();
}
}
private static void AcceptCallback(IAsyncResult ar)
{
accepted.Set();
Connection connection = ar.AsyncState as Connection;
Socket remoteSocket = null;
try
{
remoteSocket = listenSocket.EndAccept(ar);
remoteSocket.NoDelay = true;
connection.RemoteSocket = remoteSocket;
//
// Start the Receive cycle
//
Receive(connection);
}
catch (SocketException)
{
Disconnect(connection);
}
}
Simple Test Client:
[TestMethod()]
public void ClientTest()
{
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient("localhost", 10300);
NetworkStream stream = client.GetStream();
TestContext.EndTimer("Connection");
...
Using a LoadTest I loaded 25 users, and the Transaction "Connection" always takes above 1 second.
Not sure why, but simply changing this:
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient("localhost", 10300);
TestContext.EndTimer("Connection");
To this:
TestContext.BeginTimer("Connection");
TcpClient client = new TcpClient();
client.Connect("localhost", 10300);
TestContext.EndTimer("Connection");
Drops the time from 1 second to .13 seconds. Will have to investigate as to why, but hopefully this will help somebody out in the future.
When you attempt to connect using the TcpClient constructor on a host that resolves to both Ipv6 and Ipv4 addresses, the connection using Ipv6 is attempted first. If it fails then it attempts to connect using the Ipv6 address. This is the cause of the 1 second delay. Here is the MSDN link:

select() function in C#

im new to C# and any help/feedback would be appreciated. im trying to develop a a client-server program in c#, however i do have different clients sending information to the server side. Is there any function similar to the c language select() such that can help to get all the information from every client side in C#?
here is my server side code:
// Create the listening socket...
m_mainSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, 9051);
// Bind to local IP Address...
m_mainSocket.Bind(ipLocal);
// Start listening...
m_mainSocket.Listen(10);
Socket clientSock = m_mainSocket.Accept();
byte[] clientData = new byte[1024];
int receivedBytesLen = clientSock.Receive(clientData);
string clientDataInString =
Encoding.ASCII.GetString(clientData, 0, receivedBytesLen);
string clientStr = "Client Data Received: " + clientDataInString;
byte[] sendData = new byte[1024];
sendData = Encoding.ASCII.GetBytes(clientStr);
clientSock.Send(sendData);
clientSock.Close();
There are higher level constructs, but if you want to get pretty low level, you are probably looking for Socket.Accept:
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.accept.aspx
You want to accept connections from more than one client, so you have to call the blocking Accept method again after acception a connection:
while (true)
{
var clientSocket = s.Accept();
beginReceive(clientSocket);
}
After accepting you might want to start receiving data in an async manner:
private static void beginReceive(Socket clientSocket)
{
byte[] buffer = new byte[1000];
clientSocket.BeginReceive(
buffer, 0, 1000, SocketFlags.None, OnReceiveData, clientSocket);
}
And finally here is the callback method which is called by the framework on another thread when data arrives. You have to finish the async call with EndReceive:
private static void OnReceiveData(IAsyncResult ar)
{
int bytesReceived = ((Socket) ar.AsyncState).EndReceive(ar);
// process data...
}
Of cause you have to store your buffer somewhere else and maintain one receive buffer per client. Maybe you should write an own class for managing a connected client.
Here is a code project with some nice diagrams and examples. The underlying "select" is handled by the .NET framework so you have to think / work at a higher level.
At a high level you socket.accept create a thread to process the connection.
http://msdn.microsoft.com/en-us/library/system.net.sockets.socket.accept.aspx
http://www.codeproject.com/KB/IP/dotnettcp.aspx

reading messages from Device over gprs

i have a GPS device that will be installed in many trucks.
i can configure the device to send data statement "gps data, device id" over gprs to IP and Port.
i'm using TcpListener class to read the data on the server side.
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
Byte[] bytes = new Byte[256];
String data = null;
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.Write("Connected!");
data = null; int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
}
}
that method is listening to what is coming on server ip and port.
i want to know if i configured the devices to send to the server on the same port.am i able to listen to all the devices or the first device to connect will be the only one ?
is this method the the best way to read the coming data from the devices?
do i need to configure a different port for each device and create a new listen thread for each device port?
sometimes i'm facing exceptions "the request channel timed out while waiting for a reply"
many thanks in advance for your help.
In your code you are listening to the all devices but only after finish read all data from the first device so you are receiving "the request channel timed out while waiting for a reply".You should have a different threads each one handle a tcpClient.
so the code should be something like:
TcpListener server = null;
private void listen_data()
{
Int32 port = controller_port;
IPAddress localAddr = IPAddress.Parse(this_ip);
server = new TcpListener(localAddr, port);
server.Start();
while (true)
{
Console.Write("Waiting for a connection...-- ");
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("new client connected");
ThreadPool.QueueUserWorkItem(new WaitCallback(HandleClient), client);//or use Task if 4.0 or new Thread...
}
}
private void HandleClient(object tcpClient)
{
TcpClient client = (TcpClient)tcpClient;
Byte[] bytes = new Byte[256];
String data = null;
int i;
NetworkStream stream = client.GetStream();
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
}
Console.WriteLine(data);
}
1) Both. You should be able to listen for all devices, but you often cannot with your code because the listener thread is tied up waiting for the stream from a device that connected earlier.
2) Probably not. IIRC, NetworkStream.Read returns 0 when the connection is closed by the peer device. Is this your protocol - ie. the device connects, sends some data and disconnects? If so that will work, though slowly. Anyway, there is another problem. You should be concatenating the bytes received on your stream to data, not just replacing them - Read() my return multiple times for one communication, perhaps even with a single byte each time, (unlikely, but permitted with TCP streams). You could keep a count of bytes rx. so far and use the 'offset' parameter to do this.
3) You only need one listening thread, ie. the one that calls AcceptTcpClient(). This thread should not be making blocking calls to receive data from the socket returned by AcceptTcpClient(). Either create/allocate/depool/whatever a new client-server thread to run your Read() loop for each 'client' socket returned by AcceptTcpClient() or use asynchronous IO.
4) Your single listener/read thread will be non-responsive for new connections while it is waiting on the NetworkStream - other devices will be unable to connect. The listener should get back to AcceptTcpClient() quickly and not wait for slow networks/devices to send data.
Rgds,
Martin

Categories