I have a class where i listen for connections in a separated thread, my problem is that when i try close the socket, comes a exception in Socket.Accept(); that says:
A blocking operation was interrupted by a call to WSACancelBlockingCall
After a seach, i understood that probably this is because i'm closing the socket from another thread (in my case this thread is UI). How i can close and open the socket correctly anytime?
Listener
class Listener
{
private Socket s;
private bool listening = false;
public bool Running
{
get { return listening; }
}
public Listener()
{
s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
}
public void BeginListen(int port)
{
s.Bind(new IPEndPoint(IPAddress.Any, port));
s.Listen(100);
listening = true;
while (listening)
{
Socket clientSocket = s.Accept();
}
}
public void StopListen()
{
if (listening == true)
{
s.Close();
listening = false;
}
}
}
frmMain
public partial class frmMain : Form
{
private Listener listener;
private void frmMain_Load(object sender, EventArgs e)
{
listener = new Listener();
}
private void listen()
{
listener.BeginListen(101);
}
private void stopToolStripMenuItem_Click(object sender, EventArgs e)
{
listener.StopListen();
}
private void tmrcheck_Tick(object sender, EventArgs e)
{
if (listener.Running)
{
startToolStripMenuItem.Enabled = false;
stopToolStripMenuItem.Enabled = true;
}
if (!listener.Running)
{
startToolStripMenuItem.Enabled = true;
stopToolStripMenuItem.Enabled = false;
}
}
}
Related
WPF MainWindow closes automatically soon after showed for 1 sec. I have only this mainwindow in the wpf project. There is no error showing when running the application. Without showing any error, the MainWindow simply closes soon after loaded. There is nothing code in App.xaml.cs.
Here is the code written in the MainWindow.
public partial class MainWindow : Window
{
private Socket clientSocket;
private byte[] buffer;
public MainWindow()
{
InitializeComponent();
}
private bool CheckField()
{
if (txtIP.Text == string.Empty)
{
MessageBox.Show("Please specify IP Address");
return false;
}
if (txtPort.Text == string.Empty)
{
MessageBox.Show("Please specify Port Number");
return false;
}
return true;
}
private void btnGreen_Click(object sender, RoutedEventArgs e)
{
if(CheckField()) SendMessage("GREEN");
}
private void btnRed_Click(object sender, RoutedEventArgs e)
{
if (CheckField()) SendMessage("RED");
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
try
{
clientSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// if below code commented, window will not close
clientSocket.BeginConnect(new IPEndPoint(IPAddress.Loopback,
3333), new AsyncCallback(ConnectCallback), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void ConnectCallback(IAsyncResult ar)
{
clientSocket.EndConnect(ar);
}
public void SendMessage(string xmlstring)
{
try
{
byte[] xmlbuffer = Encoding.ASCII.GetBytes(xmlstring);
clientSocket.BeginSend(xmlbuffer, 0, xmlbuffer.Length,
SocketFlags.None, new AsyncCallback(SendCallback), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void SendCallback(IAsyncResult ar)
{
clientSocket.EndSend(ar);
buffer = new byte[clientSocket.ReceiveBufferSize];
}
}
What's wrong in here ???
Everything is going fine with connection , except when i close the connection and reopen (everything fine till now , data is received fine).
The error pops up when I try to write in the stream :
Cannot access a disposed object: 'System.Net.Sockets.NetworkStream' !!
I have tried using a new instance of client each time I connect
When closing connection : i have tried all these things like _client.GetStream().Close();
_client.Close();
but everything fail
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myform = this;
}
public static Form1 myform;
Client c1;
public void ConnectButton_Click(object sender, EventArgs e)
{
c1 = new Client();
try
{ c1.Connect(IPADRESStext.Text, PORTNUMBERtext.Text); }
catch (Exception ex)
{ MessageBox.Show(ex.ToString()); }
}
private void CloseButton_Click(object sender, EventArgs e)
{
c1.Disconnect();
}
}
public sealed partial class Client
{
public void SendData(byte[] data)
{ _sender.SendData(data); }
public event EventHandler<DataReceivedEventArgs> DataReceived;
public void Connect(string IPADRESStxt, string PORTNUMBERtxt)
{
sq = new sequence();
_client = new TcpClient(IPADRESStxt, Int32.Parse(PORTNUMBERtxt));
_stream = _client.GetStream();
_sender = new Sender(_stream);
_receiver = new Receiver(_stream);
_receiver.DataReceived += OnDataReceived;
}
public void Disconnect()
{
_stream.Close();
_client.Close();
//_client.Client.Disconnect(false);
//tcpClient.GetStream().Close();
//tcpClient.Close();
}
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
var handler = DataReceived;
if (handler != null) DataReceived(this, e); // re-raise event
}
private TcpClient _client;
private NetworkStream _stream;
private Receiver _receiver;
private Sender _sender;
}
public sealed partial class Client
{
private sealed class Sender
{
internal void SendData(byte[] data)
{
_stream.Write(data, 0, data.Length); /// 2 When trying to execute this instruction
}
internal Sender(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// Code Code Code
SendData(Sframe); /// 1 Error pops up here
}
private NetworkStream _stream;
private Thread _thread;
}
}
I'm quite new to sockets programming. I hope the problem is presented understandable.
The problem is that when I use Client's button1_click to send textbox's
content - the server only gets the first message. I have no idea what's going wrong.
What might be the problem?
Here is Server:
public partial class Form1 : Form
{
Socket server;
byte[] byteData = new byte[1024];
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
server = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint endPoint = new IPEndPoint(IPAddress.Any, 20000);
server.Bind(endPoint);
server.Listen(1);
server.BeginAccept(new AsyncCallback(Accept), null);
textBox1.Text = "Server started...";
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Accept(IAsyncResult ar)
{
try
{
Socket client = server.EndAccept(ar);
server.BeginAccept(new AsyncCallback(Accept), null);
client.BeginReceive(byteData, 0, byteData.Length,
SocketFlags.None, new AsyncCallback(Receive), client);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Receive(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
client.EndReceive(ar);
textBox1.Invoke(new Action(delegate ()
{
textBox1.AppendText(Environment.NewLine
+ Encoding.ASCII.GetString(byteData));
}));
byteData = null;
}
}
And here is client:
public partial class Form1 : Form
{
Socket client;
public Form1()
{
InitializeComponent();
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text == null)
button1.Enabled = false;
else
button1.Enabled = true;
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
client = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint ipEndPoint = new IPEndPoint(ip, 20000);
client.Connect(ipEndPoint);
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void button1_Click(object sender, EventArgs e)
{
try
{
byte[] byteData = Encoding.ASCII.GetBytes(textBox1.Text);
client.BeginSend(byteData, 0, byteData.Length, SocketFlags.None,
new AsyncCallback(Send), null);
textBox1.Text = String.Empty;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void Send(IAsyncResult ar)
{
try
{
client.EndSend(ar);
}
catch (ObjectDisposedException)
{ }
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
In Async, you got to re-init the BeginReceive in the server side whenever you want to listen to a message.
Therefore, in your Receive callback, you should re-init your BeginReceive after EndReceive. Otherwise you cannot get the next message:
private void Receive(IAsyncResult ar)
{
Socket client = (Socket)ar.AsyncState;
client.EndReceive(ar);
client.BeginReceive(byteData, 0, byteData.Length, //add BeginReceive again
SocketFlags.None, new AsyncCallback(Receive), client);
textBox1.Invoke(new Action(delegate ()
{
textBox1.AppendText(Environment.NewLine
+ Encoding.ASCII.GetString(byteData));
}));
byteData = null;
}
For more of working example with Async, check this out: Sending a value from server to client with sockets
Im learning how to use Async tcp sockets server/client
Cant figure out why my server is not continue listening to data sent from the client...
The messagebox just appear once, then I need to re-open the server
This is my code ( Client )
public partial class Form1 : Form
{
private Socket client;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.BeginConnect(new IPEndPoint(IPAddress.Loopback, 8888), new AsyncCallback(ConnectCallback), null);
}
catch
{
}
}
private void ConnectCallback(IAsyncResult AR)
{
try
{
client.EndConnect(AR);
}
catch
{
}
}
private void SendCallback(IAsyncResult AR)
{
try
{
client.EndSend(AR);
}
catch
{
}
}
private void button1_Click(object sender, EventArgs e)
{
byte[] buffer = Encoding.ASCII.GetBytes("Hello World!");
client.BeginSend(buffer, 0, buffer.Length, 0, new AsyncCallback(SendCallback), null);
}
}
Server
private Socket sck, sckc;
private byte[] buffer;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
try
{
sck = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
sck.Bind(new IPEndPoint(IPAddress.Any, 8888));
sck.Listen(0);
sck.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
catch
{
}
}
private void AcceptCallback(IAsyncResult AR)
{
try
{
while (true)
{
sckc = sck.EndAccept(AR);
buffer = new byte[sckc.ReceiveBufferSize];
sckc.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
}
catch
{
}
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
string text = Encoding.ASCII.GetString(buffer);
MessageBox.Show(text);
}
catch
{
}
}
Get rid of the while loop. In the receive callback, you have to call BeginReceive() again so you can listen for the next set of packets:
private void AcceptCallback(IAsyncResult AR)
{
try
{
sckc = sck.EndAccept(AR);
buffer = new byte[sckc.ReceiveBufferSize];
sckc.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
catch
{
}
}
private void ReceiveCallback(IAsyncResult AR)
{
try
{
string text = Encoding.ASCII.GetString(buffer);
MessageBox.Show(text);
sckc.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), null);
}
catch
{
}
}
If you intend on having multiple connections then you need to maintain a separate buffer for each connection.
onrecvdChanged is an event (of Server Class) once occured I want it to change the text of label1 of the form1 class. I've been stuck here for a long time. I tried a few tricks but I get a cross thread exception.
namespace TCPServerTutorial
{
public partial class Form1 : Form
{
Server a;
public Form1()
{
InitializeComponent();
label1.Text = "Ready";
a=new Server(this);
}
private void Start_btn_Click(object sender, EventArgs e)
{
a.StartTcpServer();
label1.Text = "Listening...";
}
private void Stop_Btn_Click(object sender, EventArgs e)
{
a.StopListenForClients();
label1.Text = "Stopped...";
}
}
class Server
{
public event EventHandler recvdChanged;
private TcpListener tcpListener;
private Thread listenThread;
private string recvd;
Form1 _f1parent;
public Server(Form1 par)
{
_f1parent = par;
}
public string getsetrecvd
{
get { return this.recvd; }
set
{
this.recvd = value;
if (this.recvdChanged != null)
this.recvdChanged(this, new EventArgs());
}
}
public void StartTcpServer()
{
this.tcpListener = new TcpListener(IPAddress.Any, 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
if(client.Connected)
{
MessageBox.Show(client.Client.RemoteEndPoint + " Has Connected.");
}
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
public void StopListenForClients()
{
tcpListener.Stop();
}
private void HandleClientComm(object client)
{
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
recvdChanged += new EventHandler(onrecvdChanged);
byte[] message = new byte[4096];
int bytesRead;
Form1 p = new Form1();
while (true)
{
bytesRead = 0;
try
{
//blocks until a client sends a message
bytesRead = clientStream.Read(message, 0, 4096);
}
catch
{
//a socket error has occured
break;
}
if (bytesRead == 0)
{
//the client has disconnected from the server
break;
}
//message has successfully been received
ASCIIEncoding encoder = new ASCIIEncoding();
getsetrecvd=encoder.GetString(message, 0, bytesRead);
if (recvd != "e")
{
}
else
{
break;
}
}
tcpClient.Close();
}
void onrecvdChanged(object sender, EventArgs e)
{
MessageBox.Show("event: " + recvd);
}
}
}
You already have an event that is fired when the string is changed, recvdChanged. Just have the form add an event handler to that event and then invoke to the UI thread:
public Form1()
{
InitializeComponent();
label1.Text = "Ready";
a=new Server(this);
a.recvdChanged += (_,args) => Invoke(new MethodInvoker(
()=>label1.Text = a.getsetrecvd));
}
There is no need for the event handler for that event inside of the Server class itself.
A cross thread exception is usually fixed by the use of Invoke.
I find the simplest way is to use a MethodInvoker cast and a Lambda expression...something like:
Invoke((MethodInvoker)( () => Form1.Label1.Text = "some string" ) );