I am trying to create a multi-threading application that'll try and send a lot of data to a specific IP and port using sockets in C#. I have completed this, but I need help in getting more information from it.
I would like to know how I could get how much data is being sent a second? In MB if possible, from all threads and all requests?
I am mearly doing this for educational purposes to see how much data can actually be sent and how it all works when doing it with multi -threading
Here is my code:
static void Main(string[] args)
{
int amountOfThreads = 10;
while (amountOfThreads > 0)
{
Thread thread = new Thread(SendData);
thread.Start();
}
}
private static void SendData()
{
byte[] dataToSend = Encoding.Default.GetBytes("some string that'll be sent many times.");
string ipAddress = "127.0.0.1";
int port = 3924;
IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ipAddress), port);
Socket socketToSendTo = new Socket(System.Net.Sockets.AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socketToSendTo.SendTo(dataToSend, ep);
}
Related
I'm trying to write a high-performance HTTP server in C# without using third-party libraries, and during my readings, I found this post on nginx blog. What mentioned there is using SO_REUESEPORT but that option is not available in .NET sockets and also Windows, so I searched for an alternative to this option and I've read that SO_REUSEADDR which is available in both Windows and .NET is the option that I have looking for.
I have tried to implement that by creating 4 sockets and enabling reuse-address before binding the sockets and start listening, but what happens after is only one of the sockets accepts connections even though its thread goes busy.
static readonly byte[] Response = Encoding.ASCII.GetBytes("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r");
static int s_ListenerIndex = 0;
static void Main(string[] args)
{
var listenAddress = new IPEndPoint(IPAddress.Any, 26000);
var sockets = new Socket[4];
Console.WriteLine("Creating sockets");
for (int i = 0; i < sockets.Length; i++)
{
sockets[i] = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sockets[i].SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
sockets[i].Bind(listenAddress);
}
Console.WriteLine("Starting listener threads");
for (int i = 0; i < sockets.Length; i++)
{
var socket = sockets[i];
CreateThread(() => ListenSocket(socket));
}
Thread.Sleep(Timeout.Infinite);
}
static void ListenSocket(Socket socket)
{
var listenerId = Interlocked.Increment(ref s_ListenerIndex);
socket.Listen(100);
Console.WriteLine($"Socket #{listenerId} is listening");
while (true)
{
Socket client = socket.Accept();
Console.WriteLine($"Socket #{listenerId} accepted connection");
client.Send(Response);
client.Close();
}
}
static void CreateThread(ThreadStart threadStart)
{
var thread = new Thread(threadStart);
thread.IsBackground = true;
thread.Start();
}
Am I doing something wrong or the whole trick is not possible in Windows and .NET?
On Windows, the SO_REUSEADDR option has no use cases for an HTTP server. It's only real use case is for multicast sockets where data is delivered to all of the sockets bound on the same port.
I suggest this SO post for a indepth discussion. How do SO_REUSEADDR and SO_REUSEPORT differ?
Under Windows with IOCP you don't need the Linux/Unix equivalent which can provide load balancing across multiple threads. IOCP takes care of this for you. The implementation is very different but achieves the same highly scalable result.
Hello I am developing sample application for demonstration of udp client to send data from client to server. I have created console application and below is my code.
class Program
{
static void Main(string[] args)
{
senddata();
while (true)
{
try {
UdpClient udpClient = new UdpClient(9999);
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
string result;
result = returnData.ToString();
}
catch(Exception e)
{
}
}
void senddata()
{
UdpClient udpClient = new UdpClient(9999);
udpClient.Connect("10.170.84.163", 9999);
Byte[] senddata1 = Encoding.ASCII.GetBytes("Hello World");
udpClient.Send(senddata1, senddata1.Length);
}
}
}
whenever Byte[] receiveBytes is executed i get my empty black screen and nothing is going to happen. Can someone tell me how to fix this? Any help would be appreciated. Thank you.
There are several issues here:
You send data to udp port (via senddata()) before starting a listener on that port, and you do this only once, so there is no chance listener might receive it.
There is no need to bind UdpClient to specific port when sending data, especially to the same port on which you are listening with another UdpClient. Just use UdpClient udpClient = new UdpClient(); to let it use any available port for sending.
Since you are testing - there is no need to send data to your external ip, send to loopback interface instead: udpClient.Connect(IPAddress.Loopback, 9999);.
UdpClient implements IDisposable, so dispose it when you are done.
Your while (true) loop will not work, because you don't dispose UdpClient, so on second iteration of the loop, second UdpClient will try to bind to the same 9999 port and fail, because there is already listener (which you didn't dispose) on that same port.
Your code with fixes above (obviously that is not "production" code so I won't add things like cancellation and so on, only fixes to be able to see message is coming):
static void senddata() {
// send message every 100 ms
while (true) {
// wrap in using
using (UdpClient udpClient = new UdpClient()) {
// loopback
udpClient.Connect(IPAddress.Loopback, 9999);
Byte[] senddata1 = Encoding.ASCII.GetBytes("Hello World");
udpClient.Send(senddata1, senddata1.Length);
}
Thread.Sleep(100);
}
}
static void Main(string[] args) {
// run sending in background
Task.Run(() => senddata());
try {
// wrap in using
using (UdpClient udpClient = new UdpClient(9999)) {
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
// move while loop here
while (true) {
// this blocks until message is received
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
string returnData = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine(returnData);
}
}
}
catch (Exception e) {
// do something meaningful
}
}
It doesn't look like you're outputting the received string.
Something like this....
string result;
result = returnData.ToString();
Console.WriteLine(result);
Try changing the following:
IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, 0);
Byte[] receiveBytes = udpClient.Receive(ref RemoteIpEndPoint);
To use the port 9999 rather than a random port. I'm honestly somewhat surprised that doesn't throw an exception.
Note that binding to a random port as a server is not atypical but the remote end will need some way to discover that random port I..E. the way ftp uses a second port for actual file data transfer, that port number is sent as part of the message starting the transfer.
I've made a simple chat application in c#.net that sends and receives data between 2 computers.
So, I used this method to send the data:
int port = 11000;
private void send(string data, string ip)
{
Socket sending_socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
IPEndPoint sending_end_point = null;
byte[] send_buffer = Encoding.ASCII.GetBytes(data);
sending_end_point = new IPEndPoint(IPAddress.Parse(ip), port);
try { sending_socket.SendTo(send_buffer, sending_end_point); }
catch { }
}
And to receive I used this:
string receiveddata = "";
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
UdpClient listener = new UdpClient(port);
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, port);
byte[] receive_byte_array;
try
{
receive_byte_array = listener.Receive(ref groupEP);
receiveddata = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
}
catch { }
listener.Close();
}
This works without any problems between 2 computers on a LAN, but I would like to know (if possible) how to do the same thing over the Internet.
From what I've searched on the Internet, it seems that I have to use port-forwarding in order to do that, so I already did that, but I don't know what should I do know.
So my question is, how should I change this code (if I have to) so I could send and receive data (UDP) over the internet, assuming I have port-forwarded correctly already and assuming I know the external IPs of both routers?
Thank you in advance.
This should work just fine, as long as your (public) IP-address is correct and the ports are forwarded correctly on your router (meaning, forwarded to the correct private IP, on the correct protocol, in your case UDP).
You are aware that this is UDP though, so it's not reliable data transfer.
I have looked just about all over Google, and even here on Stack overflow, but I cannot seem to find the solution I'm looking for. I am testing my programming skills remaking Pong using MonoGame for C# and I'm trying to make this multiplayer with both UDP Clients and a UDP Server. I'm going with "the perfect client-server model" idea where the server handles all the calculations, while the game client just receives data from the server and displays it on the screen. Unfortunately I have had past issue working with programming UDP Servers. I have a loop in which I receive a datagram, than begin listening for another. I use Asynchronous calls because in my mind that is what would work the best for client and server. Main code looks something like this: (I'm going to cut out the bit that won't affect CPU, and show only the networking.)
static void Main()
{
//Initialize
Console.Title = "Pong Server";
Console.WriteLine("Pong Server");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Bind socket
EndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 25565);
Console.WriteLine("Binding to port 25565");
serverSocket.Bind(localEndPoint);
//Listen
Console.WriteLine("Listening on {0}.", localEndPoint);
//Prepare EndPoints
EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
//Recive Data...
rcvPacket = new byte[Data.Size];
serverSocket.BeginReceiveFrom(rcvPacket, 0, Data.Size, SocketFlags.None, ref clientEndPoint, new AsyncCallback(Receive), null);
}
And then in the Receive(IAsyncResult ar) Method:
static void Receive(IAsyncResult ar)
{
//Prepare EndPoints
EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
//End
int PacketSize = serverSocket.EndReceiveFrom(ar, ref clientEndPoint);
//<Handle Packet Code Here>
//Receive Loop
rcvPacket = new byte[Data.Size];
serverSocket.BeginReceiveFrom(rcvPacket, 0, Data.Size, SocketFlags.None, ref clientEndPoint, new AsyncCallback(Receive), null);
}
What this code looks like is that it will wait until a packet is received, than listen for another one, which will halt this "listener" thread, being asynchronous. Anyway thanks for reading my question and hopefully I'll get to the bottom of this.
Oh by the way, here is an image of one of my 4 cores getting maxed out. (Yes I'm currently debugging it.)
Adding Thread.Sleep(1) call to the update loop fixed not only the CPU usage in the original problem, but it also made the the code executed in the update loop behave better. inside the while(alive)}{ } where I keep track of the elapsed time and total time, I insert the sleep call.
The value seems to be needed at least 1.
static void Main(string[] args)
{
//Initialize
Console.Title = "Pong Server";
Console.WriteLine("Pong Server");
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
//Bind socket
EndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 25565);
Console.WriteLine("Binding to port 25565");
serverSocket.Bind(localEndPoint);
//Listen
Console.WriteLine("Listening on {0}.", localEndPoint);
//Prepare EndPoints
EndPoint clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
//Recive Data...
serverSocket.BeginReceiveFrom(rcvPacket, 0, Data.Size, SocketFlags.None, ref clientEndPoint, new AsyncCallback(ReceiveFrom), null);
//Initialize TimeSpans
DateTime Now = DateTime.Now;
DateTime Start = Now;
DateTime LastUpdate = Now;
TimeSpan EllapsedTime;
TimeSpan TotalTime;
//Create Physics Objects
Paddle1 = new Physics2D();
Paddle2 = new Physics2D();
Ball = new Physics2D();
//Loop
while (alive)
{
Now = DateTime.Now;
TotalTime = Now - Start;
EllapsedTime = Now - LastUpdate;
LastUpdate = Now;
Update(EllapsedTime, TotalTime);
//Add Sleep to reduce CPU usage;
Thread.Sleep(1);
}
//Press Any Key
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
From MSDN documentation:
Your callback method should invoke the EndReceiveFrom method. When your application calls BeginReceiveFrom, the system will use a separate thread to execute the specified callback method, and it will block on EndReceiveFrom until the Socket reads data or throws an exception. If you want the original thread to block after you call the BeginReceiveFrom method, use WaitHandle.WaitOne. Call the Set method on a T:System.Threading.ManualResetEvent in the callback method when you want the original thread to continue executing. For additional information on writing callback methods, see Callback Sample
From my understanding, you create the callback thread directly when you call BeginReceiveFrom.
Because you do not use EndReceiveFrom, you callback thread is executed, creating another thread , again and again ...
Use EndReceiveFrom to wait for the whole packet to be read, then your callback will repeat and start reading again. Watch out for thread safety I have no idea how you manage your data here.
Looking at that post could help :
Asynchronous TCP/UDP Server
I have a simple server that waits for a client to connect, reads the incoming stream, and sends a message back. What I would like to do is have every connection handled by a separate thread. This is my first time working with sockets and threads in C#, and most of the examples I have found are really confusing, so any help or simple examples would be much appreciated.
Here is what I have right now.
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
[STAThread]
static void Main(string[] args)
{
TestServer ts = new TestServer();
ts.Start();
}
class TestServer
{
private readonly int port = 48888;
private readonly IPAddress ip = IPAddress.Parse("127.0.0.1");
private TcpListener listener;
public TestServer()
{
this.listener = new TcpListener(this.ip, this.port);
}
public void Start()
{
this.listener.Start();
Console.WriteLine("Server Running...");
Socket s;
Byte[] incomingBuffer;
int bytesRead;
Byte[] Message;
while (true)
{
s = this.listener.AcceptSocket();
incomingBuffer = new Byte[100];
bytesRead = s.Receive(incomingBuffer);
string message = "Hello from the server";
Message = Encoding.ASCII.GetBytes(message.ToCharArray());
s.Send(Message);
}
}
}
Try this:
public void Start()
{
this.listener.Start();
Console.WriteLine("Server running...");
while (true)
{
Socket s = this.listener.AcceptSocket();
ThreadPool.QueueUserWorkItem(this.WorkMethod, s);
}
}
private void WorkMethod(object state)
{
using (Socket s = (Socket)state)
{
byte[] buffer = new byte[100];
int count = s.Receive(buffer);
string message = "Hello from the server";
byte[] response = Encoding.ASCII.GetBytes(message);
s.Send(response);
}
}
Not answering your question directly, but ...
Thread pools are not about 'new thread per connection', they are about having some meaningful number of threads (with some relation to number of cores on the box) already running and waiting for work. This "work" is given to the pool by the producer thread (the one accepting the connections in your case) via one or more queues.
Please note that this is not always the best solution though. Take a look at C10K and at Hight Performance Server Architecture pages.
Use a threadpool. You can use instantiate threads manually but since you have might have a huge number of connections, a threadpoool is more efficient.
System.Threading.ThreadPool.QueueUserWorkItem(new System.Threading.WaitCallback(processMessage), socket);
processMessage is the method that will process the message. And there will be one thread per connection. Really simple actually.