I want to handle multiple client's request concurrently using Socket Server.
i have 10 clients, which can send request to my server at same time.
How could i handle this?
Is it possible?
With below code, i can handle only one request at a time, after completion of the request, server accepts next request.
Due to this 10th client need to wait until 9 requests get complete.
Any help would be appreciated
Below is the code i am using for Server Socket
Socket _serverSocket;
byte[] _buffer = new byte[255];
void SetupServer()
{
try
{
Console.WriteLine ("Setting up server...");
IPEndPoint ipEndPoint = new IPEndPoint (IPAddress.Parse(_ip), _port);
// create server socket to listen new client's connection
_serverSocket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind (ipEndPoint);
_serverSocket.Listen (100);
_serverSocket.BeginAccept (new AsyncCallback (AcceptCallback), null);
}
catch (System.Exception ex)
{
Console.WriteLine ("Server failed :: {0}", ex.Message);
}
}
void AcceptCallback(IAsyncResult ar)
{
Socket clientSocket = _serverSocket.EndAccept(ar);
_serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallback), clientSocket);
}
void RecieveCallback(IAsyncResult ar)
{
Socket clientSocket = (Socket)ar.AsyncState;
int received = clientSocket.EndReceive(ar);
// check if client is disconnected?
if (received == 0)
{
Console.WriteLine("client is disconnected...");
return;
}
// do whatever you want with received data here...
byte[] dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
string text = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine("Received Data: {0}", text);
// accept new request
clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(RecieveCallback), clientSocket);
}
You should familiarize yourself with the concept of a "multi threaded server". You should start a thread for each client which connects to the server. So you can simultaneously handle multiple clients. Or you could use Tasks Parallel Library if you want to try newer .NET features.
But there are many examples out there in the web that describe how to implement such a server.
Related
I am connecting to a server via TCP socket and sending in strings of data and expecting responses. The responses are unique to the request string and there are two responses per request. One that says the server completed an intermediate task and another indicating the task is complete. These tasks take up to about 20 seconds to complete. Note - I have no access to the server program/code its proprietary.
The client should be able to send in string requests anytime and sometimes fairly quickly. Requests could stack up and the client needs to wait for the unique responses to each request as they are received.
Assuming this needs an asynchronous client I am using the example right from the MS site.
https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-client-socket-example
Developing in a console app, I am able to connect and send string requests and I get one response back. The program then exits. New to async sockets I'm not sure how to keep the socket "alive" or open and randomly Console.Read new strings, send them, and get both responses as they are received.
Here is my client code.
public static Socket ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
// 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
{
// 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;
public static void StartClient()
{
// Connect to a remote device.
try
{
IPEndPoint remoteEP = new IPEndPoint(ip, port);
// Create a TCP/IP socket.
Socket client = new Socket(ip.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
connectDone.WaitOne();
Console.WriteLine("Enter a message string: \n");
message = Console.ReadLine();
// Send test data to the remote device.
Send(client, message + "\r\n"); // \r\n required for server to know end of string
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
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("Connected to: {0}", client.RemoteEndPoint.ToString());
// Signal that the connection has been made.
connectDone.Set();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
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,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
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,
new AsyncCallback(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();
}
// Added this here to see if receiving would continue, does not work
client.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReceiveCallback), state);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void Send(Socket client, String data)
{
// 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, new AsyncCallback(SendCallback), client);
}
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());
}
}
At the very least, you could wrap your read-send-receive logic in a loop:
while (true) {
Console.WriteLine("Enter a message string: \n");
message = Console.ReadLine();
if (message == "quit") break;
// Send test data to the remote device.
Send(client, message + "\r\n"); // \r\n required for server to know end of string
sendDone.WaitOne();
// Receive the response from the remote device.
Receive(client);
receiveDone.WaitOne();
// Write the response to the console.
Console.WriteLine("Response received : {0}", response);
}
I also recommend that you learn how to use the Task asynchronous programming (TAP) model, which is the recommended approach for new development. TAP uses the async and await keywords, along with the Task classes, to achieve asynchronicity in a concise, readable way.
I'm new in StackOverflow and I spent a lot of time searching for a solution for my issue and couldn't found any.
So, I want to test a very simple C# server/multiple client application.
It works fine with clients what have different IP addresses. When I start two clients using the same wi-fi, I have the following socket exception on the server socket.EndReceive line:
"An existing connection was forcibly closed by the remote host"
This is my server code:
class Program {
private static Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
private static byte[] bufferPubblico = new byte[4096];
static void Main(string[] args) {
Console.WriteLine("Setting up server...");
server.Bind(new IPEndPoint(IPAddress.Any, *port*));
server.Listen(1);
server.BeginAccept(new AsyncCallback(AcceptCallback), null);
Console.ReadKey();
}
private static void AcceptCallback(IAsyncResult AR) {
Socket socket = server.EndAccept(AR);
Console.WriteLine("A new client connected");
socket.BeginReceive(bufferPubblico, 0, bufferPubblico.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
server.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
private static void ReceiveCallBack(IAsyncResult AR) {
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] dataBuf = new byte[received];
Array.Copy(bufferPubblico, dataBuf, received);
string text = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine("Text Received: " + text);
socket.BeginReceive(bufferPubblico, 0, bufferPubblico.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
}
}
And this is my client code:
class Program
{
private static Socket socket;
private static byte[] bufferPubblico = new byte[4096];
static void Main(string[] args) {
string ip = Console.ReadLine();
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(ip), *port*);
socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(localEndPoint);
socket.BeginReceive(bufferPubblico, 0, bufferPubblico.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
while (true) {
string messaggio = Console.ReadLine();
byte[] data = Encoding.ASCII.GetBytes(messaggio);
socket.Send(data);
}
}
static void ReceiveCallBack(IAsyncResult AR) {
Socket socket = (Socket)AR.AsyncState;
int received = socket.EndReceive(AR);
byte[] dataBuf = new byte[received];
Array.Copy(bufferPubblico, dataBuf, received);
string messaggio = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine("Text Received: " + messaggio);
socket.BeginReceive(bufferPubblico, 0, bufferPubblico.Length, SocketFlags.None, new AsyncCallback(ReceiveCallBack), socket);
}
}
So, my question is Why when I connect two clients sharing the same IP I get the above exception?
P.S. The two clients that generate the exception have the same IP of the server, i.e. they are started on the same computer.
Post edit:
I solved my issue adding the
Socket.Close()
to close the connection between server and client before ending the application.
I supposed it wasn't so important, but the tcp connection must be closed, otherwise some exceptions occur.
MSDN have an excellent guide on how to create an asynchronous socket server here.
Following this tutorial will certainly help with your en-devours into socket programming(it is copy/paste-able code).
A thing to note with the Socket API, there is a chance not all data is received in OnReceive and as such requires you to check for a string terminator, MSDN uses the example of appending <EOF> to the end of each string you send.
Give that article a good read and see if it doesn't fix your problems.
How can I stop sending message to a client, while client do not read a message from server. To better understand what this means, consider a scenario in which a client does not call Read for an extended period of time, and server stops sending message to this client.
Server.cs receive message from client, and send to all clients
private static void ReceiveCallback(IAsyncResult AR)
{
Socket current = (Socket)AR.AsyncState;
int received;
try
{
received = current.EndReceive(AR);
}
catch (SocketException)
{
Console.WriteLine("Client forcefully disconnected");
current.Close();
clientSockets.Remove(current);
return;
}
byte[] recBuf = new byte[received];
Array.Copy(buffer, recBuf, received);
string text = Encoding.ASCII.GetString(recBuf);
Console.WriteLine("Received Text: " + text);
buffQueue.Enqueue(text);
current.BeginReceive(buffer, 0, BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current);
foreach (var client in clientSockets)
{
foreach (var msg in buffQueue)
{
Sendata(client, text);
}
}
}
static void Sendata(Socket socket, string noidung)
{
byte[] data = Encoding.ASCII.GetBytes(noidung);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
}
private static void SendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
Client.cs
public void ReceiveMessage(IAsyncResult ar)
{
Random rnd = new Random();
Socket socket = (Socket)ar.AsyncState;
int received = socket.EndReceive(ar);
byte[] dataBuf = new byte[received];
Array.Copy(receivedBuf, dataBuf, received);
string msg = Encoding.ASCII.GetString(dataBuf);
Console.WriteLine("> " + msg + '\n');
ClientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None,
new AsyncCallback(ReceiveMessage), ClientSocket);
}
The problem is, that when a client does not read the buffer, the receivebuffer of the client will be full and the server will block in execution. You could prevent this by either:
Queue the data for each client. The client must request data, so the server will send it's queue. (on a different thread)
Use the socket.Blocking = false on the socket on the server. When the server is sending the data and the buffers are full, you'll get an WouldBlock exception or when using the right overload on sending, a SocketErrorCode is returned. Windows Sockets: Blocking. You still need a queue.
The SendData could be done parallel, because the bytebuffer/data doesn't change while sending.
I would like to know if my way of thinking is any good.
Here is sitution:
Server is accepting async for connections. After accept is recieveing async on accepted sockets.
Clients are connecting async to server, then listening for request async.
What I want to do is to send requests from both client and server. Other side should recieve it.
Server code:
public ServerHandler()
{
_serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_serverSocket.Bind(_ipLocal);
_serverSocket.Listen(4);
_serverSocket.BeginAccept(AcceptCallback, null);
}
private void AcceptCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
_clients.Add(socket);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, socket);
_serverSocket.BeginAccept(AcceptCallback, null);
}
private void RecieveCallback(IAsyncResult ar)
{
var socket = (Socket) ar.AsyncState;
var recieved = socket.EndReceive(ar);
var dataBuff = new byte[recieved];
Array.Copy(_buffer, dataBuff, recieved);
OnMessageRecieved(dataBuff);
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, socket);
}
private void Send(byte[] data, Socket socket)
{
socket.BeginSend(data, 0, data.Length, SocketFlags.None,
SendCallback, socket);
}
private void SendCallback(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
private void SendToAll(byte[] data)
{
foreach (var clientSocket in _clients)
{
Send(data, clientSocket);
Debug.WriteLine("sent to: " + clientSocket.LocalEndPoint);
}
}
Client code:
public ClientHandler()
{
_ipLocal = new IPEndPoint(IPAddress.Parse(ServerIp), Port);
}
public void ConnectLoop()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.BeginConnect(IPAddress.Parse(ServerIp), Port, ConnectCallback, null);
_clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback,
_clientSocket);
}
catch (Exception)
{
Debug.WriteLine("Connection attempts: " + attempts);
}
}
Debug.WriteLine("Connected");
}
private void ConnectCallback(IAsyncResult ar)
{
_clientSocket.EndConnect(ar);
}
private void RecieveCallback(IAsyncResult ar)
{
var socket = (Socket) ar.AsyncState;
int recieved = _clientSocket.EndReceive(ar);
var dataBuff = new byte[recieved];
Array.Copy(_buffer, dataBuff, recieved);
OnMessageRecieved(dataBuff);
_clientSocket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, RecieveCallback, _clientSocket);
}
private void Send(byte[] data, Socket socket)
{
socket.BeginSend(data, 0, data.Length, SocketFlags.None,
SendCallback, socket);
}
private void SendCallback(IAsyncResult ar)
{
var socket = (Socket)ar.AsyncState;
socket.EndSend(ar);
}
Will sth like this work?
EDIT1: Oh, and I want to do it through 1 socket. Client/server sending and recieveing on same socket. But there can be multiple clients sockets, but only 1 for pair client-server.
Without testing, your code looks alright however, you'll need to provide extra code to determine if you've got a whole message or not.
When you do a read, you may get one of the following scenarios:
Some of a message, but not all
exactly all of a message
all of a message plus some/all of another message
a socket error (disconnected etc).
There are a few generally accepted methods of determining what a whole message is:
delimiting your message so your receival code needs to look for the delimiters
A fixed message size with some sort of embedding to indicate if there are more messages
a variable message size but with a fixed "size" part which is transmitted first Ie say the first 4 bytes will indicate the size of the message. So you know you always need 4 bytes first to determine the length of the message; and then you know how much to process for the next message.
This SO post Chat service application has some more and links on processing messages.
I have a simple C#/.NET 3.5 client/server apps I am trying to write to get a handle on how to communicate in UDP. I am able to get the sync methods working and sending data back and forth, but now I am trying to switch to the async methods and I keep getting the error, "The requested address is not valid in it's context."
My Client code is as follows:
IPEndPoint ipep = new IPEndPoint(ipaddr, ipport);
newsock = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
EndPoint remote1 = (EndPoint)ipep;
AddMessage("Looking for connections");
byte[] strt = Encoding.ASCII.GetBytes("open");
newsock.SendTo(strt,remote1);//.BeginSendTo(strt, 0, strt.Length, SocketFlags.None, remote1, new AsyncCallback(OnSend), null);
IPEndPoint ipeSender = new IPEndPoint(IPAddress.Any, 0);
EndPoint epSender = (EndPoint)ipeSender;
newsock.ReceiveFrom(rcv, ref epSender);
My Server is more complicated, as I have already switched to Async communication.
In a worker thread I call:
try
{
IPEndPoint sender = new IPEndPoint(IPAddress.Any, 0);
EndPoint remote = (EndPoint)sender;
AddMessage("Beginning Wait for connections");
newsock.BeginReceiveFrom(rcv, 0, rcv.Length, SocketFlags.None, ref remote, new AsyncCallback(OnReceive), null);
while (true)
{
if (pleasestop.WaitOne(20))
break;
ts = DateTime.Now - lastnoop;
if (senddata)
{
//...fill sending byte array...
IPEndPoint ipep = new IPEndPoint(IPAddress.Any,0);//ipaddr, ipport);
EndPoint remote1 = (EndPoint)ipep;
newsock.BeginSendTo(sending, 0, sending.Length, SocketFlags.None, remote1, new AsyncCallback(OnSend), null);
}
}
In my OnSend callback function is where I get the error: "The requested address is not valid in it's context."
private void OnSend(IAsyncResult ar)
{
try
{
newsock.EndSendTo(ar);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "\n" + ex.StackTrace, "Server Send Error");
}
}
I dont think the object state can be null, try this:
newsock.BeginSendTo(sending, 0, sending.Length, SocketFlags.None,
remote1, new AsyncCallback(OnSend), newsock);
I found my problem. I wasn't using the correct EndPoint in my server to send a response back to my client.
In my receive callbackup function I now use mySender, which is a SendPoint defined at the class level. I then use this to send a response back to my client.
newsock.EndReceiveFrom(ar, ref mySender);
newsock.BeginSendTo(sending, 0, sending.Length, SocketFlags.None, mySender, new AsyncCallback(OnSend), mySender);
My app is now working correctly.