C# TCP add Client thread-safe List<T> - c#

In the below code I am adding new clients to the clientList:
public partial class Form1 : Form
{
TcpListener tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
private int appStatus = 0;
TcpClient client;
TcpClient streamData;
List<TcpClient> clientList = new List<TcpClient>();
NetworkStream networkStream;
Thread th_StartListen, th_inPutStream, th_outPutStream, th_checkConnection;
StringBuilder strOutput;
public Form1()
{
InitializeComponent();
customizeDesign();
}
private void Form1_Load(object sender, EventArgs e)
{
th_StartListen = new Thread(new ThreadStart(StartListen));
th_StartListen.Start();
txtCmdOutput.Focus();
}
private void StartListen()
{
//Creating a TCP Connection and listening to the port
tcpListener = new TcpListener(System.Net.IPAddress.Any, 6666);
tcpListener.Start();
toolStripStatusLabel1.Text = "Listening on port 6666 ...";
int counter = 0;
appStatus = 0;
while (true)
{
try
{
client = tcpListener.AcceptTcpClient();
counter++;
clientList.Add(client);
clientList.AsParallel().ForAll(item => clientList.Add(client));
Parallel.ForEach(clientList, item =>
{
lock (clientList)
clientList.Add(client);
});
IPEndPoint ipend = (IPEndPoint)client.Client.RemoteEndPoint;
//Updating status of connection
toolStripStatusLabel1.Text = "Connected from " + IPAddress.Parse(ipend.Address.ToString());
appStatus = 1;
th_outPutStream = new Thread(delegate () { outPutStream(client); });
th_outPutStream.Start();
th_inPutStream = new Thread(delegate () { inPutStream(client); });
th_inPutStream.Start();
th_checkConnection = new Thread(checkConnection);
th_checkConnection.Start();
}
catch (Exception err)
{
{
Cleanup();
}
}
}
}
I was advised that using a non-thread-safe List<T> to keep a list of clients is not a good solution.
So I was wondering how I could apply a thread-safe List<T> as to add the clients without encountering any errors.
So I attempted to do the following:
clientList.AsParallel().ForAll(item => clientList.Add(client));
Could anyone suggest a correct methodology?
Is the above code thread-safe? Is there a chance of the processed list getting could get corrupted? Or should I use a lock before adding?
Parallel.ForEach(clientList, item =>
{
lock (clientList)
clientList.Add(client);
});

The questions were answered in the comments.

Related

ReceiveAsync creates an exception when socket accepts a new connection after closing the old one

public class AsynchronousClient
{
private const int port = 7777;
public static ManualResetEvent allDone = new ManualResetEvent(false);
public class AppServer
{
Socket serverSocket = null;
void accept()
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.Completed += new EventHandler<SocketAsyncEventArgs>(e_Completed);
bool raiseEvent = serverSocket.AcceptAsync(e);
while (true)
{
if (!raiseEvent)
AcceptCallback(e);
}
}
public void Start()
{
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(IPAddress.Parse("0.0.0.0"), 7777));
serverSocket.Listen(100);
serverSocket.Blocking = false;
accept();
}
void e_Completed(object sender, SocketAsyncEventArgs e)
{
AcceptCallback(e);
}
Socket clientSocket;
private void AcceptCallback(SocketAsyncEventArgs e)
{
SocketAsyncEventArgs readEventArgs = new SocketAsyncEventArgs();
byte[] buffer = new byte[1024];
readEventArgs.SetBuffer(buffer, 0, buffer.Length);
readEventArgs.Completed += new EventHandler<SocketAsyncEventArgs>(readEventArgs_Completed);
clientSocket = e.AcceptSocket;
while (true)
{
allDone.Reset();
bool raiseEvent = clientSocket.ReceiveAsync(readEventArgs); // <-- Error goes here
if (!raiseEvent)
ReceiveCallback(readEventArgs);
allDone.WaitOne();
}
}
void readEventArgs_Completed(object sender, SocketAsyncEventArgs e)
{
ReceiveCallback(e);
}
private void ReceiveCallback(SocketAsyncEventArgs e)
{
allDone.Set();
if (e.BytesTransferred > 0)
clientSocket.Send(e.Buffer);
else
{
accept(); }
}
private void SendCallback(SocketAsyncEventArgs e)
{
}
}
public static int Main(String[] args)
{
AppServer a = new AppServer();
a.Start();
return 0;
}
}
Hello. The idea of this code is to run the program, connect with netcat, and whatever i send from netcat, it needs to be echoed back to it. It works fine, until i close netcat, reopen it, connect to the server and when i send a message, it crashes on ReceievAsync. It says:"An asynchronous socket operation is already in progress using this SocketAsyncEventArgs instance.". I can't figure out why. Does anyone understand why?
You shouldn't use a loop in the AcceptCallback, instead you should call the serverSocket.AcceptAsync(e); at the end of the method.
At the end of ReceiveCallback you should call the clientSocket.ReceiveAsync(readEventArgs) again to continue receiving. (not loop needed)
while (true)
{
if (!raiseEvent)
AcceptCallback(e);
}
// ^^^^^^^^^^^^^^^^^^^^^
// Doesn't look right....
I never used the ReceiveAsync. The BeginReceive/EndReceive are much easier.

