I have been experimenting with some code to find other computer's on my network running my app. Firstly I broadcast and listen for those broadcasts. After that I am a little lost on the next step. Once Computer A knows the ip address of Computer B because of the broadcast how do I put Computer B in a state to accept socket connections. Then how does Computer A begin that connection?
Also I have tried doing the broadcasting with Multicast and cannot get that to work. If anyone has extra time could they show that as well.
Starting Listener and Sender:
private static void StartServer()
{
Task.Factory.StartNew(async () =>
{
await StartListeningAsync();
});
}
private static void StartClient()
{
Task.Factory.StartNew(async () =>
{
await StartSendingAsync();
});
}
Those inner methods:
private static async Task StartSendingAsync()
{
try
{
using (UdpClient _broadcaster = new UdpClient())
{
var ipHost = Dns.GetHostEntry("");
var ipAddr = ipHost.AddressList[ipHost.AddressList.Count() - 1];
IPEndPoint ip = new IPEndPoint(IPAddress.Broadcast, PORT);
var ipAddress = Encoding.ASCII.GetBytes(ipAddr.ToString());
for (int x = 0; x < 10; x++)
{
_broadcaster.Send(ipAddress, ipAddress.Count(), ip);
await Task.Delay(TimeSpan.FromSeconds(6));
}
}
}
catch (Exception ex)
{
}
}
private static async Task StartListeningAsync()
{
while (true)
{
using (UdpClient _listener = new UdpClient(PORT))
{
try
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, PORT);
var incoming = await _listener.ReceiveAsync();
NewPing(incoming.Buffer, incoming.RemoteEndPoint);
await Task.Delay(TimeSpan.FromSeconds(10));
}
catch (SocketException ex)
{
if (ex.SocketErrorCode == SocketError.TimedOut)
{
//Time out that's fine
}
}
}
}
}
What happens when the listener hears a broadcast:
private static void NewPing(byte[] incoming, IPEndPoint rem)
{
Console.WriteLine($"New ping from {rem.ToString()}, attempting to connect!");
//What should happen here now that one of the computer's know the other exists?
//Start some kind of Socket Accepting method?
}
If I understand correctly, you want a machine to send out a UDP broadcast, and then establish a TCP connection between the two?
I'd perform the following steps:
B is listening for UDP broadcasts
A wants a TCP connection with B, so
A starts listening for incoming TCP connections
A sends out a broadcast saying "I'm listening"
B receives the broadcast and attempts to connect to A
I've created two sample console applications, one server, one client:
Server:
using System;
using System.Net;
using System.Net.Sockets;
class Program
{
static void Main(string[] args)
{
TcpListener listener = new TcpListener(new IPEndPoint(IPAddress.Any, 11220));
listener.Start();
listener.AcceptSocketAsync().ContinueWith((t) => HandleClient(t.Result));
Console.WriteLine($"Listening for TCP connections at port 11220...");
using (UdpClient broadcaster = new UdpClient(AddressFamily.InterNetwork))
{
broadcaster.EnableBroadcast = true;
Console.WriteLine("Broadcasting...");
broadcaster.Send(new byte[] { 1, 2, 3 }, 3, new IPEndPoint(IPAddress.Broadcast, 11221));
}
while (Console.ReadKey(true).Key != ConsoleKey.Q)
{
Console.WriteLine("Press 'Q' to quit");
}
}
static void HandleClient(Socket socket)
{
Console.WriteLine($"TCP connection accepted ({socket.RemoteEndPoint})!");
}
}
Client:
using System;
using System.Net;
using System.Net.Sockets;
class Program
{
static void Main(string[] args)
{
using (UdpClient client = new UdpClient(11221, AddressFamily.InterNetwork))
{
Console.WriteLine("Waiting for broadcast...");
client.EnableBroadcast = true;
client.ReceiveAsync().ContinueWith((t) => HandleBroadcast(t.Result)).Wait();
}
Console.WriteLine("Press any key to continue");
Console.ReadKey(true);
}
static void HandleBroadcast(UdpReceiveResult result)
{
Console.WriteLine($"Received broadcast from {result.RemoteEndPoint}, attempting to connect via TCP");
Socket socket = new Socket(result.RemoteEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(new IPEndPoint(result.RemoteEndPoint.Address, 11220));
}
}
First start the client, then the server. The data sent in the broadcast is just dummy data, but you could include some information like the TCP port number the server is listening at.
PS. Remember that this is just a proof of concept.
Related
My problem is weird and i was not able to find a resolution from referring to other threads regarding this. I am getting the error when i run the microsoft Synchronous Server Socket Example, Synchronous Client Socket Example, on two systems which are part of the domain but i do not get this error when i run the same code on two systems which are part of the network but they are not part of the domain! Anyone know what might be causing the issue?
The things i have done to try to resolve are I made sure the port was open, switched off the firewall and antivirus as suggested by others with similar problem.But it has not helped.
Server code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SynchronousSocketListener {
// Incoming data from the client.
public static string data = null;
public static void StartListening() {
// Data buffer for incoming data.
byte[] bytes = new Byte[1024];
// Establish the local endpoint for the socket.
// Dns.GetHostName returns the name of the
// host running the application.
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(10);
// Start listening for connections.
while (true) {
Console.WriteLine("Waiting for a connection...");
// Program is suspended while waiting for an incoming connection.
Socket handler = listener.Accept();
data = null;
// An incoming connection needs to be processed.
while (true) {
int bytesRec = handler.Receive(bytes);
data += Encoding.ASCII.GetString(bytes,0,bytesRec);
if (data.IndexOf("<EOF>") > -1) {
break;
}
}
// Show the data on the console.
Console.WriteLine( "Text received : {0}", data);
// Echo the data back to the client.
byte[] msg = Encoding.ASCII.GetBytes(data);
handler.Send(msg);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
} catch (Exception e) {
Console.WriteLine(e.ToString());
}
Console.WriteLine("\nPress ENTER to continue...");
Console.Read();
}
public static int Main(String[] args) {
StartListening();
return 0;
}
}
Client Code::
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
public class SynchronousSocketClient {
public static void StartClient() {
// Data buffer for incoming data.
byte[] bytes = new byte[1024];
// Connect to a remote device.
try {
// Establish the remote endpoint for the socket.
// This example uses port 11000 on the local computer.
IPAddress ipAddress = IPAddress.Parse("172.21.98.122");//Server IP
IPEndPoint remoteEP = new IPEndPoint(ipAddress,11000);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp );
// Connect the socket to the remote endpoint. Catch any errors.
try {
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
// Encode the data string into a byte array.
byte[] msg = Encoding.ASCII.GetBytes("This is a test<EOF>");
// Send the data through the socket.
int bytesSent = sender.Send(msg);
// Receive the response from the remote device.
int bytesRec = sender.Receive(bytes);
Console.WriteLine("Echoed test = {0}",
Encoding.ASCII.GetString(bytes,0,bytesRec));
// Release the socket.
sender.Shutdown(SocketShutdown.Both);
sender.Close();
} catch (ArgumentNullException ane) {
Console.WriteLine("ArgumentNullException : {0}",ane.ToString());
} catch (SocketException se) {
Console.WriteLine("SocketException : {0}",se.ToString());
} catch (Exception e) {
Console.WriteLine("Unexpected exception : {0}", e.ToString());
}
} catch (Exception e) {
Console.WriteLine( e.ToString());
}
}
public static int Main(String[] args) {
StartClient();
return 0;
}
}
I'm trying to understand the backlog parameter of TcpListener class but I struggle on how to achieve maximum number of pending connections at same time so I can test it.
I have a sample async server and client code. MSDN says that the backlog is the maximum length of the pending connections queue. I made the server listen for connections all the time and the client is connecting 30 times. What I expect is after the 20th request to throw a SocketException in the client because the backlog is set to 20. Why doesn't it block it?
My second misunderstanding is do I really need to put my logic of the accepted connection in a new thread assuming there is a slow operation which takes around 10 seconds e.g. sending a file over the TCP? Currently, I put my logic in a new Thread, I know it's not the best solution and instead I should use a ThreadPool but the question is principal. I tested it by changing the client side's loop to 1000 iterations and if my logic is not in a new thread, the connections were getting blocked after the 200th connection probably because Thread.Sleep slows the main thread each time by 10 seconds and the main thread is responsible for all the accept callbacks. So basically, I explain it myself as the following: if I want to use the same concept, I have to put my AcceptCallback logic in a new thread like I did or I have to do something like the accepted answer here: TcpListener is queuing connections faster than I can clear them. Am I right?
Server code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
class Program
{
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 80);
try
{
listener.Start(20);
while (true)
{
_mre.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener);
_mre.WaitOne();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AcceptCallback(IAsyncResult ar)
{
_mre.Set();
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
IPAddress ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Console.WriteLine($"{ip} has connected!");
// Actually I changed it to ThreadPool
//new Thread(() =>
//{
// Console.WriteLine("Sleeping 10 seconds...");
// Thread.Sleep(10000);
// Console.WriteLine("Done");
//}).Start();
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("Sleeping 10 seconds...");
Thread.Sleep(10000);
Console.WriteLine("Done");
}));
// Close connection
client.Close();
}
}
}
Client code:
using System;
using System.Net.Sockets;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 30; i++)
{
Console.WriteLine($"Connecting {i}");
using (TcpClient client = new TcpClient()) // because once we are done, we have to close the connection with close.Close() and in this way it will be executed automatically by the using statement
{
try
{
client.Connect("localhost", 80);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.ReadKey();
}
}
}
Edit: Since my second question might be a little bit confusing, I will post my code which includes sent messages and the question is should I leave it like that or put the NetworkStream in a new thread?
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Server
{
class Program
{
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
static void Main(string[] args)
{
// MSDN example: https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example
// A better solution is posted here: https://stackoverflow.com/questions/2745401/tcplistener-is-queuing-connections-faster-than-i-can-clear-them
TcpListener listener = new TcpListener(IPAddress.Any, 80);
try
{
// Backlog limit is 200 for Windows 10 consumer edition
listener.Start(5);
while (true)
{
// Set event to nonsignaled state
_mre.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener);
// Wait before a connection is made before continuing
_mre.WaitOne();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue
_mre.Set();
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
IPAddress ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Console.WriteLine($"{ip} has connected!");
using (NetworkStream ns = client.GetStream())
{
byte[] bytes = Encoding.Unicode.GetBytes("test");
ns.Write(bytes, 0, bytes.Length);
}
// Use this only with backlog 20 in order to test
Thread.Sleep(5000);
// Close connection
client.Close();
Console.WriteLine("Connection closed.");
}
}
}
Client:
using System;
using System.Net.Sockets;
using System.Text;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 33; i++)
{
Console.WriteLine($"Connecting {i}");
using (TcpClient client = new TcpClient()) // once we are done, the using statement will do client.Close()
{
try
{
client.Connect("localhost", 80);
using (NetworkStream ns = client.GetStream())
{
byte[] bytes = new byte[100];
int readBytes = ns.Read(bytes, 0, bytes.Length);
string result = Encoding.Unicode.GetString(bytes, 0, readBytes);
Console.WriteLine(result);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.ReadKey();
}
}
}
The listen backlog is defined in RFC 6458 and tells the OS the maximum number of sockets allowed in the accept queue.
Incoming connections are placed in this queue by the TCP/IP stack and removed when the server calls Accept to handle the new connection.
In your question, both versions of the server code call Accept in a loop from the main thread, and wait for AcceptCallback to start before making another accept call. This results in quite fast draining of the queue.
To demonstrate listen queue overflow, its easiest to slow down your server's rate of accepting - E.g. slow it down to zero:
var serverEp = new IPEndPoint(IPAddress.Loopback, 34567);
var serverSocket = new TcpListener(serverEp);
serverSocket.Start(3);
for (int i = 1; i <= 10; i++)
{
var clientSocket = new TcpClient();
clientSocket.Connect(serverEp);
Console.WriteLine($"Connected socket {i}");
}
In your examples you could just add a sleep at the end of the Accept loop in the main thread, and increase the connection rate.
In the real world, the optimal backlog depends on:
The rate that the clients / internet / OS can fill the queue
The rate that the OS / server can process the queue
I don't recommend using Thread directly, here's how the server looks using Task and Socket Task Extensions:
static async Task Main(string[] args)
{
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, 80));
server.Listen(5);
while (true)
{
var client = await server.AcceptAsync();
var backTask = ProcessClient(client);
}
}
private static async Task ProcessClient(Socket socket)
{
using (socket)
{
var ip = ((IPEndPoint)(socket.RemoteEndPoint)).Address;
Console.WriteLine($"{ip} has connected!");
var buffer = Encoding.Unicode.GetBytes("test");
await socket.SendAsync(buffer, SocketFlags.None);
}
Console.WriteLine("Connection closed.");
}
I'm trying to figure out how I can send & receive data via the UDP protocol using C# as a client, and having a JS server running that will transmit a "response" packet for testing purposes.
Below is the UDP class that I made for testing, it's simply just 2 threads:
One that read the received data from UDP and another thread for sending data.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace UDPTesting {
class UDPHandler {
private int receivePort, sendPort;
private string serverIP;
private IPEndPoint sendEndPoint, receiveEndPoint;
public UDPHandler(string serverIP, int receivePort, int sendPort) {
this.serverIP = serverIP;
this.receivePort = receivePort;
this.sendPort = sendPort;
this.sendEndPoint = new IPEndPoint(IPAddress.Parse(this.serverIP), this.sendPort);
this.receiveEndPoint = new IPEndPoint(IPAddress.Parse(this.serverIP), this.receivePort);
this.readerUdpClient();
this.senderUdpClient();
}
void readerUdpClient() {
UdpClient readerClient = new UdpClient();
IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, 3000);
readerClient.Client.Bind(localEndpoint); //Tried both Connect and Bind
//readerClient.Connect(this.receiveEndPoint);
Thread t = new Thread(() => {
Console.WriteLine("Awaiting data from server...");
var remoteEP = new IPEndPoint(IPAddress.Any, 3000);
byte[] bytesReceived = readerClient.Receive(ref remoteEP);
//The above throws: System.InvalidOperationException: 'You must call the Bind method before performing this operation'
Console.WriteLine("Received data from " + remoteEP.ToString());
});
t.Start();
}
void senderUdpClient() {
UdpClient senderClient = new UdpClient();
senderClient.Connect(this.sendEndPoint);
string sendString = "1;2;3";
byte[] bytes = toBytes(sendString);
Thread t = new Thread(() => {
while (true) {
senderClient.Send(bytes, bytes.Length);
Thread.Sleep(1000);
}
});
t.Start();
}
public byte[] toBytes(string text) {
return Encoding.UTF8.GetBytes(text);
}
public string fromBytes(byte[] bytes) {
return Encoding.UTF8.GetString(bytes);
}
}
}
Additionally my "main" for my program is this:
using System;
using System.Threading;
namespace UDPTesting {
class Program {
static void Main(string[] args) {
string serverIP = "46.101.102.243";
int sendPort = 41234;
int receivePort = 3000;
UDPHandler handler = new UDPHandler(serverIP, receivePort, sendPort);
}
}
}
How can I read the response that the server sends in the client, at the same time as I send data from the client to the server?
We tested it individually:
1) Sending a UDP packet from client -> server works, as I can see that the server receives the packet.
2) Sending a UDP packet from server -> client works, as I can see the client receives the packet.
3) When the client tries to send and read simultaneously, it will send data to the server, but will not read the response.
Any help would be greatly appreciated!
Your receiving function should work like this
void readerUdpClient()
{
new Thread(() => {
UdpClient readerClient = new UdpClient(receivePort);
Console.WriteLine("Awaiting data from server...");
var remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] bytesReceived = readerClient.Receive(ref remoteEP);
Console.WriteLine($"Received {bytesReceived.Length} bytes from {remoteEP}");
}).Start();
}
The UdpClient constructor that takes a port automatically binds the local end point for you.
So here's the thing, i'm creating a server/client environment for a game where a port forwarded computer acts as a server, and clients send the first UDP message to connect and get the accept message then start sending the in-game UDP messages after successfully connecting.
The problem is, when I use the local IPs say the server using 10.0.0.7 and a client is using 10.0.0.4, everything works just fine:
Client sends connect message.
Server receives it.
Servers sends back accept message.
Client receives it
All further messages reach both ends without any problem.
But when I use the external IP:
Client sends connect message.
Server receives it.
Servers sends back accept message.
Client receives it
Both ends can send messages but the client doesn't receive any more messages.
Wanted to know at the end if the problem is somehow from the code, or from what I think it's really from, router, NAT, firewalls or anything like that.
(Note: Client sends to server's 8888 port, and server sends back through the client's local port, as it should be.)
Below is the client code, written for Unity:
void Start()
{
client = new UdpClient();
client.Connect(IPAddress.Parse("<Global IP>"), 8888);
client.BeginReceive(new AsyncCallback(ReadMessage), client);
}
private void ReadMessage(IAsyncResult result)
{
IPEndPoint ipEndPoint = null;
string message = Encoding.ASCII.GetString(client.EndReceive(result, ref ipEndPoint));
print("Got: " + message);
string[] wholeMessages = message.Split('#');
for (int w = 0; w < wholeMessages.Length - 1; w++)
{
string[] parts = wholeMessages[w].Split('$');
if (!connected && parts.Length == 3 && parts[0] == "accept" && int.TryParse(parts[1], out ID))
{
connected = true;
code = parts[2];
}
}
client.BeginReceive(new AsyncCallback(ReadMessage), client);
}
public void SendUDP(string message)
{
client.Send(Encoding.ASCII.GetBytes(message), message.Length);
}
Ok, after several trials and errors this worked for me...
//Server Code
private static UdpClient udpClient;
static void Main(string[] args)
{
Console.WriteLine("Server initiated...");
udpClient = new UdpClient(8888);
}
private static void ReadMessage()
{
while (true)
{
try
{
IPEndPoint IPEP = null;
string message = Encoding.ASCII.GetString(udpClient.Receive(ref IPEP));
}
}
}
private static void SendUDP(IPEndPoint e,string message)
{
new UdpClient().Send(Encoding.ASCII.GetBytes(message), message.Length, e);
}
//Client Code
private IPAddress ip;
void Start()
{
ip = Dns.GetHostAddresses("HOSTNAME")[0];
client = new UdpClient(new IPEndPoint(IPAddress.Any, 0));
udpThread = new Thread(new ThreadStart(ReadMessage))
{
IsBackground = true
};
udpThread.Start();
}
private void ReadMessage()
{
while (true)
{
try
{
IPEndPoint IPEP = null;
byte[] data = client.Receive(ref IPEP);
string message = Encoding.ASCII.GetString(data);
}
}
}
public void SendUDP(string message)
{
client.Send(Encoding.ASCII.GetBytes(message), message.Length, new IPEndPoint(ip, 8888));
}
I am trying to make a program in witch multiply clients will connect to the server. But i have a problem because when i try to connect more than 1 client at the same time, it takes a "long time" to do it.
i am using asynchronous way to connect:
public bool connect(string IP,int port)
{
try
{
if (m_clientSocket == null)
{
m_clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse(IP.ToString());
int iPortNo = System.Convert.ToInt16(port.ToString());
IPEndPoint ipEnd = new IPEndPoint(ip, iPortNo);
client.BeginConnect(remoteEP, new AsyncCallback(ConnectCallback), client);
}
}catch()
{
return false;
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
Socket client = (Socket)ar.AsyncState;
if (m_clientSocket != null)
{
if (m_clientSocket.Connected)
{
client.EndConnect(ar);
// send next data here
}
else
{
client.EndConnect(ar);
m_clientSocket.Close();
m_clientSocket = null;
state = CONNECT_ERROR;
}
}
}
catch ()
{
}
}
For each client I want to connect I open a new class that includes two methods that you can see above. than with simple for loop I call methods one after another.
in Wireshark I observe the time that next needs to connect to a server is 0.1s witch I think is allot.
Any idea why does it take so long ?
Thanks for any kind of help.