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.
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 have a simple asynchronous socket server written in C# (pretty much Microsoft's example), however the issue with this example is that it accepts only one message from a client and then shuts down. I want this server to stay alive after receiving any message.
This question has been asked before here, and the answer & comments explain that the resolution to this is simply to call handler.beginReceive within the SendCallback function, however to do this requires passing in a state variable. This is something I am unsure of doing with Async programming as I'm pretty new to it.
With the example below, how can I carry my state object from the Send function to the SendCallback function?
Server code:
// Asynchronous Server Socket Example
// http://msdn.microsoft.com/en-us/library/fx6588te.aspx
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
// State object for reading client data asynchronously
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class GetState
{
}
public class AsynchronousSocketListener
{
// Thread signal.
public static ManualResetEvent allDone = new ManualResetEvent(false);
public AsynchronousSocketListener()
{
}
public static void StartListening()
{
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// The DNS name of the computer
// running the listener is "host.contoso.com".
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static void AcceptCallback(IAsyncResult ar)
{
// 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);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
public static 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)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content != null)
{
// All the data has been read from the
// client. Display it on the console.
Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",
content.Length, content);
// Echo the data back to the client.
Send(handler, content, state);
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
}
}
}
private static void Send(Socket handler, String data, StateObject state)
{
// Convert the string data to byte data using ASCII encoding.
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);
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
Console.WriteLine("Sent {0} bytes to client.", bytesSent);
/// ******* WIP ******** //
//handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
//handler.Shutdown(SocketShutdown.Both);
//handler.Close();
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args)
{
StartListening();
return 0;
}
}
This is how I would do it:
public class AsynchronousSocketServer
{
private Socket listener;
private byte[] buffer = new byte[8192]; // Buffer to store data from clients.
public void StartListening()
{
listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(localIPAddress, listeningPort));
listener.Listen(20);
listener.BeginAccept(OnSocketAccepted, null);
}
private void OnSocketAccepted(IAsyncResult result)
{
// This is the client socket, where you send/receive data from after accepting. Keep it in a List<Socket> collection if you need to.
Socket client = listener.EndAccept(result);
// Pass in the client socket as the state object, so you can access it in the callback.
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, client); // Start receiving data from this client.
listener.BeginAccept(OnSocketAccepted, null); // Start a new async accept operation to accept incoming connections from other clients.
}
private void OnDataReceived(IAsyncResult result)
{
// This is the client that sent you data. AsyncState is exactly what you passed into the state parameter in BeginReceive
Socket client = result.AsyncState as Socket;
int received = client.EndReceive(result);
// Handle received data in buffer, send reply to client etc...
// Start a new async receive on the client to receive more data.
client.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, OnDataReceived, client);
}
}
As you can see it's pretty much a lot of recursive callbacks. The basic idea is that you call BeginAccept to start accepting the first connection, then once your callback fires you accept the connection with EndAccept and start a new BeginAccept to start accepting more connections. This same logic applies to BeginReceive and EndReceive when you start communicating with the clients. With this logic the server will continuously accept incoming connections and clients will also be able to continously send data to server.
In your example you get your listener from the AsyncState but you didn't call BeginAccept again to accept more incoming connections, which probably explains why your server only accepts 1 connection and shuts down.
For the state parameter in BeginSend, you can actually just put your BeginReceive right after your Send() method to save yourself the hassle:
Send(handler, content, state);
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReadCallback), state);
It's much better to just fire up a background thread and use blocking calls.
Here's a TcpServer using the TcpListener and NetworkStream
public class TcpServer
{
public void Run(string address, int port)
{
var listener = new TcpListener(IPAddress.Parse(address), port);
listener.Start();
while (true)
{
TcpClient tcpclient = null;
NetworkStream netstream = null;
try
{
tcpclient = listener.AcceptTcpClient();
Console.WriteLine("Client connected from " + tcpclient.Client.LocalEndPoint.ToString());
netstream = tcpclient.GetStream();
var responsewriter = new StreamWriter(netstream) { AutoFlush = true };
while (true)
{
if (IsDisconnected(tcpclient))
throw new Exception("Client disconnected gracefully");
if (netstream.DataAvailable) // handle scenario where client is not done yet, and DataAvailable is false. This is not part of the tcp protocol.
{
string request = Read(netstream);
Console.WriteLine("Client sent: " + request);
responsewriter.Write("You sent: " + request);
}
}
}
catch (Exception ex)
{
netstream.Close();
tcpclient.Close();
Console.WriteLine(ex.Message);
}
}
}
private bool IsDisconnected(TcpClient tcp)
{
if (tcp.Client.Poll(0, SelectMode.SelectRead))
{
byte[] buff = new byte[1];
if (tcp.Client.Receive(buff, SocketFlags.Peek) == 0)
return true;
}
return false;
}
private string Read(NetworkStream netstream)
{
byte[] buffer = new byte[1024];
int dataread = netstream.Read(buffer, 0, buffer.Length);
string stringread = Encoding.UTF8.GetString(buffer, 0, dataread);
return stringread;
}
}
To run it
static void Main()
{
ThreadPool.QueueUserWorkItem(w => {
var asyncserver = new TcpServer();
asyncserver.Run("192.168.0.7", 5055); // or whatever your local IP Address is
});
Console.WriteLine("Press [Enter] to quit");
Console.ReadLine();
}
I have some weird problem with two c# server sockets.
I have 2 servers. One is asynchronous and second is synchronous. I have also client in android which sends picture to this servers.
Synchronous Server:
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public void Start()
{
byte[] bytes = new Byte[1024000];
String content = String.Empty;
IPAddress ipAddress = IPAddress.Parse("192.168.1.2");
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 53100);
try
{
listener.Bind(localEndPoint);
listener.Listen(10);
while (true)
{
//// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
data = null;
// An incoming connection needs to be processed.
while (true)
{
bytes = new byte[1024000];
int bytesRec = handler.Receive(bytes);
strBuilder.Append(Encoding.ASCII.GetString(bytes, 0, bytesRec));
if (strBuilder.Length > 1)
{
content = strBuilder.ToString();
byte[] xdata = Convert.FromBase64String(content);
using (var mStream = new MemoryStream(xdata, 0, xdata.Length))
{
pictureBox1.Image = Image.FromStream(mStream, true);
}
}
}
byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Form1_Load(object sender, EventArgs e)
{
thr = new Thread(new ThreadStart(Start));
thr.Start();
}
Asynchronous Server:
public void StartListening()
{
listener.Bind(new IPEndPoint(IPAddress.Parse("192.168.1.2"), 53100));
listener.Listen(1);
allDone.Reset();
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
public void AcceptCallback(IAsyncResult ar)
{
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
StateObject stateObj = new StateObject();
stateObj.clientSocket = handler;
handler.BeginReceive(stateObj.buffer, 0, StateObject.buffSize, 0,
new AsyncCallback(ReadCallback), stateObj);
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
}
public void ReadCallback(IAsyncResult ar)
{
String content = String.Empty;
StateObject stateObj = (StateObject)ar.AsyncState;
Socket handler = stateObj.clientSocket;
SocketError errorCode;
int bytesRead = handler.EndReceive(ar, out errorCode);
if (errorCode != SocketError.Success)
{
bytesRead = 0;
}
if (bytesRead > 0)
{
stateObj.strBuilder.Append(Encoding.ASCII.GetString(stateObj.buffer, 0, bytesRead));
handler.BeginReceive(stateObj.buffer, 0, stateObj.buffer.Length, SocketFlags.None, new AsyncCallback(ReadCallback), stateObj);
}
else
{
if (stateObj.strBuilder.Length > 1)
{
content = stateObj.strBuilder.ToString();
Debug.WriteLine(content);
byte[] data = Convert.FromBase64String(content);
using (var mStream = new MemoryStream(data, 0, data.Length))
{
pictureBox1.Image = Image.FromStream(mStream, true);
}
recImage = (Bitmap)pictureBox1.Image;
imgImage = new Image<Bgr, Byte>(recImage);
imageBox1.Image = imgImage;
while (imageBox1.Image != null)
{
SURFDetectionAndGUIUpdate(this, new EventArgs());
}
string xname = name.ToString();
Send(handler, xname);
}
}
}
private void Send(Socket handler, String data)
{
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
private void SendCallback(IAsyncResult ar)
{
try
{
Socket handler = (Socket)ar.AsyncState;
int bytesSent = handler.EndSend(ar);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
The problem is that when I send picture from client to synchronous server everything works and server receives it, but if I send picture from the same client to asynchronous server it doesn't receive it.
Currently your synchronous server attempts to create a bitmap from the data of the first Receive, and the asynchronous server waits until the client disconnects before trying to create a bitmap from the data.
TCP streams data, which means that you can read data as it arrives, in the order it was sent, but sending 1000 bytes doesn't mean you'll receive 1000 bytes at once. You could even receive data from two different message in a single Receive operation. The more data you send, and the more times you send data, the bigger the chance that this effect will occur.
In the comments you mention that the client is going to send multiple images, so before you continue you should decide how you want to determine when the first image is received and when data for the second image starts:
You could choose to let the client disconnect after sending each image, as the asynchronous server currently expects
You could choose to first send the number of bytes of an image, before sending the image data itself. Make sure the size itself is encoded at a fixed length. This prevents you from having to reconnect all the time, and also allows you to predetermine the size of the receive buffers
Or you could delimit the data using a byte outside the base64 range, but this requires scanning through the received data
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.
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.