TcpListener does not receive data

So my homework is to write a POP3 messaging software using tcp packets and im not allowed to use external libraries. I start the tcp connection when i press the Connect button and i also have a Disconnect button which stops it. I tested my server program with PuTTY and it works fine after the first connection but when i press Disconnect and Connect again it doesnt print the received data to the monitor. This problem is bothering me for ages please help. Here is my code:
Edit:
The problem was that i dont quite understand how threads work and i didnt create a new thread for each connection so i instantiated a new thread every time i created a new listener.
namespace POP3Server
{
public partial class MainWindow : Window
{
private TcpListener server;
private Int32 port;
private IPAddress ipAddress;
private TcpClient client;
private Logger log;
private Thread tcpAcceptThread;
private bool serverStarted;
public MainWindow()
{
InitializeComponent();
log = new Logger(txtConsole);
serverStarted = false;
tcpAcceptThread = new Thread(GetData);
}
private void btnConnect_Click(object sender, RoutedEventArgs e)
{
try
{
port = Convert.ToInt32(txtPort.Text);
ipAddress = IPAddress.Parse(txtIP.Text);
server = new TcpListener(ipAddress, port);
server.Start();
if (tcpAcceptThread.ThreadState != ThreadState.Unstarted)
tcpAcceptThread.Start();
serverStarted = true;
log.WriteLine("Server started!");
btnConnect.IsEnabled = false;
btnDisconnect.IsEnabled = true;
}
catch (Exception ex)
{
log.WriteLine(ex.ToString());
}
}
private void btnDisconnect_Click(object sender, RoutedEventArgs e)
{
try
{
if (client != null)
client.Close();
server.Stop();
log.WriteLine("Server stopped!");
serverStarted = false;
btnConnect.IsEnabled = true;
btnDisconnect.IsEnabled = false;
}
catch (Exception ex)
{
log.WriteLine(ex.ToString());
}
}
private void GetData()
{
try
{
while (serverStarted)
{
client = server.AcceptTcpClient();
this.Dispatcher.Invoke(() => log.WriteLine("Connected!"));
Byte[] bytes = new Byte[256];
String data = null;
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);
this.Dispatcher.Invoke(() => log.WriteLine("Received: " + data));
}
}
}
catch (Exception ex)
{
this.Dispatcher.Invoke(() => log.WriteLine(ex.ToString()));
}
}
private void btnClear_Click(object sender, RoutedEventArgs e)
{
log.Clear();
}
}
}
Could you change following code
private bool serverStarted;
to:
private object _someLockObject = new object();
private bool _serverStarted = false;
private bool serverStarted {
get {
lock (_someLockObject)
{
return _serverStarted;
}
}
set {
lock (_someLockObject)
{
_serverStarted = value;
}
}
};
My first hunch is boolean property is not updated.

