Using the same tcp client from 2 different forms - c#

I am creating a tcpClient on my main form and i am reading and writing to an irc server.
tcpClient = new TcpClient(serverName, 6667);
reader = new StreamReader(tcpClient.GetStream());
writer = new StreamWriter(tcpClient.GetStream());
writer.AutoFlush = true;
at some point my app opens a second form with a listbox of some options and i want to double click on one of these options and write something to the initial stream. I have tried creating a new tcpClient on the same port with a new reader and writer but this does not seem to work.
private void listBox_MouseDoubleClick(object sender, MouseEventArgs e)
{
SendMessage("some message");
}
private void SendMessage(string message)
{
TcpClient tcpClient;
StreamReader reader;
StreamWriter writer;
string serverName = "chicago.il.us.undernet.org";
tcpClient = new TcpClient(serverName, 6667);
reader = new StreamReader(tcpClient.GetStream());
writer = new StreamWriter(tcpClient.GetStream());
writer.AutoFlush = true;
writer.WriteLine("PRIVMSG #chan :" + message + "\r\n");
}
Could anybody point me to the right direction please?

Just like you I am not an expert in C#, I only program as a hobby and I'm self taught. So maybe there is a better way to do this, but this is how I would approach it myself.
Add a new class to your project like this:
namespace Test //If you copy this, remember to change the namespace to match your application
{
class Shared
{
public static TcpClient client = new TcpClient(“server”, 6667);
//OR do this and use the Connect method to connect later (see below)
public static TcpClient client = new TcpClient();
}
}
If you use the second declaration you could then connect later from ANY form (you would only need to connect once) when the form loads or on a button click etc. using this:
Shared.client.Connect(serverName, 6667);
Then in both of your forms you can do the following. Or if the SendMessage() function would be the same for both forms you could always make it a static function in the Shared class and call Shared.SendMessage("your message");.
private void SendMessage(string message)
{
if (Shared.client.Connected)
{
StreamReader reader;
StreamWriter writer;
reader = new StreamReader(Shared.client.GetStream());
writer = new StreamWriter(Shared.client.GetStream());
writer.AutoFlush = true;
writer.WriteLine("PRIVMSG #chan :" + message + "\r\n");
}
}
Using static to declare client in the Shared class means that it is not referenced by an instance of the class. So you don't have to do Shared sharedClass = new Shared(); before you can access it, and if you made 2 instances of the Shared class client would only have one instance which is accessible to both instances of the class.

Related

Simple sending .txt file from one computer to another via TCP/IP

