How to add textalign and timestamp to a chat - c#

I'm learning to code and I'm currently making a server and a client with two-way communication. Is there a way to make the received message appear on the left side of the textbox and the sent message on the right side of the textbox just like in a real chat service. Is there also a way to add the timestamp, when the message was received and when it was sent?
I will attach all the code that I have written and images of the client and server windows.
Server
Client
Server code:
namespace Full_Chatt_Server
{
public partial class Form1 : Form
{
TcpListener listener;
TcpClient klient;
int port;
public Form1()
{
InitializeComponent();
}
private void btnStartServer_Click(object sender, EventArgs e)
{
btnTaEmot.Enabled = false;
port = int.Parse(tbxPort.Text);
try
{
listener = new TcpListener(IPAddress.Any, port);
listener.Start();
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartAccepting();
}
public async void StartAccepting()
{
try
{
klient = await listener.AcceptTcpClientAsync();
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartReading(klient);
}
public async void StartReading(TcpClient k)
{
byte[] buffer = new byte[1024];
int n = 0;
try
{
n = await k.GetStream().ReadAsync(buffer, 0, 1024);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
tbxMessage.AppendText(Encoding.Unicode.GetString(buffer, 0, n) + "\r\n");
StartReading(k);
}
private void btnSend_Click(object sender, EventArgs e)
{
string chatt = tbxChatt.Text;
StartSending(chatt);
tbxChatt.Clear();
tbxMessage.AppendText(chatt + "\r\n");
}
public async void StartSending(string message)
{
if (klient.Connected)
{
byte[] OutStream = Encoding.Unicode.GetBytes(message);
try
{
await klient.GetStream().WriteAsync(OutStream, 0, OutStream.Length);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
}
}
}
Client code:
namespace Full_Chatt_Klient
{
public partial class Form1 : Form
{
TcpClient klient = new TcpClient();
int port;
public Form1()
{
InitializeComponent();
}
private void btnConnect_Click(object sender, EventArgs e)
{
if (!klient.Connected)
{
Connect();
}
}
public async void Connect()
{
IPAddress address = IPAddress.Parse(tbxIP.Text);
port = int.Parse(tbxPort.Text);
try
{
await klient.ConnectAsync(address, port);
StartReading(klient);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
btnSkicka.Enabled = true;
btnAnslut.Enabled = false;
}
private void btnSend_Click(object sender, EventArgs e)
{
string chatt = tbxChatt.Text;
StartSending(chatt);
tbxChatt.Clear();
tbxMessage.AppendText(chatt + "\r\n");
}
public async void StartSending(string message)
{
if (klient.Connected)
{
byte[] OutStream = Encoding.Unicode.GetBytes(message);
try
{
await klient.GetStream().WriteAsync(OutStream, 0, OutStream.Length);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
}
}
public async void StartReading(TcpClient k)
{
byte[] buffer = new byte[1024];
int n = 0;
try
{
n = await k.GetStream().ReadAsync(buffer, 0, 1024);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
tbxMessage.AppendText(Encoding.Unicode.GetString(buffer, 0, n) + "\r\n");
StartReading(k);
}
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (klient != null)
{
klient.Close();
}
}
}
}

Related

WPF Window closes automatically soon after loaded

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 ???

C# Client-Server: Only one client receives data

I'm trying to debug this but it's getting super messy in my head, I really need a little help over here. I'm doing the classic Chat Application program with multiple clients and a server. What I have so far :
Clients connect to the server;
The server stores each client in a list;
When a client sends a message, it is then sent to all the clients in the list;
My problem is about this third step, on my server side, my program outputs the step correctly.
For example, if my user is Hugo and he sends Hey:
Sending hugo: hey
to System.Net.Sockets.TcpClient0
Sending hugo: hey
to System.Net.Sockets.TcpClient1
The message is redirected to all the Users connected to my server. Now the problem is on the Client Side, for some reasons, the message are displayed only on the LAST connected user. Considering the previous example, the message "Hey" would be displayed two times on TcpClient1 , and never on TcpClient0
Server code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using System.Net;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using System.Collections;
using ConsoleApp1;
namespace ServerSide
{
class Server
{
private int port;
private byte[] buffer = new byte[1024];
public delegate void DisplayInvoker(string t);
private StringBuilder msgclient = new StringBuilder();
private TcpListener client;
static IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
private IPAddress ipAddress = host.AddressList[0];
private TcpClient myclient;
private List<TcpClient> usersConnected = new List<TcpClient>();
public Server(int port)
{
this.port = port;
}
public void startServer()
{
client = new TcpListener(ipAddress, port);
client.Start();
SERV a = new SERV();
a.Visible = true;
a.textBox1.AppendText("Waiting for a new connection...");
while (true)
{
myclient = client.AcceptTcpClient();
usersConnected.Add(myclient);
a.textBox1.AppendText("New User connected #" + myclient.ToString() );
myclient.GetStream().BeginRead(buffer, 0, 1024, Receive, null);
a.textBox1.AppendText("Size of List " + usersConnected.Count);
}
}
private void Receive(IAsyncResult ar)
{
int intCount;
try
{
lock (myclient.GetStream())
intCount = myclient.GetStream().EndRead(ar);
if (intCount < 1)
{
return;
}
Console.WriteLine("MESSAGE RECEIVED " + intCount);
BuildString(buffer, 0, intCount);
lock (myclient.GetStream())
myclient.GetStream().BeginRead(buffer, 0, 1024, Receive, null);
}
catch (Exception e)
{
return;
}
}
public void Send(string Data)
{
lock (myclient.GetStream())
{
System.IO.StreamWriter w = new System.IO.StreamWriter(myclient.GetStream());
w.Write(Data);
w.Flush();
}
}
private void BuildString(byte[] buffer, int offset, int count)
{
int intIndex;
for (intIndex = offset; intIndex <= (offset + (count - 1)); intIndex++)
{
msgclient.Append((char)buffer[intIndex]);
}
OnLineReceived(msgclient.ToString());
msgclient.Length = 0;
}
private void OnLineReceived(string Data)
{
int i = 0;
foreach (TcpClient objClient in usersConnected)
{
Console.WriteLine("Sending " + Data + " to " + objClient + i);
Send(Data);
i++;
}
}
}
}
Client 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 WindowsFormsApp2
{
public partial class Form2 : Form
{
private delegate void DisplayInvoker(string t);
private string currentTopic = null;
private StringBuilder msg = new StringBuilder();
static public string MyUser { get; set; }
static private byte[] buffer = new byte[1024];
static IPHostEntry host = Dns.GetHostEntry(Dns.GetHostName());
static IPAddress ipAddress = host.AddressList[0];
static Client user = new Client(MyUser, ipAddress, 136);
public Form2(string User) // when a user is logged in , directly connect him to the server
{
InitializeComponent();
MyUser = User;
user.clientConnection();
Thread readingg = new Thread(reading);
readingg.Start();
user.sendText(MyUser + " joined the chatroom!" +"\n");
IPAdress.Text = GetLocalIP(host);
IPAdress.ReadOnly = true;
}
public void reading()
{
user.getClient().GetStream().BeginRead(buffer, 0, 1024, ReadFlow, null);
Console.WriteLine("READING FUNCTION TRIGGERED FOR "+MyUser);
}
private void DisplayText(string t)
{
UserChat.AppendText(t);
Console.WriteLine("DISPLAY FUNCTION TRIGGERED FOR " + MyUser + "with " +msg.ToString());
}
private void BuildString(byte[] buffer,int offset, int count)
{
int intIndex;
for(intIndex = offset; intIndex <= (offset + (count - 1)); intIndex++)
{
if (buffer[intIndex] == 10)
{
msg.Append("\n");
object[] #params = { msg.ToString() };
Console.WriteLine("BUILDSTIRNG FUNCTION TRIGGERED FOR " + MyUser);
Invoke(new DisplayInvoker(DisplayText),#params);
msg.Length = 0;
}
else
{
msg.Append((char)buffer[intIndex]);
}
}
}
private void ReadFlow(IAsyncResult ar)
{
int intCount;
try
{
intCount = user.getClient().GetStream().EndRead(ar);
Console.WriteLine(intCount);
if (intCount < 1)
{
return;
}
Console.WriteLine(MyUser + "received a message");
BuildString(buffer, 0, intCount);
user.getClient().GetStream().BeginRead(buffer, 0, 1024, this.ReadFlow, null);
}catch(Exception e)
{
return;
}
}
private string GetLocalIP(IPHostEntry host)
{
foreach (IPAddress ip in host.AddressList)
{
if (ip.AddressFamily == AddressFamily.InterNetwork)
{
return ip.ToString();
}
}
return "192.168.1.1";
} // get your local ip
private void label1_(object sender, EventArgs e)
{
this.Text = "Hello " + MyUser;
}
private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
}
private void UserMessage_TextChanged(object sender, EventArgs e)
{
}
private void UserMessage_Focus(object sender, EventArgs e)
{
UserMessage.Text = "";
}
private void UserMessage_Focus2(object sender, EventArgs e)
{
}
private void button2_Click(object sender, EventArgs e)
{
listBox1.Items.Add(addTopic.Text);
addTopic.Text = "Add Topic";
}
private void button2_(object sender, EventArgs e)
{
}
private void addTopic_(object sender, EventArgs e)
{
}
private void addTopic_TextChanged(object sender, EventArgs e)
{
}
private void listBox1_MouseDoubleClick(object sender, MouseEventArgs e)
{
string curItem = listBox1.SelectedItem.ToString();
label1.Text = "Topic "+curItem;
currentTopic = curItem;
}
private void IPAdress_TextChanged(object sender, EventArgs e)
{
}
// send msg to the server
private void UserChat_TextChanged(object sender, EventArgs e)
{
}
private void Form2_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
//Handle event here
System.Windows.Forms.Application.Exit();
}
private void Send_Click_1(object sender, EventArgs e)
{
user.sendText(MyUser + ": " + UserMessage.Text +"\n");
UserMessage.Text = " ";
}//send message
}
}
In OnLineReceived, for each client you call SendData, where you send to myclient. You probably want to pass objClient into SendData, and send to that.
Note that there are also some threading problems there; if someone connects exactly while you are iterating the list, it'll break the iterator, for example.

Send data via USB using STX ETC LRC framing (SerialPort object)

I am trying to write a simple Forms app to send data over a USB port to a listening terminal device. I have been told that I need to send the data using STX ETX LRC framing but I have no idea what that means. I am a software tester for our company and not familiar with data transmissions via usb. Is there anyone who can help me with this? This is my current forms code:
private void sendRequestButton_Click(object sender, EventArgs e)
{
try
{
_serialPort = new SerialPort
{
PortName = portsDropdown.Text,
BaudRate = 19200,//connectionTypeDropdown.Text.Equals(Usb) ? 115200 : 19200,
DataBits = 8,
Parity = Parity.None,
StopBits = StopBits.One,
};
_serialPort.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
_serialPort.Open();
_serialPort.Write(requestTextbox.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, #"Caught Exception:", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
_serialPort.Close();
}
}
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
var serialPort = (SerialPort)sender;
_response = serialPort.ReadExisting();
Debug.Print(_response);
}
Here's what I used for connecting through the serial port in C#. This is in WPF so you'll have to make some adjustments.
using System;
using System.IO.Ports;
using System.Windows;
using System.Windows.Input;
namespace SerialTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private SerialPort port = new SerialPort();
int intBaud = 0;
string strComport = "";
public MainWindow()
{
InitializeComponent();
}
private void Window_Loaded(object sender, RoutedEventArgs e)
{
string[] ports = SerialPort.GetPortNames();
cbCom.ItemsSource = ports;
}
private void StartUp()
{
int intbaud;
if (int.TryParse(cbBaud.SelectionBoxItem.ToString(), out intbaud))
{
intBaud = intbaud;
strComport = cbCom.SelectedItem.ToString();
SerialStart();
}
else
{
MessageBox.Show("Enter a valid Baudrate");
}
}
private void SerialStart()
{
try
{
port.BaudRate = int.Parse(cbBaud.SelectionBoxItem.ToString());
port.DataBits = 8;
port.StopBits = (StopBits)Enum.Parse(typeof(StopBits), "One");
port.Parity = (Parity)Enum.Parse(typeof(Parity), "None");
port.PortName = cbCom.SelectedItem.ToString();
port.DataReceived += new SerialDataReceivedEventHandler(SerialReceive);
port.Handshake = Handshake.None;
if (port.IsOpen) port.Close();
port.Open();
}
catch (Exception ex)
{
txtTerm.AppendText(ex.ToString());
}
}
public enum LogMsgType { Incoming, Outgoing, Normal, Warning, Error };
private void Log(LogMsgType msgtype, string msg)
{
try
{
txtTerm.Dispatcher.Invoke(new EventHandler(delegate
{
txtTerm.AppendText(msg);
}));
}
catch (Exception ex)
{
ex.ToString();
}
}
private void SerialReceive(object sender, SerialDataReceivedEventArgs e)
{
if (!port.IsOpen) return;
string data = port.ReadExisting();
this.Dispatcher.Invoke(() =>
{
txtTerm.AppendText(data);
txtTerm.ScrollToEnd();
});
}
private void txtInput_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Return && port.IsOpen)
{
try
{
port.WriteLine(txtInput.Text + "\r\n");
}
catch (Exception ex)
{
this.Dispatcher.Invoke(() =>
{
txtTerm.AppendText(ex.ToString()); ;
});
}
this.Dispatcher.Invoke(() =>
{
txtTerm.AppendText(txtInput.Text + "\n");
txtInput.Text = "";
});
}
}
}
}
Edit
Looks like for STX and ETC you have to also convert the characters to bytes
https://www.codeproject.com/questions/1107562/sending-ascii-control-stx-and-etx-in-csharp

C# Async socket server receives only one message from client

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

c# windows forms multithreading updating form controls from another class event

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" ) );

Categories