how to get tcp client ip and port in c# and show that?

I want to get tcp client ip address and port but I can't to do that.I want to use socket in my code except tcp listener class and my goal is get client ip and port without this class. below is my code:(I want to get client ip address and port before if(rc){} condition)
namespace Example
{
public partial class TCP_Server : Form
{
Socket socketServer = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
Socket socketClient = null;
public TCP_Server()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
}
private void Form1_Load(object sender, EventArgs e)
{
}
public void start()
{
IPEndPoint ipens = new IPEndPoint(IPAddress.Parse(txt_ip.Text), int.Parse(txt_port.Text));
socketServer.Bind(ipens);
MessageBox.Show("wait");
while (true)
{
socketServer.Listen(2);
socketClient = socketServer.Accept();
MessageBox.Show("accept");
Thread trgetmsg = new Thread(new ThreadStart(getmsg));
trgetmsg.Start();
}
}
public void getmsg()
{
int counter = 0;
string[] barray2 = new string[10];
try
{
while (true)
{
byte[] barray = new byte[1024];
EndPoint iprec = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4040);
int rc = socketClient.ReceiveFrom(barray , ref iprec);
barray2[counter] = Encoding.Unicode.GetString(barray, 0, rc);
counter =counter+1;
if (rc > 0)
{
MessageBox.Show(iprec.);
if (barray2[0] == barray2[1])
{
listBox1.Items.Add("client: " + Encoding.Unicode.GetString(barray, 0, rc));
socketClient.Send(Encoding.Unicode.GetBytes(barray2[0]));
}
}
}
}
catch { ;}
}
This will provide endpoint info of accepted client;
socketClient = socketServer.Accept();
var endPoint = (IPEndPoint)socketClient.RemoteEndPoint;

Cross thread operation on the server code

I am new in server client programming so i wrote this server code
namespace TCP_SERVER
{
public partial class Form1 : Form
{
private ArrayList nSockets;
public Form1()
{
InitializeComponent();
}
public void listenerThread()
{
new TcpListener(IPAddress.Any, 8080);
TcpListener tcpListener = new TcpListener(8080);
tcpListener.Start();
while (true)
{
Socket handlerSocket = tcpListener.AcceptSocket();
if (handlerSocket.Connected)
//try
//{
{
lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.");
lock (this)
{
nSockets.Add(handlerSocket);
}
ThreadStart thdstHandler = new
ThreadStart(handlerThread);
Thread thdHandler = new Thread(thdstHandler);
thdHandler.Start();
}
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message);
//}
}
}
public void handlerThread()
{
Socket handlerSocket = (Socket)nSockets[nSockets.Count-1];
NetworkStream networkStream = new
NetworkStream(handlerSocket);
int thisRead=0;
int blockSize=1024;
Byte[] dataByte = new Byte[blockSize];
lock(this)
{
// Only one process can access
// the same file at any given time
Stream fileStream = File.OpenWrite(#"C:\Users\KINENE\Documents\submitted.txt");
while(true)
{
thisRead=networkStream.Read(dataByte,0,blockSize);
fileStream.Write(dataByte,0,thisRead);
if (thisRead==0) break;
}
fileStream.Close();
}
lbConnections.Items.Add("File Written");
handlerSocket = null;
}
private void Form1_Load(object sender, EventArgs e)
{
IPHostEntry IPHost = Dns.GetHostByName(Dns.GetHostName());
lblStatus.Text = "My IP address is " + IPHost.AddressList[0].ToString();
nSockets = new ArrayList();
Thread thdListener = new Thread(new ThreadStart(listenerThread));
thdListener.Start();
}
}
}
i get the error on this line of code
lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.");
lock (this)
You are accessing UI elements from another thread, which is not allowed.
You should call Invoke to call the code on the right thread:
this.Invoke((MethodInvoker)delegate()
{
lbConnections.Items.Add(handlerSocket.RemoteEndPoint.ToString() + " connected.");
});