There are two C# projects: one project is for the client, the other one is for the server. First step is to run the server , then to choose a target folder, after that to run the client project, to choose some text.txt to send to the server's target folder.
Only client can send files to the server
Demo:
1.choosing file target 2.client sends
+------------+
| tar folder | <---------------- text.txt
+------------+
My problem: there isn't compile errors or syntax errors in both projects, the only problem is that the server doesn't receives the .txt file.
Client:
First I designed a form for the client such as:
And placed an OpenFileDialog from the ToolBox-> Dialogs-> OpenFileDialog control.
Full code:
namespace SFileTransfer
{
public partial class Form1 : Form
{
string n;
byte[] b1;
OpenFileDialog op;
private void button1_Click(object sender, EventArgs e) //browse btn
{
op = new OpenFileDialog();
if (op.ShowDialog() == DialogResult.OK)
{
string t = textBox1.Text;
t = op.FileName;
FileInfo fi = new FileInfo(textBox1.Text = op.FileName);
n = fi.Name + "." + fi.Length;
TcpClient client = new TcpClient("127.0.0.1", 8100);//"127.0.0.1", 5055
StreamWriter sw = new StreamWriter(client.GetStream());
sw.WriteLine(n);
sw.Flush();
// label2.Text = "File Transferred....";
}
}
private void button2_Click(object sender, EventArgs e) //send btn
{
TcpClient client = new TcpClient("127.0.0.1", 8100);//5050
Stream s = client.GetStream();
b1 = File.ReadAllBytes(op.FileName);
s.Write(b1, 0, b1.Length);
client.Close();
// label2.Text = "File Transferred....";
}
}
}
Server:
Created and designed a Form for Server like:
Then Placed a folderBrowserDialog from the ToolBox->Dialogs-> folderBrowserDialog.
Full code:
namespace SFileTransferServer
{
public partial class Form1 : Form
{
string rd;
byte[] b1;
string v;
int m=1;
TcpListener list;
TcpClient client;
Int32 port = 8100;//5050
Int32 port1 = 8100;//5055
IPAddress localAddr = IPAddress.Parse("127.0.0.1");
private void button1_Click(object sender, EventArgs e) //browse button
{
if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = folderBrowserDialog1.SelectedPath;
list = new TcpListener(localAddr, port1);
list.Start();
client = list.AcceptTcpClient();
MessageBox.Show("ggggggg" + m.ToString());
Stream s = client.GetStream();
b1 = new byte[m];
s.Read(b1, 0, b1.Length);
MessageBox.Show(textBox1.Text);
File.WriteAllBytes(textBox1.Text+ "\\" + rd.Substring(0, rd.LastIndexOf('.')), b1);
list.Stop();
client.Close();
label1.Text = "File Received......";
}
}
private void Form2_Load(object sender, EventArgs e)
{
TcpListener list = new TcpListener(localAddr, port);
list.Start();
TcpClient client = list.AcceptTcpClient();
MessageBox.Show("Client trying to connect");
StreamReader sr = new StreamReader(client.GetStream());
rd = sr.ReadLine();
v = rd.Substring(rd.LastIndexOf('.') + 1);
m = int.Parse(v);
list.Stop();
client.Close();
}
}
}
Based on this page
I'm assuming you are a new coder because I'm seeing a lot of inefficient code.
On the Client App: Don't redeclare the TcpClient, instead declare it in the global scope and just reuse it.
Then On the server side: Always use the correct datatype IF AT ALL possible
Int16 port = 8100;
//same as
int port = 8100;
Then on to the question: First you are only reading a single byte from the received data
int m=1;
byte[] b1 = new byte[m];
s.Read(b1, 0, b1.Length);
//Then if you know the length of the byte, why do the computation of b1.Length, just use
s.Read(b1, 0, 1);
I see now you are also opeing the connection on the Load event. But that variable is not in the global scope so you are essentially creating a variable in the Load event then after the Load event finishes, sending it to the garbage collection and then declaring a variable with the same name in the button click event.
So try declaring the TcpListener object in the global scope then assign it in the load event and start listening.
Now the AcceptTcpClient() method is a blocking method so it will block your thead until it receives a connection attempt at which point it will return the client object. So try to use this instead:
https://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.accepttcpclient(v=vs.110).aspx
using System.Threading;
TcpClient client;
TcpListener server = new TcpListener("127.0.0.1",8100)
Thread incoming_connection = new Thread(ic);
incoming_connection.Start();
private void ic() {
client = server.AcceptTcpClient();
Stream s = client.GetStream();
//And then all the other code
}
Or you can use the Pending method as suggested by MSDN (on the ref page).
EDIT: using threading like this is 'not safe', so if you don't understand threading go read up on it first, this post doesn't cover how to use multi-threading.

C# encapsulation when getting updates from asynchronous method

