I have a socket program that works with Udp.
I want to manage clients that connect to the server.
For example, if the clients is connected to the server, add that client to a list.
I have already done this in Tcp with the following code:
static readonly Dictionary <int, TcpClient> list_clients = new Dictionary <int, TcpClient>();
For example, just the client who is on the list, his messages will be written.
I compared each clients with GetStream(). But in Udp I do not know how to do it. Can I manage clients ?
EDIT
I use the following code to receive a message from the client :
private static UdpClient udpServer = new UdpClient(11000);
private static IPEndPoint remoteEP = new IPEndPoint(IPAddress.Any, 11000);
static void Main(string[] args)
{
var firstData = udpServer.Receive(ref remoteEP);
Console.WriteLine(Encoding.ASCII.GetString(firtsData);
}
Thanks in advance
this code works well for me!
Server:
public partial class Server : Form
{
public Server()
{
InitializeComponent();
}
void Print(string message)
{
listBox1.Items.Add(message);
}
private void button1_Click(object sender, EventArgs e)
{
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(new IPEndPoint(IPAddress.Loopback, 55555));
byte[] vs = new byte[100];
EndPoint senderRemote = new IPEndPoint(IPAddress.Any, 0);
Dictionary<EndPoint, int> pairs = new Dictionary<EndPoint, int>();
int id = 0;
for (int ii = 0; ii < 5; ii++)
{
socket.ReceiveFrom(vs, ref senderRemote);
if (pairs.ContainsKey(senderRemote))
Print(pairs[senderRemote].ToString() + " says:");
else
{
pairs.Add(senderRemote, id++);
Print("new sender");
}
Print(senderRemote.ToString());
Print(Encoding.Unicode.GetString(vs));
socket.SendTo(vs, senderRemote);
}
}
}
client:
public partial class Client : Form
{
public Client()
{
InitializeComponent();
}
Socket socket;
private void button1_Click(object sender, EventArgs e)
{
socket.Send(Encoding.Unicode.GetBytes("Gholamam!"));
byte[] vs = new byte[100];
socket.Receive(vs);
listBox1.Items.Add(Encoding.Unicode.GetString(vs));
}
private void Client_Load(object sender, EventArgs e)
{
socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.Bind(new IPEndPoint(IPAddress.Loopback, new Random().Next(1024,65000)));
socket.Connect(IPAddress.Loopback, 55555);
}
}
don't forget that client and server are communicating. therefore they must use compromised way to communicate. if you like to store client information, it must be constant. for this, you must bind it to a fixed localEndPoint.
you can also use the solution in the question comments: you can add an id in messages. also you can use both.
P.S.: I'm using Socket Class instead of TCPClient or UDPClient because i found them awkward and inconsistent in some manners.
Related
I have previously had this code working, and am unsure of the cause of the issue i am currently having. I am writing a simple client/server application for encrypted chat. The server allows for multiple simultaneous clients. When i bind the server to the local IP Address i can connect with multiple local clients simultaneously, but when I bind it to the external IP address, only the first instance on the local machine will connect, but other devices may connect with multiple instances simultaneously. In this case even closing the first instance will not allow another to connect, and the AcceptCallBack is never called. I have been unable to find any other reports of this issue. Reasons that come to mind include that I made some sort of mistake in the code, or I need to separately listen for local connections and remote connections, or that it is a router/firewall issue.
For my server i have:
public partial class frmServer : Form
{
Thread listenThread;
private static bool listening = false;
private static List<StateObject> Users = new List<StateObject>();
public frmServer()
{
InitializeComponent();
}
private void frmServer_Load(object sender, EventArgs e)
{
listenThread = new Thread(new ThreadStart(StartListening));
listenThread.Start();
}
public static void StartListening()
{
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, 19541);
// 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);
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
listening = true;
while (true)
{
//check if there are new connections
if (!listening)
{
listener.BeginAccept(new AsyncCallback(AcceptCallback), listener);
listening = true;
}
Thread.Sleep(50);
}
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
public static void AcceptCallback(IAsyncResult ar)
{
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
listening = false;
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
Users.Add(state);
}
}
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();
//user info
}
And For the client i have
public partial class frmClient : Form
{
public frmClient()
{
InitializeComponent();
}
private void frmClient_Load(object sender, EventArgs e)
{
StartClient();
}
private void StartClient()
{
// Connect to a remote device.
try
{
// Establish the remote endpoint for the socket.
IPHostEntry ipHostInfo = Dns.GetHostEntry("Remote Host Address");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
// Create a TCP/IP V4 socket.
Socket client = new Socket(ipAddress.AddressFamily,
SocketType.Stream, ProtocolType.Tcp);
// Connect to the remote endpoint.
client.BeginConnect(remoteEP,
new AsyncCallback(ConnectCallback), client);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private void ConnectCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket client = (Socket)ar.AsyncState;
// Complete the connection.
client.EndConnect(ar);
// Signal that the connection has been made.
Console.WriteLine("Socket connected to {0}",
client.RemoteEndPoint.ToString());
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
i created form appliction, and tried to make chat with socket i have problem when its execute line "acc = sck.Accept();" the form freez and cant press any button whats is in Form, basicly, freez! What im foing wrong? Doing by tutorial
static Socket sck;
static Socket acc;
static int port = 9000;
static IPAddress ip;
static Thread rec;
private void button2_Click(object sender, EventArgs e){
rec = new Thread(recV);
ip = IPAddress.Parse(GetIp());
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(ip, port));
sck.Listen(0);
acc = sck.Accept();
/*while (true)
{
byte[] sdata = Encoding.ASCII.GetBytes("TEST");
acc.Send(sdata, 0, sdata.Length, 0);
}*/
}
Use AcceptAsync like this:
private async void button2_Click(object sender, EventArgs e){
rec = new Thread(recV);
ip = IPAddress.Parse(GetIp());
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(ip, port));
sck.Listen(0);
acc = await sck.AcceptAsync();
//This will block here, let the UI thread continue and then resume when a connection is accepted
/*while (true)
{
byte[] sdata = Encoding.ASCII.GetBytes("TEST");
acc.Send(sdata, 0, sdata.Length, 0);
}*/
}
Note that the method is now async and I'm using await in front of theAcceptAsync` call.
If you want your Send/Receive methods to also free the UI, look into their corresponding Async method.
In a project there is a device that listens on a specific UDP port and answers to the senders port.
For the sender and receiver I want the system to choose a free port, so I have the following code:
[Please excuse the vast masses of code, but this is the smallest example to show what behaviour occurs]
Sending code:
public class UdpSender
{
public int Port = 0; // some initially random port
public UdpClient UdpServer { get; set; }
public UdpSender()
{
UdpServer = CreateUdpClient();
// save the portnumber chosen by system to reuse it
Port = ((IPEndPoint)(UdpServer.Client.LocalEndPoint)).Port;
}
private UdpClient CreateUdpClient()
{
if (UdpServer != null)
{
UdpServer.Close();
}
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, Port);
var udpServer = new UdpClient();
udpServer.ExclusiveAddressUse = false;
udpServer.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpServer.Client.Bind(localEndPoint);
return udpServer;
}
public void Send(byte[] arr)
{
UdpServer = CreateUdpClient();
int remotePortNumber = 6565;
var remoteEndPoint = new IPEndPoint(IPAddress.Broadcast, remotePortNumber);
try
{
UdpServer.Send(arr, arr.Length, remoteEndPoint);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
UdpServer.Close();
}
}
Receiving code:
public class UDPListener
{
private static int portNumber;
private UdpClient udpClient = null;
public List<DeviceData> DeviceList = new List<DeviceData>();
public UDPListener(int port)
{
portNumber = port;
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Any, portNumber);
udpClient = new UdpClient();
udpClient.ExclusiveAddressUse = false;
udpClient.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
udpClient.Client.Bind(localEndPoint);
udpClient.Client.ReceiveBufferSize = 1 << 23;
}
public void StartListening()
{
this.udpClient.BeginReceive(Receive, new object());
}
private void Receive(IAsyncResult ar)
{
IPEndPoint ip = new IPEndPoint(IPAddress.Any, portNumber);
byte[] bytes = udpClient.EndReceive(ar, ref ip);
string message = Encoding.ASCII.GetString(bytes);
DeviceList.Add(new DeviceData(message));
StartListening();
}
}
Bringing it together:
public class DeviceFinder
{
public IEnumerable<DeviceData> Find()
{
var sender = new UdpSender();
int port = sender.Port;
var listener = new UDPListener(port);
listener.StartListening();
sender.Send(new byte[] { 0x1, 0x2, 0x3, 0x4, 0x5, 0x6 });
System.Threading.Thread.Sleep(5000); // wait some time for answers
return listener.DeviceList;
}
}
The Receive method is never called with this approach. But in Wireshark, I can see an answer coming from the device.
What is wrong about this approach?
Before using this approach, I have used a fixed port and the call to CreateUdpClient was added also. Seems to have something to with that, but I cannot figure it out.
Before I just created a UdpClient with the fixed port just inside the receive / send method.
The previous version can be seen in this question. This works perfectly. But I fear if the fixed port is already in use, it does not work, hence this new approach.
Just specify zero as your own port number. The system will allocate one when you bind or send. The source port number will accompany the datagram to the peer, who should reply to it.
tried to solve this alone for the past I don't even know but no googling will help me here, I would need some advice with this one. I am receiving UDP packets from another PC on my local network every 10 seconds, can see them in wireshark but the application is stuck on the udpClient.Receive() line. The multicast group and port are the right values, checked in main() n+1 times. Please suggest a solution if you have any idea that might help. Thanks.
(I'm trying to receive the server's information so that th application can automaticaly start to communicate vith it via TCP)
class MulticastListener {
private UdpClient udpClient;
private IPEndPoint remoteEndPoint;
IPAddress multicastIP;
private int port;
public MulticastListener(ref IPAddress multicastIP, int port) {
remoteEndPoint = new IPEndPoint(IPAddress.Any, port);
this.multicastIP = multicastIP;
this.port = port;
udpClient = new UdpClient();
udpClient.Client.Bind(remoteEndPoint);
}
public IPEndPoint GetServer() {
try {
udpClient.JoinMulticastGroup(multicastIP);
} catch (ObjectDisposedException e) {
Console.WriteLine("ERROR: The underlying socket has been closed!");
} catch (SocketException e) {
Console.WriteLine("ERROR: An error occurred when accessing the socket!");
} catch (ArgumentException e) {
Console.WriteLine("ERROR: The IP address is not compatible with the AddressFamily value that defines the addressing scheme of the socket!");
}
Byte[] serverInfoBytes = udpClient.Receive(ref remoteEndPoint);
Stream stream = new MemoryStream(serverInfoBytes); //receives a serialised IPEndpoint object
BinaryFormatter formatter = new BinaryFormatter();
udpClient.Close();
return (IPEndPoint)formatter.Deserialize(stream);
}
}
As I commented, your code works fine for me 100% as is. I would check you are sending on the same subnet you are receiving on. Perhaps your sender is not configured to the right interface?
Perhaps it would help to try out a different sender, here is what I used to test:
static void Main(string[] args)
{
//Configuration
var interfaceIp = IPAddress.Parse("192.168.9.121");
var interfaceEndPoint = new IPEndPoint(interfaceIp, 60001);
var multicastIp = IPAddress.Parse("230.230.230.230");
var multicastEndPoint = new IPEndPoint(multicastIp, 60001);
//initialize the socket
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
socket.ExclusiveAddressUse = false;
socket.MulticastLoopback = false;
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, 1);
MulticastOption option = new MulticastOption(multicastEndPoint.Address, interfaceIp);
socket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.AddMembership, option);
//bind on a network interface
socket.Bind(interfaceEndPoint);
//initialize args for sending packet on the multicast channel
var sockArgs = new SocketAsyncEventArgs();
sockArgs.RemoteEndPoint = multicastEndPoint;
sockArgs.SetBuffer(new byte[1234], 0, 1234);
//send an empty packet of size 1234 every 3 seconds
while (true)
{
socket.SendToAsync(sockArgs);
Thread.Sleep(3000);
}
}
I am attempting to build a simple C# TCP proxy for my business so I can block certain websites from my employees. All is well except I am having trouble seeing what website the user is trying to visit... I can see that the user has connected to my proxy server so I know I am getting connections but the OnRecieve callback isn't even firing. Am I reading from the socket wrong?
Here is my code:
internal class AsyncState
{
public const int BufferSize = 4096;
public byte[] Buffer = new byte[AsyncState.BufferSize];
public Socket Socket;
public StringBuilder Content = new StringBuilder();
}
private void OnLoad(object sender, EventArgs e)
{
IPAddress[] addressCollection = Dns.GetHostAddresses(Dns.GetHostName());
foreach (IPAddress ipAddress in addressCollection)
{
if (ipAddress.AddressFamily == AddressFamily.InterNetwork)
{
localEndPoint = new IPEndPoint(ipAddress, 8080);
Console.WriteLine("Local IP address found... " + localEndPoint.ToString());
break;
}
}
isListening = true;
thread = new Thread(new ThreadStart(
delegate()
{
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(localEndPoint);
serverSocket.Listen(10);
while (isListening)
{
resetEvent.Reset();
Console.WriteLine("Waiting for clients...");
serverSocket.BeginAccept(new AsyncCallback(OnAccept), serverSocket);
resetEvent.WaitOne();
}
}));
thread.Start();
}
}
private void OnAccept(IAsyncResult result)
{
resetEvent.Set();
Socket clientSocket = (result.AsyncState as Socket).EndAccept(result);
Console.WriteLine("Client has connected... " + clientSocket.RemoteEndPoint.ToString());
AsyncState state = new AsyncState();
state.Socket = clientSocket;
state.Socket.BeginReceive(state.Buffer, 0, AsyncState.BufferSize, SocketFlags.None, new AsyncCallback(OnRecieve), state);
}
private void OnRecieve(IAsyncResult result)
{
AsyncState state = result.AsyncState as AsyncState;
int totalRead = state.Socket.EndReceive(result);
if (totalRead > 0)
{
state.Content.Append(Encoding.ASCII.GetString(state.Buffer, 0, totalRead));
state.Socket.BeginReceive(state.Buffer, 0, AsyncState.BufferSize, SocketFlags.None, new AsyncCallback(OnRecieve), state);
}
else
{
if (state.Content.Length > 1)
Console.WriteLine("Message recieved from client... " + state.Content.ToString());
state.Socket.Close();
}
}
Building a well working proxy is no simple task as you will have to understand and handle HTTP etc. in both directions...
I would recommend to either use an existing library for that OR some configurable proxy...
http://www.mentalis.org/soft/projects/proxy/ (with source)
http://sourceforge.net/p/portfusion/home/PortFusion/ (with source)
http://www.wingate.com/
http://www.squid-cache.org/
REMARK:
I don't know in which jurisdiction you are but using such technology without knowledge/consent of employees can in some places be a problem...
Another point: Instead of using such methods I would tell the employee to stop abusing the internet connection of the company 1-3 times and if that doesn't work I would rather fire that person... such employees is not only abusing the internet connection of the company but in worstcase is putting the company at risk (virus/trojan etc.) and also defrauding the company (if he does this in work hours)...