A socket gets delayed from queue after awhile

am trying to use Socket.Select in multi-threaded application , and I don't wanna use async socket , so here is my code :-
public class Server {
private TcpListener m_listener;
private IConnectionFactory m_factory;
private List<Socket> Sockets = new List<Socket>();
private ConcurrentDictionary<Socket, Connection> Clients = new ConcurrentDictionary<Socket, Connection>();
private ConcurrentDictionary<string, ConcurrentQueue<Socket>> Threads = new ConcurrentDictionary<string, ConcurrentQueue<Socket>>();
private int maxsockets = 0;
private object sync = new object();
public Server(string ip, int port, IConnectionFactory factory, int maxsockets) {
IPAddress ipa = IPAddress.Parse(ip);
TcpListener listener = new TcpListener(ipa, port);
this.maxsockets = maxsockets;
m_listener = listener;
m_factory = factory;
int threads = maxsockets <= 100 ? 1 : maxsockets / 100;
for (int i = 0; i < threads; i++) {
Thread th = new Thread(HandelSockets);
th.Name = i.ToString();
Threads.TryAdd(i.ToString(), new ConcurrentQueue<Socket>());
th.Start();
}
}
public void HandelSockets() {
ConcurrentQueue<Socket> queue = Threads[Thread.CurrentThread.Name];
Connection temp;
Socket sock;
while (true) {
try {
lock (sync) {
while (queue.TryDequeue(out sock)) {
if (Clients.TryGetValue(sock, out temp)) {
if (!temp.Alive) {
Sockets.Remove(sock);
Clients.TryRemove(sock, out temp);
} else {
temp.Receive();
Console.WriteLine("recved from thread num : " + Thread.CurrentThread.Name);
}
}
}
}
} catch { }
Thread.Sleep(1);
}
}
public void Run() {
m_listener.Start();
Console.WriteLine("listen started");
Sockets.Add(m_listener.Server);
while (true) {
try {
var temp_list = Sockets.ToList();
Socket.Select(temp_list, null, null, 1000);
foreach (Socket socket in temp_list) {
if (socket == m_listener.Server) {
var sock = m_listener.AcceptSocket();
Sockets.Add(sock);
Connection conn = m_factory.Create(sock);
Clients.TryAdd(sock, conn);
} else if (Clients.Count >= maxsockets) {
Clients[socket].OnMaxConnections();
break;
} else {
if (!Threads.Values.Any(x => x.Contains(socket))) {
var quque = Threads.Values.Where(x => !x.Contains(socket)).OrderBy(x => x.Count).First();
lock (sync) {
quque.Enqueue(socket);
}
}
break;
}
}
} catch {
}
}
}
}
problem is after a while one of the connected sockets will be delayed , one of the sockets will stop sending or receiving until one of the other sockets do so!, or it might take a few secs/minutes until it comeback to receive and send!
I have no clue why would that happen!? maybe the way I select a queue with? , I hope someone can point me to what could make that delay happen thanks.
lock (sync) {
while (queue.TryDequeue(out sock)) {
if (Clients.TryGetValue(sock, out temp)) {
if (!temp.Alive) {
Sockets.Remove(sock);
Clients.TryRemove(sock, out temp);
} else {
temp.Receive();
Console.WriteLine("recved from thread num : " + Thread.CurrentThread.Name);
}
}
}
}
I can't see your implementation of Connection.Receive but if it's a blocking call i.e. doesn't return until it has received data, then that thread would be holding onto a lock on the sync object which is causing your other threads to wait and therefore causing the delay.
Now that you know what is causing the problem you can make the necessary changes, however i highly recommend you use the async methods as it'll perform better and remove the need for locking entirely.
Edit: oh i just realised this is an old question

Categories

Resources