c# Socket Close , Socket Open - c#

I have a List of Sockets that are connected and live on the Form1
List<Socket> Clients;
For Example i want to Pass on of the Socket to the next Forms as:
Form2 F2 = new Form2();
F2.ClientSocket = Clients[2];
So I want to Close the Socket :
Clients[2]
and let the F2.ClientSocket Opened
just like we're passing the connection from socket to socket !
Thanks for your Time !

use static objects:
Form1:
class Form1
{
public static List<Socket> clients = new List<Socket>();
// your codes
}
Form2:
class Form2
{
public Form2
{
var client = Form1.clients[index];
}
}

Related

Getting unhandled ArgumentException when starting a new thread for a method of an instanced class

I have class HBClient which contains connect() method.
public void connect()
{
//connect to TCP socket
}
This is a winform, and I create instances of my Form1 and HBClient as such.
//Program.CS
Form1 form = new Form1();
HBClient hbClient = new HBClient();
//Form1.CS
//Form1 Class
public HBClient hbClient;
public void GetClient(HBClient receivedHBClient)
{
hbClient = receivedHBClient;
}
//HBClient Class
public Form1 form;
public void GetForm(Form1 receivedForm)
{
form = receivedForm;
}
and link them together...
hbClient.GetForm(form);
form.GetClient(hbClient);
When my form tries to call hbClient.connect in a thread, I get an unhandled ArgumentException.
Thread thread = new Thread(hbClient.connect);
thread.IsBackground = true;
thread.Start();
"Delegate to an instance method cannot have null 'this'."

MDI Form from OnClientConnect static method

I am writing client server app and my server is WinForm.
i am trying to create child form from static method like that
private static void OnClientConnect(IAsyncResult asyn)
{
try
{
TcpClient clientSocket = default(TcpClient);
clientSocket = _listener.EndAcceptTcpClient(asyn);
clientSocket.ReceiveBufferSize = 1024;
frmClient frmClient = new frmClient(clientSocket);
frmClient.Show(this);
}
catch (Exception se)
{
throw;
}
WaitForClientConnect();
}
but "this" is not accepted because i am using it inside static method.
i also tried to create static field holding this and use it.
but also throw cross threads exception.
any suggestions.?
You can store the MDI parent window in a static variable like
public static Form RootForm;
Then you can show a new MDI child, taking cross-threading into account like this.
public static void ShowFormForClient(TcpClient clientSocket) {
// check if we are on a different thread and redirect if so
if (RootForm.InvokeRequired) {
RootForm.Invoke((MethodInvoker) delegate { ShowFormForClient(clientSocket); });
return;
}
var frmClient = new frmClient(clientSocket);
frmClient.MdiParent = RootForm;
frmClient.Show();
}
Note that this code is not tested in any ways, only for demonstration purposes.

Background running server with socket connection

now I have this:
[STAThread]
static void Main()
{
if (flag) //client view
Application.Run(new Main_Menu());
else
{
Application.Run(new ServerForm());
}
}
ServerForm.cs
public partial class ServerForm : Form
{
public ServerForm()
{
InitializeComponent();
BeginListening(logBox);
}
public void addLog(string msg)
{
this.logBox.Items.Add(msg);
}
private void button1_Click(object sender, EventArgs e)
{
}
private async void BeginListening(ListBox lv)
{
Server s = new Server(lv);
s.Start();
}
}
Server.cs
public class Server
{
ManualResetEvent allDone = new ManualResetEvent(false);
ListBox logs;
///
///
/// Starts a server that listens to connections
///
public Server(ListBox lb)
{
logs = lb;
}
public void Start()
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Loopback, 1440));
while (true)
{
Console.Out.WriteLine("Waiting for connection...");
allDone.Reset();
listener.Listen(100);
listener.BeginAccept(Accept, listener);
allDone.WaitOne(); //halts this thread
}
}
//other methods like Send, Receive etc.
}
I would like to run my ServerForm ( it has ListBox to print msg from Server). I know ListBox argument will not work, but I could not run Server inifinite loop without suspend ServerForm ( I could not even move window). I tried it also with Threads - unfortunately it does not work to.
WinForms have something called a UI-thread. Its a thread which is responsible of drawing and handling the UI. If that thread is busy doing something, the UI will stop respond.
The regular socket methods are blocking. That means that they do not return control to your application unless something have happened on the socket. Thus, each time you do a socket operation on the UI thread, the UI will stop responding until the socket method completes.
To get around that, you need to create a separate thread for the socket operations.
public class Server
{
ManualResetEvent allDone = new ManualResetEvent(false);
Thread _socketThread;
ListBox logs;
public Server(ListBox lb)
{
logs = lb;
}
public void Start()
{
_socketThread = new Thread(SocketThreadFunc);
_socketThread.Start();
}
public void SocketThreadFunc(object state)
{
Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(new IPEndPoint(IPAddress.Loopback, 1440));
while (true)
{
Console.Out.WriteLine("Waiting for connection...");
allDone.Reset();
listener.Listen(100);
listener.BeginAccept(Accept, listener);
allDone.WaitOne(); //halts this thread
}
}
//other methods like Send, Receive etc.
}
However, all UI operations MUST take place on the UI thread. This, if you try to update the listbox from the socket thread you will get an exception.
The easiest way to solve that is to use Invoke.