I have a tcp connection I want to keep open in the HandleConnectionAsync method of the server class. It will be receiving continuous updates from a client.
private async void HandleConnectionAsync(TcpClient tcpClient)
{
Console.WriteLine("Got connection request from {0}", tcpClient.Client.RemoteEndPoint.ToString());
try
{
using (var networkStream = tcpClient.GetStream())
using (var reader = new StreamReader(networkStream))
using (var writer = new StreamWriter(networkStream))
{
writer.AutoFlush = true;
while (true)
{
string dataFromClient = await reader.ReadLineAsync();
Console.WriteLine(dataFromClient);
await writer.WriteLineAsync("FromServer-" + dataFromClient);
}
}
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
}
I want to be able to receive the updates the reader puts into dataFromClient without having to put my code in the midst of my server implementation class.
So:
static void Main(string[] args)
{
Server s = new Server();
s.start();
//get dataFromClient as it comes in here
}
Problem is I'm not sure how to do this. Some kind of callback or event?
There are many many ways.
The least code is to pass an Action to your server eg:
Server s = new Server();
s.start(dataFromClient =>
{
// do something with data from client
});
And in HandleConnectionAsync call the action eg:
private async void HandleConnectionAsync(TcpClient tcpClient, Action<string> callback)
{
..
// Console.WriteLine(dataFromClient);
callback(dataFromClient);
..
However this does not address a few things e.g. many clients at the same time and needing to know which client is which.

How can I send or return List<T> with socket

ther is a server and client sockets. I want to learn a way how can I send a List<T>, IEnumerable<T> object to client to server or server to client.
i want to send server-side TaskManager Threads List to client-side. this code send line by line, I want to send complate list. How can I do it?
private static IEnumerable<string> TaskManager()
{
List<string> lst = new List<string>();
foreach (System.Diagnostics.Process p in
Process.GetProcesses().OrderBy(o => o.ProcessName))
{
lst.Add(p.ProcessName + "_" + p.Id);
}
return lst.AsParallel();
}
....
....
....
while (true)
{
Socket socket = Listener.AcceptSocket();
try
{
//open stream
Stream stream = new NetworkStream(socket);
StreamReader sr = new StreamReader(stream);
StreamWriter sw = new StreamWriter(stream);
sw.AutoFlush = true;
while (true)
{
Parallel.ForEach(
TaskManager(), item=>
sw.WriteLine(item)
);
}
stream.Close();
stream.Dispose();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.WriteLine("Disconnected: {0}", socket.RemoteEndPoint);
socket.Close();
socket.Dispose();
}
You can use BinaryFormatter to serialize and deserialze a List.
using System.Runtime.Serialization.Formatters.Binary;
// Server side
Stream stream = new NetworkStream(socket);
var bin = new BinaryFormatter();
bin.Serialize(stream, TaskManager());
// Client side
Stream stream = new NetworkStream(socket);
var bin = new BinaryFormatter();
var list = (List<string>)bin.Deserialize(stream);
You could implement all aspects of a solution yourself, i.e. serialisation, compression, sending, receiving etc. Most things can be found by reading about WCF or the System.Net namespace. I can however give you a very concise solution using the network library NetworkComms.Net here.
For the client:
using System;
using NetworkCommsDotNet;
namespace Client
{
class Program
{
static void Main(string[] args)
{
//Create a connection
Connection connection = TCPConnection.GetConnection(new ConnectionInfo("127.0.0.1", 10000));
//Make a request for the threadIds and get the answer in one statement.
string[] taskManagerThreadIds = connection.SendReceiveObject<string[]>("ThreadIdRequest", "ThreadIds", 2000);
Console.WriteLine("Server provided an array containing {0} ids", taskManagerThreadIds.Length);
Console.WriteLine("Send completed. Press any key to exit client.");
Console.ReadKey(true);
NetworkComms.Shutdown();
}
}
}
For the server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Diagnostics;
using NetworkCommsDotNet;
namespace Server
{
class Program
{
static void Main(string[] args)
{
NetworkComms.AppendGlobalIncomingPacketHandler<object>("ThreadIdRequest", (packetHeader, connection, incomingPlayer) =>
{
//Reply with the requested threadIds
Console.WriteLine("Received thread ID request from {0}.", connection.ToString());
connection.SendObject("ThreadIds", TaskManager().ToArray());
});
//Start listening for incoming TCP Connections
TCPConnection.StartListening(true);
Console.WriteLine("Server ready. Press any key to shutdown server.");
Console.ReadKey(true);
NetworkComms.Shutdown();
}
private static IEnumerable<string> TaskManager()
{
List<string> lst = new List<string>();
foreach (System.Diagnostics.Process p in
Process.GetProcesses().OrderBy(o => o.ProcessName))
{
lst.Add(p.ProcessName + "_" + p.Id);
}
return lst.AsParallel();
}
}
}
You will obviously need to download the NetworkComms.Net DLL from the website so that you can add it in the 'using NetworkCommsDotNet' reference. Also see the server IP address in the client example is currently "127.0.0.1", this should work if you run both the server and client on the same machine.
Disclaimer: I'm one of the developers for this library.
If you want a reliable and robust solution, use WCF instead of implementing serialization yourself.
Also, writing to stream from parallel threads would not work correctly. Parts of lines from different threads would mix together to some intangible garbage:
Parallel.ForEach(
TaskManager(), item=>
sw.WriteLine(item)
);

issue with multiple clients and getting a specific stream

I have a simple multithreaded C# server and client. When just one client is connected I can interact with it fine, but when two or more are connected, it seems I am using the last NetworkStream. What I'd like to be able to do is give an input command that specifies the stream to read and write to. So, for example, the first client is "Client 1" and the second client is "Client 2." I'd just type "Client 2" into my command textbox and it will get the stream for the second client.
The problem is, I don't know how to assign the text to the clients. Here is the relevant code from the server:
private void ClientThread(Object client)
{
NetworkStream networkStream = ((TcpClient)client).GetStream();
Dictionary<int, NetworkStream> myClients = new Dictionary<int, NetworkStream>(); // This didn't work.
myClients.Add(counter, ((TcpClient)client).GetStream()); // Wouldn't write.
counter = counter + 1;
streamReader = new StreamReader(networkStream);
streamWriter = new StreamWriter(networkStream);
strInput = new StringBuilder();
while (true)
{
try
{
strInput.Append(streamReader.ReadLine());
strInput.Append("\r\n");
}
catch (Exception error)
{
break;
}
Application.DoEvents();
DisplayMessage(strInput.ToString());
strInput.Remove(0, strInput.Length);
}
}
private void textBox2_KeyDown(object sender, KeyEventArgs e)
{
try
{
if (e.KeyCode == Keys.Enter)
{
//ListView.SelectedListViewItemCollection stuff = listView1.SelectedItems;
//ip is displayed in listView1, if I could also bind the stream for the ip
//to it and select it, that would be cool.
{
strInput.Append(textBox2.Text.ToString());
streamWriter.WriteLine(strInput);
streamWriter.Flush();
strInput.Remove(0, strInput.Length);
if (textBox2.Text == "cls") textBox1.Text = "";
textBox2.Text = "";
}
}
}
catch (Exception error) { }
}
So, how can I do this?
NetworkStream networkStream = myClients[2];
using(streamWriter = new StreamWriter(networkStream))
{
streamWriter.WriteLine("hello client 2"); // send something to Client 2
}
networkStream = myClients[4];
using(streamWriter = new StreamWriter(networkStream))
{
streamWriter.WriteLine("hello client 4"); // send something to Client 4
}
You are obviously storing all your client streams into a dictionary. Just load that stream into a StreamWriter and send your data.
Make your dictionary myClients class field and then just get your currently active stream like above.

Connecting to an IRC server using C#

I've been trying my hand at a minimalistic IRC bot, but I can never get a connection to work.
I'm doing this via a TcpClient object, which I've seen used in other such projects and those reportedly work.
Here's the code.
private string server = "irc.freenode.net";
private int port = 6667;
private string nick = "testingsharpbot";
private string channel = "testblablabla";
private TcpClient irc;
public ConfigForm() {
InitializeComponent();
}
private void ConnectButton_Click(object sender, EventArgs e) {
this.irc = new TcpClient(this.server, this.port);
using(NetworkStream stream = irc.GetStream()){
using(StreamReader sr = new StreamReader(stream)) {
using(StreamWriter sw = new StreamWriter(stream) {NewLine = "\r\n", AutoFlush = true}) {
sw.WriteLine("NICK " + this.nick);
sw.WriteLine("JOIN " + this.channel);
}
}
}
}
So I wait a bit and then do a /whois on the nickname, but I always get the same reply: user does not exist.
As far as I'm aware, the TcpClient makes the connection and I can then use the NetWorkStream instance to read and write to that connection.
What else do I need to do?
At first, I suggest you taking a look in the appropiate RFC:
http://www.faqs.org/rfcs/rfc2812.html
Look at Connection Registration. You need to follow this steps to get a connection:
Pass message
Nick message
User message
You're missing the USER command.

Categories