I followed link to create an Async TCP server. However, all examples cover only sending data as a response to receive. My question is how to Push data to a certain TCP client.
Let us say tat a byte[] needs to be sent/pushed to client Id 1.
How can I achieve this using SocketAsyncEventArgs architecture?
I know I have to keep a list of active connections and client ids. What should this list look like in order to push data?
public bool Send(Socket socket, byte[] message)
{
SocketAsyncEventArgs completeArgs = new SocketAsyncEventArgs();
if (socket.Connected)
{
// Prepare arguments for send/receive operation.
completeArgs.SetBuffer(message, 0, message.Length);
completeArgs.UserToken = socket;
completeArgs.AcceptSocket = socket;
completeArgs.Completed += new EventHandler<SocketAsyncEventArgs>(OnIOCompleted);
// Start sending asyncronally.
socket.SendAsync(completeArgs);
}
return true;
}
Related
I'm writing a C# program that needs to send the same data to multiple specific recipients. I can't use multicast because that sends the data to everyone listening on the multicast address.
My current solution is to just iterate through the recipients and send the data to each of them separately but I'm looking for something a little more efficient.
Here's my current solution:
public void SendToMultiple(IPAddress[] Recipients, byte[] Data)
{
UdpClient Client = new UdpClient();
foreach(IPAddress Recipient in Recipients)
{
Client.Send(Data, Data.Length, new IPEndPoint(Recipient, PORT));
}
Client.Close();
}
To the best of my knowledge you can either use Unicast, Multicast or Broadcast.
Since you are only interested in sending to a particular set of clients, I can only recommend Unicast as the other two will send to those also listening.
The only thing I can think of to make it more efficient is to put the code in maybe a Parallel.Foreach loop and create the UdpClient in there and then send the data out?
public void SendToMultiple(IPAddress[] Recipients, byte[] Data)
{
Parallel.ForEach(Recipients,
Recipient =>
{
UdpClient Client = new UdpClient();
Client.Send(Data, Data.Length, new IPEndPoint(Recipient, PORT));
Client.Close();
});
}
I believe what I am looking to create is a service that listens to a specific port, and when data is sent to that port, it sends off that data to another script for processing.
For some reason though, the service times out when I try to start it. My logs tells me TcpClient client = server.AcceptTcpClient(); is where it is stopping (actually, it is getting stuck on 'starting' in Services).
Since I have no experience with C#, making services, or working with servers in this manner, the code is pretty much just what I found online.
The OnStart method looks like this.
protected override void OnStart(string[] args)
{
try
{
TcpListener server = null;
// Set the TcpListener on port 13000.
Int32 port = 1234;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
String data = null;
// Enter the listening loop.
while (true)
{
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
data = null;
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
// Process the data sent by the client.
data = data.ToUpper();
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
// Send back a response.
stream.Write(msg, 0, msg.Length);
}
// Shutdown and end connection
client.Close();
}
}
catch (SocketException e)
{
}
finally
{
}
}
As per MSDN, TcpServer.AcceptTcpClient blocks, so you're probably never returning from your Service's OnStart method, which causes the service to never actually "start".
You might consider using another thread and return from OnStart as soon as possible.
Cheers
As far as creating the Windows service itself, you should be able to use this link, even though it's dated. This companion link shows how to have the service install and uninstall itself. Finally, use this link to understand how to have your service run constantly and how to properly respond to start and stop commands.
To have your service interact with the socket, you'll want to modify the WorkerThreadFunc() from the last link. This is where you should start listening for and processing inbound socket connections.
I am just starting out Socket Programming in C# and am now a bit stuck with this problem.
How do you handle multiple clients on a single server without creating a thread for each client?
The one thread for each client works fine when there are say 10 clients but if the client number goes up to a 1000 clients is creating a thread for every single one of them advisable? If there is any other method to do this can someone please tel me?
Try to use asynchronous server.
The following example program creates a server that receives connection requests from clients. The server is built with an asynchronous socket, so execution of the server application is not suspended while it waits for a connection from a client. The application receives a string from the client, displays the string on the console, and then echoes the string back to the client. The string from the client must contain the string <EOF> to signal the end of the message.
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 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.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
// Create a TCP/IP socket.
Socket listener = new Socket(AddressFamily.InterNetwork,
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.IndexOf("<EOF>") > -1) {
// 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);
} 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) {
// 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);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
}
public static int Main(String[] args) {
StartListening();
return 0;
}
}
That's will be the best solution.
Threads can work fine but rarely scales well to that many clients. There are two easy ways and lots of more complex ways to handle that, here's some pseudocode for how the easier two are usually structured to give you an overview.
select()
This is a call to check which sockets have new clients or data waiting on them, a typical program looks something like this.
server = socket(), bind(), listen()
while(run)
status = select(server)
if has new client
newclient = server.accept()
handle add client
if has new data
read and handle data
Which means no threads are needed to handle multiple clients, but it doesn't really scale well either if handle data take a long time, then you won't read new data or accept new clients until that's done.
Async sockets
This is another way of handling sockets which is kind of abstracted above select. You just set up callbacks for common events and let the framework do the not-so-heavy lifting.
function handleNewClient() { do stuff and then beginReceive(handleNewData) }
function handleNewData() { do stuff and then beginReceive(handleNewData) }
server = create, bind, listen etc
server.beginAddNewClientHandler(handleNewClient)
server.start()
I think this should scale better if your data handling take a long time. What kind of data handling will you be doing?
This could be a good starting point. If you want to avoid 1 thread <-> 1 client; then you should use async socket facilities provided in .NET. Core object to use here is SocketAsyncEventArgs.
I am building a client server application where a client has to send some byte stream and the server responds to it based on the bytes received from the Client. I am using the NetworkStream.Write and NetworkStream.Read methods to send and receive data. The client is able to create a TCP connection to the server. After accepting the connection, the server does NetworkStream.Read and waits for some input from the client. The Client sends the data using the NetworkStream.Write and also does NetworkStream.Flush. But the Server never wakes up from the Read.
Can you guys suggest me what could be the problem here or if you know any other methods to send Byte Stream over a TCP Connection in C# please let me know.
Thanks!
Smart-ass comments aside: even though you are only interested in 2 lines of code, I'm willing to bet your problem is someplace else in your code.
Using a modified version of the code found here, I constructed a simple example that works in my testing.
public static void Main()
{
TcpListener server = null;
try
{
// Set the TcpListener on port 13000.
Int32 port = 13000;
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
// TcpListener server = new TcpListener(port);
server = new TcpListener(localAddr, port);
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[256];
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
TcpClient client = server.AcceptTcpClient();
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream();
stream.Read(bytes, 0, bytes.Length);
Console.WriteLine(System.Text.Encoding.ASCII.GetString(bytes));
// Shutdown and end connection
client.Close();
}
catch (SocketException e)
{
Console.WriteLine("SocketException: {0}", e);
}
finally
{
// Stop listening for new clients.
server.Stop();
}
Console.WriteLine("\nHit enter to continue...");
Console.Read();
}
The read call will wait and return when I send it 1 byte with another program. We would need to see some code to figure out why this works and yours does not.
I have a server application and client application with the functionality already working. Let me show you how I connect my client application to my server app:
//SERVER
// instantiate variables such as tempIp, port etc...
// ...
// ...
server = new TcpListener(tempIp, port); //tempIp is the ip address of the server.
// Start listening for client requests.
server.Start();
// Buffer for reading data
Byte[] bytes = new Byte[MaxChunkSize];
String data = null;
// Enter the listening loop.
while (disconect == false)
{
Console.Write("Waiting for a connection... ");
// Perform a blocking call to accept requests.
// You could also user server.AcceptSocket() here.
client = server.AcceptTcpClient(); // wait until a client get's connected...
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
stream = client.GetStream();
// now that the connection is established start listening though data
// sent through the stream..
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// etc..
....
ok now on the client side lets say I want to establish a connection then send some data through the stream
//Client
client = new TcpClient(serverIP, port);
// Get a client stream for reading and writing.
stream = client.GetStream();
//then if I wish to send the string hello world to the server I would do:
sendString(stream, "Hello world");
protected void sendString(NetworkStream stream, string str)
{
sendBytes(stream, textToBytes(str));
}
protected void sendBytes(NetworkStream stream, Byte[] data)
{
// Send the message to the connected TcpServer.
stream.Write(data, 0, data.Length);
}
protected static Byte[] textToBytes(string text)
{
return System.Text.Encoding.ASCII.GetBytes(text);
}
since I am able to send bytes I am able to send files or everything that I want. the technique that I use is that if I send the string file for example to the server then the server will start listening for a file. It will open a stream and write the received bytes to that file. If a different keyword is send the server will start listening on a different method etc..
So when dealing with one server and one client everything works great. Now I want to add more clients and need them to also connect to the server. I know that several connections can be establish on the same port just like we do it with por 80 on websites... I do not know how to manage several connections. so one thing I was thinking was to leave everything as it is. if a connection is established then tell the server to start another thread listening for other connections on the same port. with this technique I will have several threads running plus I just know the basics of multrythreading. If this technique is my best option I will start implementing it. You guys out there are really knowledgeable about all this so it will be nice if someone can point me on the right direction. Or maybe I should listen on several ports. if the server is already connected on port 7777 for example then do not accept connections from that port and start listening on port 7778 for example. I mean there could be so many different ways of achieving what I need and you guys probably know the best way. I just know the basics of networking...
You could use threading:
var client = server.AcceptTcpClient();
var t = new Thread(new ParameterizedThreadStart(AccentClient));
t.Start(client);
The target method would look like this
public void AccentClient(object clientObj)
{
var client = clientObj as TcpClient;
// Do whatever you need to do with the client
}
If you are not familiar with multithreading, it is important you learn at least the basics first.
You could implement a class that encapsulates TCP behavior. Check this class:
public class SimpleListener
{
private System.Net.Sockets.TcpListener _tcpListen;
//declare delegate to handle new connections
public delegate void _new_client(System.Net.Sockets.TcpClient tcpclient);
//declare a clients container (or something like...). OPTION 1
List<System.Net.Sockets.TcpClient> _connected_clients;
//declare an event and event handler (the same for _new_client) for new connections OPTION 2
public event _new_client new_tcp_client;
//public (The list of connected clients).
public List<System.Net.Sockets.TcpClient> ConnectedClients { get { return _connected_clients; } }
public SimpleListener(string ip, int listenport)
{
System.Net.IPAddress ipAd = System.Net.IPAddress.Parse(ip);
_tcpListen = new System.Net.Sockets.TcpListener(new System.Net.IPEndPoint(ipAd,listenport));
_connected_clients = new List<System.Net.Sockets.TcpClient>();
}
//Fire this method to start listening...
public void Listen()
{
_tcpListen.Start();
_set_listen();
}
//... and this method to stop listener and release resources on listener
public void Stop()
{
_tcpListen.Stop();
}
//This method set the socket on listening mode...
private void _set_listen()
{
//Let's do it asynchronously - Set the method callback, with the same definition as delegate _new_client
_tcpListen.BeginAcceptTcpClient(new AsyncCallback(_on_new_client), null);
}
//This is the callback for new clients
private void _on_new_client(IAsyncResult _async_client)
{
try
{
//Lets get the new client...
System.Net.Sockets.TcpClient _tcp_cl = _tcpListen.EndAcceptTcpClient(_async_client);
//Push the new client to the list
_connected_clients.Add(_tcp_cl);
//OPTION 2 : Fire new_tcp_client Event - Suscribers will do some stuff...
if (new_tcp_client != null)
{
new_tcp_client(_tcp_cl);
}
//Set socket on listening mode again... (and wait for new connections, while we can manage the new client connection)
_set_listen();
}
catch (Exception ex)
{
//Do something...or not
}
}
}
You could use this in your code:
//SERVER
// instantiate variables such as tempIp, port etc...
// ...
// ...
SimpleListener server = new SimpleListener(tempIp, port); //tempIp is the ip address of the server.
//add handler for new client connections
server.new_tcp_client += server_new_tcp_client;
// Start listening for client requests.
server.Listen();
.... //No need to loop. The new connection is handled on server_new_tcp_client method
void server_new_tcp_client(System.Net.Sockets.TcpClient tcpclient)
{
// Buffer for reading data
Byte[] bytes = new Byte[MaxChunkSize];
String data = null;
Console.WriteLine("Connected!");
// Get a stream object for reading and writing
System.IO.Stream stream = tcpclient.GetStream();
// now that the connection is established start listening though data
// sent through the stream..
int i;
try
{
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine("Received: {0}", data);
// etc..
....
}