is using the same instance of udpclient on different threads while only receiving/sending thread safe? - c#

im trying to implement a quick thread safe socket for udp. for this Im creating a while true loop for both send and receive that will constantly send/receive information as needed.
I created this in a few minutes just for a rough idea of how it'll work. this is from the belief (that I'm not sure of) that send and receive methods do not affect each other or the object.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Collections.Concurrent;
namespace ConsoleApp1
{
class ThreadSafeSocket
{
private UdpClient udpclient;
private ConcurrentQueue<SendInfo> sendData;
private SendInfo data;
private object recieveLock;
private int port;
public ThreadSafeSocket(int port)
{
this.udpclient = new UdpClient(port);
this.sendData = new ConcurrentQueue<SendInfo>();
this.port = port;
Thread receiveThread = new Thread(RecieveLoop);
Thread sendThread = new Thread(SendLoop);
receiveThread.Start();
sendThread.Start();
}
public void Send(SendInfo data)
{
sendData.Enqueue(data);
}
public SendInfo Receive()
{
lock(recieveLock)
{
byte[] receivedata = new byte[data.Data.Length];
Array.Copy(receivedata, data.Data, data.Data.Length);
IPEndPoint point = new IPEndPoint(data.Point.Address, data.Point.Port);
return new SendInfo(receivedata, point);
}
}
private void SendLoop()
{
while (true)
{
if (sendData.TryDequeue(out SendInfo result))
{
udpclient.Send(result.Data, result.Data.Length,this.data.Point);
}
else
{
Thread.Sleep(1);
}
}
}
private void RecieveLoop()
{
while(true)
{
IPEndPoint point = new IPEndPoint(IPAddress.Any, this.port);
byte[] data = this.udpclient.Receive(ref point);
lock(recieveLock)
{
this.data = new SendInfo(data, point);
}
}
}
}
}
sendinfo consists of a byte array called data, and an ipendpoint called point.
I've heard that thread safety is very hard to test so if the idea itself is wrong id asked before testing. thanks in advance.

Well I got my answer, sockets by themselves already can't receive and send at the same time most likely so this implementation is wrong. It's better instead to just look an instance of udpClient and not the methods.

Related

Threadpool.cs not found in win form

i want write a chatroom with c# and Tcp but i have Threadpool.cs not found error.
this is my error
how to can i fix this ?
this is my code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Client
{
public partial class Client : Form
{
Socket socClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Client()
{
InitializeComponent();
}
private void btnConnect_Click(object sender, EventArgs e)
{
IPEndPoint ipServer = new IPEndPoint(IPAddress.Parse(txtIp.Text), int.Parse(txtPort.Text));
socClient.Connect(ipServer);
}
}
}
In Your Server Side Form1
you tried to update your list box from another thread so you faced this issue
on other to solve it you have to change your code from this :
void Accept(IAsyncResult res)
{
socClient = socServer.EndAccept(res);
listMessage.Items.Add("Client Connected...");
}
to this
private delegate void UpdateListDelegate();
void Accept(IAsyncResult res)
{
socClient = socServer.EndAccept(res);
listMessage.Invoke(new UpdateListDelegate(() =>
{
listMessage.Items.Add("Client Connected...");
}));
}
so the main key is to Invoke your element whenever you are not working with main UI Thread.
Your problem is that you have a cross-thread call. You can hack around that by using Invoke. But I would strongly advise you to switch to async await, which will maintain the current context.
public partial class Client : Form
{
Socket socClient;
public Client()
{
InitializeComponent();
}
private async void btnConnect_Click(object sender, EventArgs e)
{
socClient = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
IPEndPoint ipServer = new IPEndPoint(IPAddress.Parse(txtIp.Text), int.Parse(txtPort.Text));
await socClient.ConnectAsync(ipServer);
}
}
I also suggest you think about whether you want to use raw sockets, as it's much easier to use TcpClient.

c# tcpListener listen for connection status of multiple clients