User controls to use same TCP connection as Main Form

I have a form that acts as a client GUI for a TCP client/server project. I have multiple User Controls that act as "pages" that the user can navigate using buttons on the main GUI form.
My issue is; each one of these user controls (as well as the main form) needs to be able to communicate with the server (ie. send messages to it).
Currently to accomplish this I'm opening a new connection every time a new user control is added, by placing the following code in my main form, as well as all of the user control "pages":
public partial class MainForm: Form
{
private IPEndPoint serverEndPoint;
private TcpClient myClient = new TcpClient();
public MainForm()
{
InitializeComponent();
serverEndPoint = new IPEndPoint(IPAddress.Parse(ServerIP), 8888);
myClient.Connect(serverEndPoint);
}
}
private void SendMessage(string msg)
{
NetworkStream clientStream = myClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
What I'd like to be able to do is to have this code on my main form only, and have each user control that's added to the main form use the connection that's already open to communicate. I'm just not sure how I would accomplish this.
Wrap the connection in a static class and create static interface for connecting to the server and sending messages. You will only have to open the connection once, in you main form.
static public class ServerCommunicator
{
static private IPEndPoint serverEndPoint;
static private TcpClient myClient = new TcpClient();
static public void Connect()
{
serverEndPoint = new IPEndPoint(IPAddress.Parse(ServerIP), 8888);
myClient.Connect(serverEndPoint);
}
static public void SendMessage(string msg)
{
NetworkStream clientStream = myClient.GetStream();
ASCIIEncoding encoder = new ASCIIEncoding();
byte[] buffer = encoder.GetBytes(msg);
clientStream.Write(buffer, 0, buffer.Length);
clientStream.Flush();
}
}
And you main form class becomes:
public partial class MainForm: Form
{
public MainForm()
{
InitializeComponent();
ServerCommunicator.Connect();
// Sending a message:
ServerCommunicator.SendMessage("Hello server!");
}
}
ServerCommunicator.Connect() only needs to be called once, in the main form. The other controls can simply call SendMessage.

c# Passing parameters on event from another class to main class

I have a main (Form1) Class, and a second class which handles all the Serial Communication (ComPort)
When a new data is received through the Serial port (Event), I'd like to pass it to the Form1 and do some manipulation on this data.
Little Example: Creating long string from received data
Form1.cs
public partial class Form1 : Form
{
//Creating instance of SerialCommunication.
....
....
string receivedString = ""; //Here I will store all data
public void addNewDataMethod(string newDataFromSerial)
{
receivedString = receivedString + newDataFromSerial;
MessageBox.Show(receivedString);
}
}
SerialCommunication.cs
public partial class SerialCommunicationPort
{
constructor()
{
.... //open serial port with the relevant parameters
ComPort.DataReceived += new SerialDataReceivedEventHandler(ComPortBufferRead);//Create Handler
}
public void ComPortBufferRead(object sender, SerialDataReceivedEventArgs e)
{
//create array to store buffer data
byte[] inputData = new byte[ComPort.BytesToRead];
//read the data from buffer
ComPort.Read(inputData, 0, ComPort.BytesToRead);
//***** What should I write here in order to pass "inputData" to Form1.addNewDataMethod ?
}
}
I Tried the following:
Form1 Form;
Form1.addNewDataMethod(inputData.ToString());
The above code will generate an error: use of unassigned local variable "Form"
Form1 Form1 = new Form1();
Form1.addNewDataMethod(inputData.ToString());
the above will create a new instance of Form1, and will not contain the previous received data.
Any Suggestions ?
Create an event in SerialCommunication class which will be raised when data is arrived:
public partial class SerialCommunicationPort
{
public event Action<byte[]> DataReceived;
public void ComPortBufferRead(object sender, SerialDataReceivedEventArgs e)
{
byte[] inputData = new byte[ComPort.BytesToRead];
ComPort.Read(inputData, 0, ComPort.BytesToRead);
if (DataReceived != null)
DataReceived(inputData);
}
}
Then subscribe to this event in your form.
public partial class Form1 : Form
{
SerialCommunication serialCommunication;
public Form1()
{
InitializeComponent();
serialCommunication = new SerialCommunication();
serialCommunication.DataReceived += SerialCommunication_DataReceived;
}
private void SerialCommunication_DataReceived(byte[] data)
{
// get string from byte array
// and call addNewDataMethod
}
}
If you want to follow Microsoft coding guidelines for WinForms, then instead of Action<byte[]> delegate you should use EventHandler<DataReceivedEventArgs> delegate, where DataReceivedEventArgs is class inherited from EventArgs.
probably the best way would be to use events. Define an event which would an EventArgs parameter that would take a string. In Form1 subscribe to the event and in your serial communication class just trigger the event passing the string you want to the eventargs.
The way you wanted should work as well, but something like this:
Form1 Form = new Form1();
Form.Show(); // to display it...
/// to other stuff...
Form.addNewDataMethod(inputData); // call the method on the INSTANCE which you opened!
similar to usage of methods, you could define a property in Form1 :
private string _myString = "";
public string MyString {
private get {
}
set {
string _myString= value;
// to with the string what you want
}
}
and then similar to the method call use
Form.MyString = "abc";
Hope this help!

Categories