I am attempting to connect multiple clients to a server and monitor their connection...
I am trying to get a better understanding of TcpListener and TcpClient while creating these programs.
I found my server code from another stackoverflow answer as I am looking to get a connection from multiple clients, I have edited it abit:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace socket_server
{
class connect
{
public class State
{
public Socket workSocket = null;
public const int bufferSize = 1024;
public byte[] buffer = new byte[bufferSize];
public StringBuilder sb = new StringBuilder();
}
public class Server
{
public static ManualResetEvent allDone = new ManualResetEvent(false);
private static IPEndPoint findMe()
{
IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 5505);
return localEndPoint;
}
public static void start()
{
try
{
TcpListener listener = new TcpListener(findMe());
TcpClient client;
listener.Start();
Console.WriteLine("Server IP: {0}\n", findMe());
Console.WriteLine("Waiting for Connection...");
while (true)
{
client = listener.AcceptTcpClient();
ThreadPool.QueueUserWorkItem(threadProc, client);
}
Console.ReadKey();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
private static void threadProc(object obj)
{
try
{
var client = (TcpClient)obj;
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
You call this like connect.Server.start()
This is my current client code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace socket_client
{
class connect
{
public class State
{
public Socket workSocket = null;
public const int bufferSize = 256;
public byte[] buffer = new byte[bufferSize];
public StringBuilder sb = new StringBuilder();
}
public class Client
{
private const int port = 5505;
private static String response = String.Empty;
private static IPEndPoint findServer()
{
IPHostEntry ipHostInfo = Dns.Resolve("10.1.2.30");
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint remoteEP = new IPEndPoint(ipAddress, port);
return remoteEP;
}
public static void start()
{
TcpClient client = new TcpClient();
Console.WriteLine("Server IP: {0}", findServer().ToString());
Console.WriteLine("Client IP: {0}\n", software.getIPAddress());
connect(client);
if (client.Connected)
Console.WriteLine("\nConnected to: {0}\n", findServer().ToString());
}
private static void connect(TcpClient client)
{
try
{
client.Connect(findServer());
} catch(Exception e)
{
Console.WriteLine("Attempting to connect to: {0}", findServer().ToString());
connect(client);
}
}
}
}
}
You call this like connect.Client.start();
My classes such as hardware and software simply just get system information.
I would like to know how to check if a connection is dropped and respond with a Console.WriteLine for both Client and Server.
Edit-
This is what I have working for checking to see if a client drops from the server:
...
private static void threadProc(object obj)
{
try
{
var client = (TcpClient)obj;
Byte[] bytes = new Byte[256];
string data = null;
try {
NetworkStream stream = client.GetStream();
int i;
while((i = stream.Read(bytes,0,bytes.Length)) != 0)
{
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
Console.WriteLine(">{0}: {1}", ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString(), data);
}
} catch(Exception e)
{
Console.WriteLine(">>{0} Lost Connection...", ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString());
}
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
...
You will only be able to detect if a connection was closed when reading on the stream fails, since there is no event which would notify you.
You might raise your own event in the connection-handling class.
But for some reasons, it is possible, that a TCP-Connection drops without a pending Read()-call to fail.
So, there is no perfect method, like handling an event, which always notifies you, when the connection broke. So you have to implement some keep-alive mechanism. E.g. send a ping/pong every once in a while and wait for the answer. If there is no answer in a defined time, you can close the connection.

Can't find TcpClient.GetStream method

I'm watching this video to learn the basics on C# async communication. I'm using Microsoft Visual Studio 2013.
In this line:
_networkStream.Add(client.GetStream());
I'm getting this error:
'System.Collections.Generic.List' does not contain a definition for 'GetStream and no extension method 'GetStream' accepting a first argument of type 'System.Collections.Generic.List' could be found (are you missing a using directive or an assembly reference?)
Currently here's the code I have copied while watching the tutorial:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
namespace Networking
{
public class ServerManager
{
public int Port { get; set; }
private TcpListener _listener;
private List<TcpClient> _client;
private List<NetworkStream> _networkStream;
public ServerManager(int port)
{
// Assigning Port from the parameter.
Port = port;
// Initialize the _listener to the port specified on the constructor.
_listener = new TcpListener(new IPEndPoint(IPAddress.Any, Port));
// Initialize the _client sockets list.
_client = new List<TcpClient>();
// Initialize the _networkStream which is useful for sending and receiving data.
_networkStream = new List<NetworkStream>();
}
public void Start()
{
// Starts the _listener to listen.
_listener.Start();
_listener.BeginAcceptTcpClient(new AsyncCallback(ClientConnect), null);
}
public void Stop()
{
// Closes all the _client sockets and the network stream.
for (int i = 0; i < _client.Count; i++)
{
_client[i].Close();
_networkStream[i].Close();
}
// Stops the listener. The socket which listens and accept incoming client sockets.
_listener.Stop();
}
private void ClientConnect(IAsyncResult ar)
{
// When any client connects.
// Accept the connection.
TcpClient client = _listener.EndAcceptTcpClient(ar);
// Add on our client list.
_client.Add(client);
// Add the client's stream on our network stream.
_networkStream.Add(_client.GetStream());
Thread threadReceive = new Thread(new ParameterizedThreadStart(ClientReceiveData), null);
threadReceive.Start(_client.Count);
// Accept the next connection.
_listener.BeginAcceptTcpClient(new AsyncCallback(ClientConnect), null);
}
private void ClientReceiveData(object obj)
{
throw new NotImplementedException();
}
}
}
Based from MSDN, TcpClient.GetStream method is under the namespace System.Net.Sockets, which I have already included without errors. And so, why am I getting the error?
_client is instance of List, client is instance of TcpClient. You need to use client.GetStream() instead of _client.GetStream().
_networkStream.Add(client.GetStream());
I think it is typo by you.
_networkStream.Add(client.GetStream());

Setting Up UDP C# code

I am very new to sockets with C# and I have been working on trying to get a socket to work with localhost. Here is the main UDP code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class NetUDP
{
private UdpClient udp;
private IPEndPoint endPont;
public NetUDP(int port_local, int port_global, string ip_global, string ip_local)
{
Console.WriteLine(IPAddress.Any.ToString());
udp = new UdpClient(IPAddress.Any.ToString(), port_global);
endPont = new IPEndPoint(IPAddress.Parse(ip_global), port_global);
udp.Connect(ip_global, port_global);
}
public NetUDP()
{
}
public void UDPinit(int port_local, int port_global, string ip_global, string ip_local)
{
Console.WriteLine();
udp = new UdpClient("127.0.0.1", port_global);
endPont = new IPEndPoint(IPAddress.Parse("127.0.0.1"), port_global);
udp.Connect("127.0.0.1", port_global);
}
public void sendDataUDP(string info)
{
Byte[] SendByte = Encoding.ASCII.GetBytes(info);
udp.Send(SendByte, SendByte.Length);
}
public string getDataUDP()
{
Byte[] get = udp.Receive(ref endPont);
return Encoding.ASCII.GetString(get);
}
public void closeUDP()
{
udp.Close();
}
}
}
The problem is every time I do this code when I try to retrieve info from another UDP C# program (on the same machine) it freezes. I know it keeps on looking for info coming it's way, but id there a way to put a timeout on the receive command or do I have to make an event handler to prevent this freezing? The ports connect just fine and do not show any form of error or exception. Thank you for your help in advance!
class Program
{
static void Main(string[] args)
{
var serverEndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8500);
NetUDP udp = new NetUDP(serverEndPoint);
UdpClient localClient = new UdpClient();
Task.Delay(20000);
var dgram = Encoding.ASCII.GetBytes("Hello Server");
localClient.Send(dgram, dgram.Length, serverEndPoint); // Send "Hello Server" to Server
Console.Read();
}
}
class NetUDP
{
private UdpClient udp;
private IPEndPoint endPont;
public NetUDP() { }
public NetUDP(IPEndPoint serverEndPoint)
{
udp = new UdpClient(serverEndPoint); // Bind the EndPoint
// Receive any IPAddress send to the 8555 port
IPEndPoint receiveEndPoint = new IPEndPoint(IPAddress.Any, 8555);
Task.Run(() =>
{
try
{
while (true)
{
// This Receive will block until receive an UdpClient
// So, run in another thread in thread pool
var bytes = udp.Receive(ref receiveEndPoint);
Console.WriteLine(Encoding.ASCII.GetString(bytes));
}
}
catch (Exception ex)
{
// TODO
}
finally
{
udp.Close();
}
});
}
}
Here is and UdpChat demo in github: UdpChat

'System.Net.Sockets.Socket.Dispose(bool)' is inaccessible due to its protection level

I got this error while compiling. what does it mean and how do i resolve it?
'System.Net.Sockets.Socket.Dispose(bool)' is inaccessible due to its protection level
Here are both of my files;
Listener.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace Multi_con_Server
{
class Listener
{
Socket s;
public bool Listening
{
get;
private set;
}
public int Port
{
get;
private set;
}
public Listener(int port)
{
Port = port;
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void Start()
{
if (Listening)
return;
s.Bind(new IPEndPoint(0, Port));
s.Listen(0);
s.BeginAccept(callback, null);
Listening = true;
}
public void Stop()
{
if (!Listening)
return;
s.Close();
s.Dispose();
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
void callback(IAsyncResult ar)
{
try
{
Socket s = this.s.EndAccept(ar);
if (SocketAccepted != null)
{
SocketAccepted(s);
}
this.s.BeginAccept(callback, null);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public delegate void SocketAccecptedHandler(Socket e);
public event SocketAccecptedHandler SocketAccepted;
}
}
Program.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;
namespace Multi_Con_C
{
class Program
{
static void Main(string[] args)
{
Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream,
ProtocolType.Tcp);
s.Connect("127.0.0.1", 8);
s.Close();
s.Dispose();
}
}
}
From MSDN, Socket.Close() automatically "releases all associated resources". You can safely remove all occurances of Socket.Dispose() from your code.

Categories