I have a communication device which sends requests every two seconds through COM. Between the requests, the device waits for response. I'm building software in C# with SerialPort. I call an event handler for data receiving and I run a method in new thread with while loop which checks that the request is as expected and calls method responsible for response. The thing is, after response next received data is wrong. Here is the code:
The SerialPortManager:
class SerialPortManager : IDisposable
{
...
public void connect()
{
if (mSerialPort.IsOpen)
return;
mSerialPort.DataReceived += new SerialDataReceivedEventHandler(serialPort_DataReceived);
try
{
mSerialPort.Open();
}
catch (Exception e)
{
MessageBox.Show(e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
mStatus = Status.DISCONNECTED;
return;
}
if (mSerialPort.IsOpen)
{
mStatus = Status.CONNECTED;
Thread tryToResponseThread = new Thread(tryToResponse);
tryToResponseThread.Start();
}
}
private void tryToResponse()
{
while (mStatus == Status.CONNECTED)
{
if (mRequest.Length >= 56)
{
string checksum = "555555555555555580808080";
if (mRequest.Length > 56)
{
mRequest.Remove(55, mRequest.Length - 56);
Debug.Print("cutting");
}
if (mRequest.ToString().StartsWith(checksum))
{
StringBuilder strToCMD = new StringBuilder();
for (int i = 0; i < mRequest.Length; i += 2)
{
strToCMD.Append(mRequest[i]);
strToCMD.Append(mRequest[i + 1]);
strToCMD.Append(" ");
}
StringBuilder address = new StringBuilder();
StringBuilder group = new StringBuilder();
address.Append(mRequest.ToString(24, 8));
group.Append(mRequest.ToString(24 + 8, 2));
mMainForm.appendCMDTextboxText(Environment.NewLine);
mMainForm.appendCMDTextboxText(DateTime.Now.ToLongTimeString() + " [RX] " + address.ToString() + " " + group.ToString() + "\t");
mMainForm.appendCMDTextboxText(strToCMD.ToString());
byte[] request = ByteArrayConverter.fromString16(mRequest.ToString());
mRequest.Clear();
response(request);
Array.Clear(request, 0, request.Length);
Debug.Print("starts with checksum");
}
else if (mRequest.ToString().Contains(checksum))
{
int indexOfChecksum = mRequest.ToString().IndexOf(checksum);
mRequest.Remove(0, indexOfChecksum);
Debug.Print("contains");
}
else
{
int index = 0;
bool found = false;
for (int i = 0; i < checksum.Length; i++)
{
StringBuilder s = new StringBuilder();
int sub = mRequest.Length - checksum.Length + i + 2;
if (sub == mRequest.Length)
break;
s.Append(mRequest.ToString().Substring((Math.Max(0, mRequest.Length - checksum.Length + i + 2))));
s.Append(mRequest.ToString(0, i + 2));
if (s.ToString().Equals(checksum))
{
index = sub;
found = true;
break;
}
}
if (found)
{
mRequest.Remove(0, index);
}
else
{
mRequest.Clear();
}
Debug.Print("on start and end");
}
}
}
}
private void response(byte[] request)
{
Luminaire lumToResponse = mLuminaireManager.getLuminaire(request);
if (lumToResponse == null)
{
return;
}
else
{
if (lumToResponse.isNotResponding())
return;
}
byte[] responseMsg = lumToResponse.getWholeFrame(request);
mMainForm.setCommandLabelForResponsingLuminaire(lumToResponse);
mMainForm.appendCMDTextboxText(Environment.NewLine + DateTime.Now.ToLongTimeString() + " [TX]\t");
string responseMsgAsString = ByteArrayConverter.toString(responseMsg).Replace("-", " ");
mMainForm.appendCMDTextboxText(responseMsgAsString);
write(responseMsg, 0, responseMsg.Length);
mSerialDataEventArgs.clearData();
}
public void write(byte[] buffer, int offset, int count)
{
if (mStatus == Status.DISCONNECTED || mSerialPort.IsOpen == false)
{
mStatus = Status.DISCONNECTED;
return;
}
mSerialPort.Write(buffer, offset, count);
}
void serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
if (mStatus == Status.DISCONNECTED)
return;
int dataLength = mSerialPort.BytesToRead;
if (dataLength == 0)
return;
byte[] data = new byte[dataLength];
mSerialPort.Read(data, 0, dataLength);
mSerialDataEventArgs.setData(data);
mDataReceived?.Invoke(this, mSerialDataEventArgs);
}
...
}
The helpser class for passing the received data:
public class SerialDataEventArgs : EventArgs
{
public SerialDataEventArgs()
{
}
public void setData(byte[] data)
{
clearData();
mData = data;
}
public SerialDataEventArgs(byte[] dataInByteArray)
{
mData = dataInByteArray;
}
public void clearData()
{
if (mData == null)
return;
Array.Clear(mData, 0, mData.Length);
}
public byte[] mData;
}
And the main class:
public partial class MainForm : Form
{
...
private void MainForm_Load(object sender, EventArgs e)
{
mSerialPortManager = new SerialPortManager();
mSerialPortManager.setPortBoudRate((int)numUpDown_SerialPortSpeed.Value);
mLuminaireManager = new LuminaireManager();
mSerialPortManager.mMainForm = this;
mSerialPortManager.mLuminaireManager = mLuminaireManager;
fixTableLayoutColumnSize(ref tl_SingleLuminaire);
fillTheRestOfSingleLuminaireGroupBoxes();
fillSerialPortComboBoxWithNamesOfAvailablePorts();
mSerialPortManager.mDataReceived += new EventHandler<SerialDataEventArgs>(serialPortManager_DataReceived);
mIsPaused = false;
}
private void serialPortManager_DataReceived(object sender, SerialDataEventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke(new EventHandler<SerialDataEventArgs>(serialPortManager_DataReceived), new object[] { sender, e });
return;
}
if (mIsPaused)
return;
mSerialPortManager.mRequest.Append(ByteArrayConverter.toString(e.mData).Replace("-", ""));
}
...
}
The communication should be like below:
request: 5555555555555555808080800100000001001A0006070001060031B1
response: 55555555555555558080808001000000010000808076
request: 5555555555555555808080800200000001001A0006070001060034B2
response: 555555555555555580808080020000000100008041BA
request: 5555555555555555808080800300000001001A000607000106003473
response: 55555555555555558080808003000000010000804049
And so on. It is just example, what the request frame should look like. As you can see, the device asks for 1,2,3,4, etc. It always asks in this order. The last four values are just checksum. What I receive after response is like:
request: 5555555555555555808080800200000001001A0006070001060034B2
response: 555555555555555580808080020000000100008041BA
request: 55555555555555558080808002000000000A0100000000000000BCAE
After response for 2, there should be an ask for 3. If I set the software to not responding, every request looks fine.
What I am doing wrong?
Ok, so everything is okay. My COM interface is broken :( Everything is fine with both ways - DataReceived event handler and read() right after write() (no matter which solution is better in programming way). Thank you all for trying help with my case anyway!
Related
Before i begin I know its messy, I'm getting it working before I clean it up. This is also just for my own knowledge growth I do not intend on rolling this out throughout the company. I have made a monitoring program to check the status of a couple of servers for one of my clients. I have managed to get all the relevant data I need from the ping to the servers, I take the data and send it to the "sort" method where it sends that to the next method which figures out which label I should change the text of, it makes it into these if statements however it just doesn't update the text.
I have already tried:
Application.doEvents();
Label.Refresh();
Label.Update();
I've tried using multithreading too see if that would perhaps force it through.
I have even tried using a button to manually update and that didn't work either.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Button1_Click(object sender, EventArgs e)
{
Synergy s = new Synergy();
s.Start();
}
private void Label2_Click(object sender, EventArgs e)
{
}
public void Sort(String Name, double P, long RTT, String Response)
{
Console.WriteLine(Name + ": Inside Sort");
if (Name.Contains("SYN-"))
{
SynergySort(Name, P, RTT, Response);
}
}
public void SynergySort(String Name, double P, long RTT, String Response)
{
Console.WriteLine(Name + ": Inside Synergy Sort");
if (Name.Equals("SYN-DC01"))
{
Console.WriteLine(Name + ": Inside DC01 SORT");
this.SD1R.Text = RTT.ToString();
this.SD1P.Text = P.ToString();
}
else if (Name.Equals("SYN-DC03"))
{
Console.WriteLine(Name + ": Inside DC03 SORT");
this.SD3R.Text = RTT.ToString();
this.SD3P.Text = P.ToString();
}
}
}
public class Synergy
{
private Form1 f = new Form1();
private Pinger ping = new Pinger();
public void Start()
{
NAS01Scan();
DC03Scan();
TRACKERScan();
DC01Scan();
VoiceScan();
NETAPPScan();
}
public void NAS01Scan()
{
Console.WriteLine("Pinging NAS01");
ping.IP("172.16.xx.xxx", 5, "SYN-NAS01");
}
public void DC03Scan()
{
Console.WriteLine("pinging DC03");
ping.IP("172.16.xx.xxx", 5, "SYN-DC03");
}
public void TRACKERScan()
{
Console.WriteLine("pinging TRACKER");
ping.IP("172.16.xx.xxx", 5, "SYN-TRACKER");
}
public void DC01Scan()
{
Console.WriteLine("pinging DC01");
ping.IP("172.16.xx.xxx", 5, "SYN-DC01");
}
public void NETAPPScan()
{
Console.WriteLine("pinging NETAPP");
ping.IP("172.16.xx.xxx", 5, "SYN-NETAPP");
}
public void VoiceScan()
{
Console.WriteLine("pinging AVAYA_Voice");
ping.IP("172.16.xx.xxx", 5, "SYN-AVAYA_Voice");
}
}
public class Pinger
{
private Form1 f = new Form1();
public void IP(String host, int echoNum, String Name)
{
long totalTime = 0;
PingReply reply = null;
int timeout = 120;
Ping pingSender = new Ping();
PingOptions options = new PingOptions();
options.DontFragment = true;
string data = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int failed = 0;
for (int i = 0; i < echoNum; i++)
{
reply = pingSender.Send(host, timeout, buffer, options);
if (reply.Status == IPStatus.Success)
{
}
else
{
failed += 1;
Console.WriteLine(Name + ": " + reply.Status);
}
}
totalTime += reply.RoundtripTime;
Console.WriteLine(Name + ": RoundTrip time: {0}", reply.RoundtripTime);
Console.WriteLine(Name + ": Time in MS = " + totalTime / echoNum);
double percent = (failed / echoNum) * 100;
Console.WriteLine(Name + ": Percent Loss is " + percent);
f.Sort(Name, percent, reply.RoundtripTime, reply.Status.ToString());
}
}
I am having a hard time. I am new to this. Can someone help me with this. Every time I call the _clientSocket.Close(); I got an error message.
Cannot access a disposed object. Object name:
System.net.Sockets.Socket
There's no error in my code. It can run smooth but every time I open and close a form it comes up. I want to get rid of it. The program can run with it but its to irritating. Because when I try to open a client it will pop up. And when the time of the client is done, the form will close and the login will come out with another pop up of
Cannot access a disposed object. Object name:
System.net.Sockets.Socket
I use _clientSocket.Close() because if I'm not closing the sockets it will be doubled in Server side. I close it so it will not be double IP in Checklistbox of the Server.
I'm doing this for my project and I'm just studying myself so some of the comments I really don't understand but I'm trying my best to learn from it thank you!
Your suggestions will much appreciated. Correct me if I'm wrong thank you!
This code is the Loginform when Server sends -O it will _clientSocket.Close(); and open the Form2. If Form2 use all the time it will back to Loginform and form2 _clientSocket.Close(); I call the _clientSocket.Close(); because the Server Checklistbox that catches all the connected sockets will be doubled if I don't close the Sockets.
Edited
Server
namespace RealVersion2
{
public partial class Server : Form
{
public class SocketT2h
{
public Socket _Socket { get; set; }
public string _Name { get; set; }
public SocketT2h(Socket socket)
{
this._Socket = socket;
}
}
private byte[] _buffer = new byte[1024];
public List<SocketT2h> __ClientSockets { get; set; }
List<string> _names = new List<string>();
private Socket _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Server()
{
InitializeComponent();
CheckForIllegalCrossThreadCalls = false;
__ClientSockets = new List<SocketT2h>();
this.list_Client.SelectionMode = System.Windows.Forms.SelectionMode.None;
}
private void Send_Click(object sender, EventArgs e)
{
{
for (int i = 0; i < list_Client.CheckedItems.Count; i++)
{
string t = list_Client.CheckedItems[i].ToString();
for (int j = 0; j < __ClientSockets.Count; j++)
{
if (__ClientSockets[j]._Socket.Connected && __ClientSockets[j]._Name.Equals("#" + t))
{
Sendata(__ClientSockets[j]._Socket, "Server: " );
}
else
{
Sendata(__ClientSockets[j]._Socket, "Server: " + txt_Text.Text);
}
}
}
rich_Text.AppendText("\nServer: " + txt_Text.Text);
txt_Text.Text = "";
}
}
void Sendata(Socket socket, string noidung)
{
byte[] data = Encoding.ASCII.GetBytes(noidung);
socket.BeginSend(data, 0, data.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AppceptCallback), null);
}
private void SendCallback(IAsyncResult AR)
{
Socket socket = (Socket)AR.AsyncState;
socket.EndSend(AR);
}
private void SetupServer()
{
try
{
lb_stt.Text = "Setting up server . . .";
_serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8000));
_serverSocket.Listen(1);
_serverSocket.BeginAccept(new AsyncCallback(AppceptCallback), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void AppceptCallback(IAsyncResult ar)
{
Socket socket = _serverSocket.EndAccept(ar);
__ClientSockets.Add(new SocketT2h(socket));
list_Client.Items.Add(socket.RemoteEndPoint.ToString());
lb_soluong.Text = "Number of clients connected: " + __ClientSockets.Count.ToString();
lb_stt.Text = "Client connected. . .";
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
_serverSocket.BeginAccept(new AsyncCallback(AppceptCallback), null);
}
private void ReceiveCallback(IAsyncResult ar)
{
Socket socket = (Socket)ar.AsyncState;
if (socket.Connected)
{
int received;
try
{
received = socket.EndReceive(ar);
}
catch (Exception)
{
// client close connection
for (int i = 0; i < __ClientSockets.Count; i++)
{
if (__ClientSockets[i]._Socket.RemoteEndPoint.ToString().Equals(socket.RemoteEndPoint.ToString()))
{
//taga tapoon ng panget
list_Client.Items.RemoveAt(i);
__ClientSockets.RemoveAt(i);
lb_soluong.Text = "Number of clients connected: "+__ClientSockets.Count.ToString();
}
}
//delete in list
return;
}
if (received!=0)
{
byte[] dataBuf = new byte[received];
Array.Copy(_buffer, dataBuf, received);
string text = Encoding.ASCII.GetString(dataBuf);
//lb_stt.Text = "Text received: " + text;
string reponse = string.Empty;
//reponse = "Server: Hi! You're Connected to the Librarian.";
if (text.Contains("##"))
{
for (int i = 0; i < list_Client.Items.Count; i++)
{
if (socket.RemoteEndPoint.ToString().Equals(__ClientSockets[i]._Socket.RemoteEndPoint.ToString()))
{
list_Client.Items.RemoveAt(i);
list_Client.Items.Insert(i, text.Substring(1, text.Length - 1));
__ClientSockets[i]._Name = text;
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
return;
}
}
}
for (int i = 0; i < __ClientSockets.Count; i++)
{
if (socket.RemoteEndPoint.ToString().Equals(__ClientSockets[i]._Socket.RemoteEndPoint.ToString()))
{
rich_Text.AppendText("\n" + __ClientSockets[i]._Name + ": " + text);
}
}
}
else
{
for (int i = 0; i < __ClientSockets.Count; )
{
if (__ClientSockets[i]._Socket.RemoteEndPoint.ToString().Equals(socket.RemoteEndPoint.ToString()))
{
__ClientSockets.RemoveAt(i);
lb_soluong.Text ="The number of clients connected: " + __ClientSockets.Count.ToString();
}
}
}
}
socket.BeginReceive(_buffer, 0, _buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), socket);
}
private void tabPage1_Click(object sender, EventArgs e)
{
}
private void Server_Load(object sender, EventArgs e)
{
SetupServer();
}
private void Restartbtn_Click(object sender, EventArgs e)
{
string Restart = string.Empty;
Restart = "-r";
{
for (int i = 0; i < list_Client.CheckedItems.Count; i++)
{
string t = list_Client.CheckedItems[i].ToString();
for (int j = 0; j < __ClientSockets.Count; j++)
{
if (__ClientSockets[j]._Socket.Connected && __ClientSockets[j]._Name.Equals("#" + t))
{
Sendata(__ClientSockets[j]._Socket, "Server: " + Restart);
}
}
}
rich_Text.AppendText("\nServer: " + txt_Text.Text);
}
}
private void Shutdownbtn_Click(object sender, EventArgs e)
{
string Shutdown = string.Empty;
Shutdown = "-s";
{
for (int i = 0; i < list_Client.CheckedItems.Count; i++)
{
string t = list_Client.CheckedItems[i].ToString();
for (int j = 0; j < __ClientSockets.Count; j++)
{
if (__ClientSockets[j]._Socket.Connected && __ClientSockets[j]._Name.Equals("#" + t))
{
Sendata(__ClientSockets[j]._Socket, "Server: " + Shutdown);
}
}
}
rich_Text.AppendText("\nServer: " + txt_Text.Text);
}
}
private void list_Client_SelectedIndexChanged(object sender, EventArgs e)
{
for (int i = 0; i < list_Client.Items.Count; i++)
{
if (list_Client.GetItemRectangle(i).Contains(list_Client.PointToClient(MousePosition)))
{
switch (list_Client.GetItemCheckState(i))
{
case CheckState.Checked:
list_Client.SetItemCheckState(i, CheckState.Unchecked);
break;
case CheckState.Indeterminate:
case CheckState.Unchecked:
list_Client.SetItemCheckState(i, CheckState.Checked);
break;
}
}
}
}
private void openPCToolStripMenuItem_Click_1(object sender, EventArgs e)
{
string Open = string.Empty;
Open = "-O";
{
for (int i = 0; i < list_Client.CheckedItems.Count; i++)
{
string t = list_Client.CheckedItems[i].ToString();
for (int j = 0; j < __ClientSockets.Count; j++)
{
if (__ClientSockets[j]._Socket.Connected && __ClientSockets[j]._Name.Equals("#" + t))
{
Sendata(__ClientSockets[j]._Socket, "Server: " + Open);
//use [i] if u dont want name in list
}
}
}
//rich_Text.AppendText("\nServer: " + txt_Text.Text);
}
}
private void Server_FormClosing(object sender, FormClosingEventArgs e)
{
string Ext = string.Empty;
Ext = "exit";
{
for (int i = 0; i < list_Client.CheckedItems.Count; i++)
{
string t = list_Client.CheckedItems[i].ToString();
for (int j = 0; j < __ClientSockets.Count; j++)
{
if (__ClientSockets[j]._Socket.Connected && __ClientSockets[j]._Name.Equals("#" + t))
{
Sendata(__ClientSockets[j]._Socket, "Server: " + Ext);
}
}
}
//rich_Text.AppendText("\nServer: " + txt_Text.Text);
Application.Exit();
_serverSocket.Close();
}
}
private void End_Click(object sender, EventArgs e)
{
string Ext = string.Empty;
Ext = "close";
{
for (int i = 0; i < list_Client.CheckedItems.Count; i++)
{
string t = list_Client.CheckedItems[i].ToString();
for (int j = 0; j < __ClientSockets.Count; j++)
{
if (__ClientSockets[j]._Socket.Connected && __ClientSockets[j]._Name.Equals("#" + t))
{
Sendata(__ClientSockets[j]._Socket, "Server: " + Ext);
}
}
}
//rich_Text.AppendText("\nServer: " + txt_Text.Text);
}
}
}
}
Client
public partial class UserLog : Form
{
private Socket _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
TimeSpan countdownClock = TimeSpan.Zero;
public UserLog()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
string Username = "User";
string Pass = "123";
if (Username == textBox1.Text && Pass == textBox2.Text)
{
MessageBox.Show("Login Successfully");
Usertimer User = new Usertimer(textBox1.Text);
User.Show();
this.Hide();
_clientSocket.Dispose();
_clientSocket.Close();
}
else
{
MessageBox.Show("Please Enter valid Username or Password");
}
}
byte[] receivedBuf = new byte[1024];
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
if (_clientSocket != null && _clientSocket.Connected)
{
_clientSocket.Close();
}
}
private void ReceiveData(IAsyncResult ar)
{
try
{
int received = _clientSocket.EndReceive(ar);
if (received == 0)
{
return;
}
Array.Resize(ref receivedBuf, received);
string text = Encoding.Default.GetString(receivedBuf);
Array.Resize(ref receivedBuf, _clientSocket.ReceiveBufferSize);
AppendtoTextBox(text);
if (text == "Server: -O")
{
Thread NT = new Thread(() =>
{
this.BeginInvoke((Action)delegate ()
{
textBox1.Text = "Guest";
this.Hide();
_clientSocket.Close();
Usertimer us = new Usertimer(textBox1.Text);
us.Show();
});
});
NT.Start();
}
if (text == "Server: exit")
{
_clientSocket.Close();
Application.Exit();
}
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), null);
}
catch (ObjectDisposedException ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void AppendtoTextBox(string text)
{
MethodInvoker invoker = new MethodInvoker(delegate
{
textBox4.Text += text + "\r\n";
});
this.Invoke(invoker);
}
private void LoopConnect()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.Connect(IPAddress.Parse(textBox5.Text), 8000);
//_clientSocket.Connect(IPAddress.Parse(textBox4.Text), 100);
}
catch (SocketException)
{
//Console.Clear();
lb_stt.Text = ("Connection attempts: " + attempts.ToString());
}
}
AppendtoTextBox(reponse);
}
private void button2_Click(object sender, EventArgs e)
{
LoopConnect();
// SendLoop();
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), _clientSocket);
byte[] buffer = Encoding.ASCII.GetBytes("##"+txName.Text);
_clientSocket.Send(buffer);
}
private void UserLog_Load(object sender, EventArgs e)
{
LoopConnect();
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), _clientSocket);
byte[] buffer = Encoding.ASCII.GetBytes("##"+txName.Text);
_clientSocket.Send(buffer);
}
private void UserLog_FormClosed(object sender, FormClosedEventArgs e)
{
Application.Exit();
}
}
}
Form2 of the client
public partial class Usertimer : Form
{
private Socket _clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
public Usertimer(string pass)
{
InitializeComponent();
label3.Text = pass;
}
byte[] receivedBuf = new byte[1024];
protected override void OnShown(EventArgs e)
{
base.OnShown(e);
this.btnConnect_Click(null, null);
}
protected override void OnClosing(CancelEventArgs e)
{
base.OnClosing(e);
if (_clientSocket != null && _clientSocket.Connected)
{
_clientSocket.Close();
}
}
private void ReceiveData(IAsyncResult ar)
{
try
{
int received = _clientSocket.EndReceive(ar);
if (received == 0)
{
return;
}
Array.Resize(ref receivedBuf, received);
string text = Encoding.Default.GetString(receivedBuf);
if (text == "Server: close")
{
Thread NT = new Thread(() =>
{
this.BeginInvoke((Action)delegate ()
{
UserLog Log = new UserLog();
Log.Show();
this.Close();
_clientSocket.Close();
});
});
NT.Start();
}
Array.Resize(ref receivedBuf, _clientSocket.ReceiveBufferSize);
AppendtoTextBox(text);
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), null);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void AppendtoTextBox(string text)
{
MethodInvoker invoker = new MethodInvoker(delegate
{
richTextBox1.Text += text + "\r\n";
});
this.Invoke(invoker);
}
private void LoopConnect()
{
int attempts = 0;
while (!_clientSocket.Connected)
{
try
{
attempts++;
_clientSocket.Connect(IPAddress.Parse(textBox4.Text), 8000);
}
catch (SocketException)
{
//Console.Clear();
lb_stt.Text = ("Connection attempts: " + attempts.ToString());
}
}
AppendtoTextBox(reponse);
}
private void btnConnect_Click(object sender, EventArgs e)
{
LoopConnect();
// SendLoop();
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), _clientSocket);
byte[] buffer = Encoding.ASCII.GetBytes("##" + txName.Text);
_clientSocket.Send(buffer);
}
private void btnSend_Click(object sender, EventArgs e)
{
if (_clientSocket.Connected)
{
byte[] buffer = Encoding.ASCII.GetBytes(txt_text.Text);
_clientSocket.Send(buffer);
AppendtoTextBox(txName.Text + ": " + txt_text.Text);
}
txt_text.Text = "";
}
private void button1_Click(object sender, EventArgs e)
{
UserLog log = new UserLog();
log.Show();
this.Close();
_clientSocket.Close();
}
}
}
Like I answered in your previous question, you should spend the time to read these two pages. They will help you get your answer much faster.
There's no error in my code.
If you're getting an error message, then there's an error in your code.
every time I open and close a form
What form? There is no form in your example.
it will be doubled in Server side. I close it so it will not be double IP in Checklistbox of the Server.
What server? What checklistbox? We don't know what you are referring to here.
Without a minimal, complete and verifiable example, we can't help you very well. That being said, it looks like you are closing your _clientSocket. Once you've closed a socket you must re-open it or create a new one before you can use it again. You cannot call BeginReceive after you've closed your socket.
I was able to reproduce your error by creating a complete, minimal and verifiable example. Here is the code:
public partial class Form1 : Form
{
Socket _clientSocket;
public Form1()
{
InitializeComponent();
}
const int buffSize = 1024;
byte[] receivedBuf = new byte[buffSize];
Socket listenerSock;
Socket handlerSock;
private void Form1_Load(object sender, EventArgs e)
{
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, 11000);
listenerSock = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listenerSock.Bind(localEndPoint);
listenerSock.Listen(10);
listenerSock.BeginAccept(ServerAcceptAsync, null);
_clientSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
_clientSocket.Connect(localEndPoint);
_clientSocket.BeginReceive(receivedBuf, 0, buffSize, SocketFlags.None, ReceiveData, null);
}
private void ServerAcceptAsync(IAsyncResult ar)
{
handlerSock = listenerSock.EndAccept(ar);
}
private void ReceiveData(IAsyncResult ar)
{
//try
//{
Debug.WriteLine("received data");
int received = _clientSocket.EndReceive(ar);
if (received == 0)
{
return;
}
Array.Resize(ref receivedBuf, received);
string text = Encoding.Default.GetString(receivedBuf);
Debug.WriteLine(text);
if (text == "Server: -O")
{
Thread NT = new Thread(() =>
{
this.BeginInvoke((Action)delegate ()
{
textBox1.Text = "Guest";
this.Hide();
_clientSocket.Close();
//Usertimer us = new Usertimer(textBox1.Text);
//us.Show();
});
});
NT.Start();
}
Array.Resize(ref receivedBuf, _clientSocket.ReceiveBufferSize);
//AppendtoTextBox(text);
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), null);
//}
//catch (Exception ex)
//{
// MessageBox.Show(ex.Message, Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Error);
//}
}
private void button1_Click(object sender, EventArgs e)
{
var message = Encoding.UTF8.GetBytes("Server: -O");
handlerSock.Send(message);
}
}
I commented the code that was not necessary to reproduce. As expected, the problem is that you call ReceiveAsync after you call _clientSock.Close(). You can't do that. If you close the socket, you should not execute anymore code. Here is an example of how to fix this:
if (text == "Server: -O")
{
Thread NT = new Thread(() =>
{
this.BeginInvoke((Action)delegate ()
{
textBox1.Text = "Guest";
this.Hide();
_clientSocket.Close();
//Usertimer us = new Usertimer(textBox1.Text);
//us.Show();
});
});
NT.Start();
}
else
{
Array.Resize(ref receivedBuf, _clientSocket.ReceiveBufferSize);
//AppendtoTextBox(text);
_clientSocket.BeginReceive(receivedBuf, 0, receivedBuf.Length, SocketFlags.None, new AsyncCallback(ReceiveData), null);
}
Using visual studios Windows forms on c#, I'm making a chatprogram with unlimited clients and one server. The server has to be activated before I connect any client. However, after connecting one or more clients and closing one of them, the server crashes. I can nor close it or send any data from my clients to it without getting an error. The CPU usage of my computer rises to 50% during the crash. After I manage to close the server through task manager, different code lines are highlighted, indicating the error.
Here's my server code:
namespace TCPa
{ // skapar en lista med tcp clients
// säg till så att send funktioner tar tcp clients som input i
metoderna och referera till metoderna
// och loopa genom listan, som kallar metoden i lista.
public partial class Server : Form
{
TcpClient klient = null;
List<TcpClient> klientLista = new List<TcpClient>();
TcpListener lyssnare;
int port = 0;
public Server()
{
InitializeComponent();
}
private void btnTaEmot_Click(object sender, EventArgs e)
{
try
{
port = int.Parse(tbxPort.Text);
if (port >= 1024 && port <= 65535)
{
les(port);
}
else
{
MessageBox.Show("Skriv in ett giltigt portnummer mellan 1024 och 65535");
}
}
catch (Exception)
{
MessageBox.Show("Skriv in ett giltigt portnummer mellan 1024 och 65535");
}
}
public void les(int portT)
{
btnTaEmot.Enabled = false;
tbxPort.Enabled = false;
try
{
lyssnare = new TcpListener(IPAddress.Any, portT);
lyssnare.Start();
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartAccepting();
}
public async void StartAccepting()
{
try
{
klient = await lyssnare.AcceptTcpClientAsync();
klientLista.Add(klient);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartReading(klient);
StartAccepting();
}
public async void StartReading(TcpClient k)
{
byte[] buffer = new byte[1024];
int n = 0;
try
{
///NEW
n = await k.GetStream().ReadAsync(buffer, 0, 1024);
if (n <= 0)
{
klient.Close();
}
////NEW
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
StartSending(k, Encoding.Unicode.GetString(buffer, 0, n));
tbxLogg.AppendText(Encoding.Unicode.GetString(buffer, 0, n));
StartReading(k);
}
public async void StartSending(TcpClient klientSomSkickar, string message)
{
if (klientLista.Count > 0)
{
byte[] utData = Encoding.Unicode.GetBytes(message);
foreach (TcpClient klient in klientLista)
{
try
{
if (klient != klientSomSkickar)
{
await klient.GetStream().WriteAsync(utData, 0, utData.Length);
}
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text); return;
}
}
}
}
private void Server_FormClosing(object sender, FormClosingEventArgs e)
{
lyssnare.Stop();
if (klient != null && klient.Connected)
{
klient.Close();
}
}
}
}
Here's my client code
namespace Klient
{
public partial class Klient : Form
{
TcpClient klient = new TcpClient();
public Klient()
{
InitializeComponent();
btnSend.Enabled = false;
}
private void btnAnslut_Click(object sender, EventArgs e)
{
Connect();
}
private async void Connect()
{
IPAddress adress = IPAddress.Parse(tbxIP.Text);
int port = int.Parse(tbxPort.Text);
try
{
await klient.ConnectAsync(adress, port);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
if (klient.Connected)
{
btnAnslut.Enabled = false;
btnSend.Enabled = true;
tbxNmn.Enabled = false;
tbxMedd.Focus();
}
StartReading(klient);
}
private async void btnSend_Click(object sender, EventArgs e)
{
if (klient.Connected)
{
string namn = tbxNmn.Text;
string tid = DateTime.Now.ToString("HH:mm tt");
if (String.IsNullOrEmpty(tbxMedd.Text) || String.IsNullOrWhiteSpace(tbxMedd.Text))
{
MessageBox.Show("Skriv in ditt meddelande");
}
else
{
byte[] utData = Encoding.Unicode.GetBytes("<" + " " + namn + " " + ">" + " " + tid + ":" + "\t" + tbxMedd.Text + "\r\n");
try
{
tbxLogg.AppendText("<" + " " + namn + " " + ">" + " " + tid + ":" + "\t" + tbxMedd.Text + "\r\n");
await klient.GetStream().WriteAsync(utData, 0, utData.Length);
}
catch (Exception error)
{
MessageBox.Show(error.Message, Text);
return;
}
}
}
tbxMedd.Clear();
}
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;
}
tbxLogg.AppendText(Encoding.Unicode.GetString(buffer, 0, n));
StartReading(k);
}
private void Klient_FormClosing(object sender, FormClosingEventArgs e)
{
if (klient != null)
klient.Close();
}
}
}
Any help is appreciated!!
can someone please help me out with this... I've been struggling all day.
So I'm trying to learn Async sockets which is something that's been giving me trouble.
The issue is basically the way I'm updating the ListBox with people who have joined the chat room's names:
Basically what I'm doing is having each client send "!!addlist [nickname]" when they join the server.
It's not ideal as it doesn't check for duplicates etc. but now I just want to know why it won't work.
Whenever somebody adds a name they haven't seen before, they will also send "!!addlist [nick]"
In this way, every time someone joins, the lists should be updated for everyone.
The issue seems to be that all the clients start communicating at the same time and it interferes with the buffer.
I've tried using a separate buffer for every client so that's not the issue.
I've tried using lock() but that doesn't seem to be working either.
Essentially what happens is the buffers seem to truncate; where there is data from two different people in the same buffer.
Please just tell me what I'm doing wrong with the buffers or on the client side:
Note that the async socket is using Send instead of BeginSend.
I've tried both methods and they run into the same issue... so it's probably client side?
public partial class Login : Form
{
private ChatWindow cw;
private Socket serverSocket;
private List<Socket> socketList;
private byte[] buffer;
private bool isHost;
private bool isClosing;
public void startListening()
{
try
{
this.isHost = true; //We're hosting this server
cw.callingForm = this; //Give ChatForm the login form (this) [that acts as the server]
cw.Show(); //Show ChatForm
cw.isHost = true; //Tell ChatForm it is the host (for display purposes)
this.Hide(); //And hide the login form
serverSocket.Bind(new IPEndPoint(IPAddress.Any, int.Parse(portBox.Text))); //Bind to our local address
serverSocket.Listen(1); //And start listening
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); //When someone connects, begin the async callback
cw.connectTo("127.0.0.1", int.Parse(portBox.Text), nicknameBox.Text); //And have ChatForm connect to the server
}
catch (Exception) { /*MessageBox.Show("Error:\n\n" + e.ToString());*/ } //Let us know if we ran into any errors
}
public void AcceptCallback(IAsyncResult AR)
{
try
{
Socket s = serverSocket.EndAccept(AR); //When someone connects, accept the new socket
socketList.Add(s); //Add it to our list of clients
s.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), s); //Begin the async receive method using our buffer
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); //And start accepting new connections
}
catch (Exception) {}
}
public void ReceiveCallback(IAsyncResult AR) //When a message from a client is received
{
try
{
if (isClosing)
return;
Socket s = (Socket)AR.AsyncState; //Get the socket from our IAsyncResult
int received = s.EndReceive(AR); //Read the number of bytes received (*need to add locking code here*)
byte[] dbuf = new byte[received]; //Create a temporary buffer to store just what was received so we don't have extra data
Array.Copy(buffer, dbuf, received); //Copy the received data from our buffer to our temporary buffer
foreach (Socket client in socketList) //For each client that is connected
{
try
{
if (client != (Socket)AR.AsyncState) //If this isn't the same client that just sent a message (*client handles displaying these*)
client.Send(dbuf); //Send the message to the client
}
catch (Exception) { }
} //Start receiving new data again
s.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, new AsyncCallback(ReceiveCallback), s);
}
catch (Exception) { /*cw.output("\n\nError:\n\n" + e.ToString());*/ }
}
public void SendCallback(IAsyncResult AR)
{
try
{
Socket s = (Socket)AR.AsyncState;
s.EndSend(AR);
}
catch (Exception) { /*cw.output("\n\nError:\n\n" + e.ToString());*/ }
}
Here is the client side:
public void getData()
{
try
{
byte[] buf = new byte[1024];
string message = "";
while(isConnected)
{
Array.Clear(buf, 0, buf.Length);
message = "";
clientSocket.Receive(buf, buf.Length, SocketFlags.None);
message = Encoding.ASCII.GetString(buf);
if (message.StartsWith("!!addlist"))
{
message = message.Replace("!!addlist", "");
string userNick = message.Trim();
if (!namesBox.Items.Contains(userNick))
{
addNick(userNick.Trim());
}
continue;
}
else if (message.StartsWith("!!removelist"))
{
message = message.Replace("!!removelist", "");
string userNick = message.Trim();
removeNick(userNick);
output("Someone left the room: " + userNick);
continue;
}
else if (!namesBox.Items.Contains(message.Substring(0, message.IndexOf(":"))))
{
addNick(message.Substring(0, message.IndexOf(":")).Trim()); //So they at least get added when they send a message
}
output(message);
}
}
catch (Exception)
{
output("\n\nConnection to the server lost.");
isConnected = false;
}
}
Here is my addNick function that seems to fix some things?
public void addNick(string n)
{
if (n.Contains(" ")) //No Spaces... such a headache
return;
if (n.Contains(":"))
return;
bool shouldAdd = true;
n = n.Trim();
for (int x = namesBox.Items.Count - 1; x >= 0; --x)
if (namesBox.Items[x].ToString().Contains(n))
shouldAdd = false;
if (shouldAdd)
{
namesBox.Items.Add(n);
output("Someone new joined the room: " + n);
sendRaw("!!addlist " + nickName);
}
}
I think the issue is that some of the packets are being skipped?
Maybe there's too much code in the client after Receive before it gets called again?
Should I create a separate thread for each message so that receive runs constantly? (Dumb)
Should I have my client use Async receives and sends as well?
I have a feeling that is the answer ^
With all of the checks I do, I managed to clean up the duplicate name issue... but i regularly receive messages with spaces and partial messages from other clients it seems.
Okay so, after messing with this for a long time, I have it relatively stable.
For starters, I added the following state object:
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
public bool newConnection = true;
}
This makes it easy to keep track of each connection and gives each connection its own buffer.
The second thing I did was look for a new line in each message.
I wasn't looking for this in the original code and I believe this was the root of most issues.
I also gave the responsibility of dealing with username management to the server; something that I should have done from the start obviously.
Here is the current server code:
This code is in no way perfect and I'm continuously finding new errors the more I try to break it. I'm going to keep messing with it for awhile but at the moment, it seems to work decently.
public partial class Login : Form
{
private ChatWindow cw;
private Socket serverSocket;
private List<Socket> socketList;
private byte[] buffer;
private bool isHost;
private bool isClosing;
private ListBox usernames;
public Login()
{
InitializeComponent();
}
private void Login_Load(object sender, EventArgs e)
{
ipLabel.Text = getLocalIP();
cw = new ChatWindow();
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socketList = new List<Socket>();
buffer = new byte[1024];
isClosing = false;
usernames = new ListBox();
}
public string getLocalIP()
{
return Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
}
private void joinButton_Click(object sender, EventArgs e)
{
try
{
int tryPort = 0;
this.isHost = false;
cw.callingForm = this;
if (ipBox.Text == "" || portBox.Text == "" || nicknameBox.Text == "" || !int.TryParse(portBox.Text.ToString(), out tryPort))
{
MessageBox.Show("You must enter an IP Address, Port, and Nickname to connect to a server.", "Missing Info");
return;
}
this.Hide();
cw.Show();
cw.connectTo(ipBox.Text, int.Parse(portBox.Text), nicknameBox.Text);
}
catch(Exception otheree) {
MessageBox.Show("Error:\n\n" + otheree.ToString(),"Error connecting...");
cw.Hide();
this.Show();
}
}
private void hostButton_Click(object sender, EventArgs e)
{
int tryPort = 0;
if (portBox.Text == "" || nicknameBox.Text == "" || !int.TryParse(portBox.Text.ToString(), out tryPort)) {
MessageBox.Show("You must enter a Port and Nickname to host a server.", "Missing Info");
return;
}
startListening();
}
public void startListening()
{
try
{
this.isHost = true; //We're hosting this server
cw.callingForm = this; //Give ChatForm the login form (this) [that acts as the server]
cw.Show(); //Show ChatForm
cw.isHost = true; //Tell ChatForm it is the host (for display purposes)
this.Hide(); //And hide the login form
serverSocket.Bind(new IPEndPoint(IPAddress.Any, int.Parse(portBox.Text))); //Bind to our local address
serverSocket.Listen(1); //And start listening
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null); //When someone connects, begin the async callback
cw.connectTo("127.0.0.1", int.Parse(portBox.Text), nicknameBox.Text); //And have ChatForm connect to the server
}
catch (Exception) {}
}
public void AcceptCallback(IAsyncResult AR)
{
try
{
StateObject state = new StateObject();
state.workSocket = serverSocket.EndAccept(AR);
socketList.Add(state.workSocket);
state.workSocket.BeginReceive(state.buffer, 0, StateObject.BufferSize, SocketFlags.None, new AsyncCallback(ReceiveCallback), state);
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), null);
}
catch (Exception) {}
}
public void ReceiveCallback(IAsyncResult AR)
{
try
{
if (isClosing)
return;
StateObject state = (StateObject)AR.AsyncState;
Socket s = state.workSocket;
String content = "";
int received = s.EndReceive(AR);
if(received > 0)
state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, received));
content = state.sb.ToString();
if (content.IndexOf(Environment.NewLine) > -1) //If we've received the end of the message
{
if (content.StartsWith("!!addlist") && state.newConnection)
{
state.newConnection = false;
content = content.Replace("!!addlist", "");
string userNick = content.Trim();
if (isHost && userNick.StartsWith("!"))
userNick = userNick.Replace("!", "");
userNick = userNick.Trim();
if (userNick.StartsWith("!") || userNick == string.Empty || usernames.Items.IndexOf(userNick) > -1)
{
//Invalid Username :c get dropped
s.Send(Encoding.ASCII.GetBytes("Invalid Username/In Use - Sorry :("));
s.Shutdown(SocketShutdown.Both);
s.Disconnect(false);
s.Close();
socketList.Remove(s);
return;
}
usernames.Items.Add(userNick);
foreach (string name in usernames.Items)
{
if (name.IndexOf(userNick) < 0)
{
s.Send(Encoding.ASCII.GetBytes("!!addlist " + name + "\r\n"));
Thread.Sleep(10); //such a hack... ugh it annoys me that this works
}
}
foreach (Socket client in socketList)
{
try
{
if (client != s)
client.Send(Encoding.ASCII.GetBytes("!!addlist " + userNick + "\r\n"));
}
catch (Exception) { }
}
}
else if (content.StartsWith("!!removelist") && !state.newConnection)
{
content = content.Replace("!!removelist", "");
string userNick = content.Trim();
usernames.Items.Remove(userNick);
foreach (Socket client in socketList)
{
try
{
if (client != s)
client.Send(Encoding.ASCII.GetBytes("!!removelist " + userNick + "\r\n"));
}
catch (Exception) { }
}
}
else if (state.newConnection) //if they don't give their name and try to send data, just drop.
{
s.Shutdown(SocketShutdown.Both);
s.Disconnect(false);
s.Close();
socketList.Remove(s);
return;
}
else
{
foreach (Socket client in socketList)
{
try
{
if (client != s)
client.Send(System.Text.Encoding.ASCII.GetBytes(content));
}
catch (Exception) { }
}
}
}
Array.Clear(state.buffer, 0, StateObject.BufferSize);
state.sb.Clear();
s.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
catch (Exception) {
socketList.Remove(((StateObject)AR.AsyncState).workSocket);
}
}
public void SendCallback(IAsyncResult AR)
{
try
{
StateObject state = (StateObject)AR.AsyncState;
state.workSocket.EndSend(AR);
}
catch (Exception) {}
}
private void Login_FormClosed(object sender, FormClosedEventArgs e)
{
try
{
this.isClosing = true;
if (this.isHost)
{
foreach (Socket c in socketList)
{
if (c.Connected)
{
c.Close();
}
}
serverSocket.Shutdown(SocketShutdown.Both);
serverSocket.Close();
serverSocket = null;
serverSocket.Dispose();
}
socketList.Clear();
}
catch (Exception) { }
finally
{
Application.Exit();
}
}
}
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public StringBuilder sb = new StringBuilder();
public bool newConnection = true;
}
The client code (work in progress):
public partial class ChatWindow : Form
{
private Socket clientSocket;
private Thread chatThread;
private string ipAddress;
private int port;
private bool isConnected;
private string nickName;
public bool isHost;
public Login callingForm;
private static object conLock = new object();
public ChatWindow()
{
InitializeComponent();
isConnected = false;
isHost = false;
}
public string getIP() {
return Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(ip => ip.AddressFamily == AddressFamily.InterNetwork).ToString();
}
public void displayError(string err)
{
output(Environment.NewLine + Environment.NewLine + err + Environment.NewLine);
}
public void op(string s)
{
try
{
lock (conLock)
{
chatBox.Text += s;
}
}
catch (Exception) { }
}
public void connectTo(string ip, int p, string n) {
try
{
this.Text = "Trying to connect to " + ip + ":" + p + "...";
this.ipAddress = ip;
this.port = p;
this.nickName = n;
clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
if (!isHost)
{
op("Connecting to " + ipAddress + ":" + port + "...");
}
else
{
output("Listening on " + getIP() + ":" + port + "...");
}
clientSocket.Connect(ipAddress, port);
isConnected = true;
if (!isHost)
{
this.Text = "Connected to " + ipAddress + ":" + port + " - Nickname: " + nickName;
output("Connected!");
}
else
{
this.Text = "Hosting on " + getIP() + ":" + port + " - Nickname: " + nickName;
}
chatThread = new Thread(new ThreadStart(getData));
chatThread.Start();
nickName = nickName.Replace(" ", "");
nickName = nickName.Replace(":", "");
if(nickName.StartsWith("!"))
nickName = nickName.Replace("!", "");
namesBox.Items.Add(nickName);
sendRaw("!!addlist " + nickName);
}
catch (ThreadAbortException)
{
//do nothing; probably closing chat window
}
catch (Exception e)
{
if (!isConnected)
{
this.Hide();
callingForm.Show();
clearText();
MessageBox.Show("Error:\n\n" + e.ToString(), "Error connecting to remote host");
}
}
}
public void removeNick(string n)
{
if (namesBox.Items.Count <= 0)
return;
for (int x = namesBox.Items.Count - 1; x >= 0; --x)
if (namesBox.Items[x].ToString().Contains(n))
namesBox.Items.RemoveAt(x);
}
public void clearText()
{
try
{
lock (conLock)
{
chatBox.Text = "";
}
}
catch (Exception) { }
}
public void addNick(string n)
{
if (n.Contains(" ")) //No Spaces... such a headache
return;
if (n.Contains(":"))
return;
bool shouldAdd = true;
n = n.Trim();
for (int x = namesBox.Items.Count - 1; x >= 0; --x)
if (namesBox.Items[x].ToString().Contains(n))
shouldAdd = false;
if (shouldAdd)
{
namesBox.Items.Add(n);
output("Someone new joined the room: " + n);
//sendRaw("!!addlist " + nickName);
}
}
public void addNickNoMessage(string n)
{
if (n.Contains(" ")) //No Spaces... such a headache
return;
if (n.Contains(":"))
return;
bool shouldAdd = true;
n = n.Trim();
for (int x = namesBox.Items.Count - 1; x >= 0; --x)
if (namesBox.Items[x].ToString().Contains(n))
shouldAdd = false;
if (shouldAdd)
{
namesBox.Items.Add(n);
//sendRaw("!!addlist " + nickName);
}
}
public void getData()
{
try
{
byte[] buf = new byte[1024];
string message = "";
while(isConnected)
{
Array.Clear(buf, 0, buf.Length);
message = "";
int gotData = clientSocket.Receive(buf, buf.Length, SocketFlags.None);
if (gotData == 0)
throw new Exception("I swear, this was working before but isn't anymore...");
message = Encoding.ASCII.GetString(buf);
if (message.StartsWith("!!addlist"))
{
message = message.Replace("!!addlist", "");
string userNick = message.Trim();
if(!namesBox.Items.Contains(userNick))
{
addNick(userNick);
}
continue;
}
else if (message.StartsWith("!!removelist"))
{
message = message.Replace("!!removelist", "");
string userNick = message.Trim();
removeNick(userNick);
output("Someone left the room: " + userNick);
continue;
}
output(message);
}
}
catch (Exception)
{
isConnected = false;
output(Environment.NewLine + "Connection to the server lost.");
}
}
public void output(string s)
{
try
{
lock (conLock)
{
chatBox.Text += s + Environment.NewLine;
}
}
catch (Exception) { }
}
private void ChatWindow_FormClosed(object sender, FormClosedEventArgs e)
{
try
{
if(isConnected)
sendRaw("!!removelist " + nickName);
isConnected = false;
clientSocket.Shutdown(SocketShutdown.Receive);
if (chatThread.IsAlive)
chatThread.Abort();
callingForm.Close();
}
catch (Exception) { }
}
private void sendButton_Click(object sender, EventArgs e)
{
if(isConnected)
send(sendBox.Text);
}
private void sendBox_KeyUp(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
{
if (isConnected)
{
if (sendBox.Text != "")
{
send(sendBox.Text);
sendBox.SelectAll();
e.SuppressKeyPress = true;
e.Handled = true;
}
}
}
}
private void send(string t) {
try
{
byte[] data = System.Text.Encoding.ASCII.GetBytes(nickName + ": " + t + "\r\n");
clientSocket.Send(data);
output(nickName + ": " + t);
}
catch (Exception e)
{
displayError(e.ToString());
}
}
private void sendRaw(string t)
{
try
{
byte[] data = System.Text.Encoding.ASCII.GetBytes(t + "\r\n");
clientSocket.Send(data);
}
catch (Exception e)
{
displayError(e.ToString());
}
}
private void chatBox_TextChanged(object sender, EventArgs e)
{
chatBox.SelectionStart = chatBox.Text.Length;
chatBox.ScrollToCaret();
}
private void sendBox_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Enter)
e.SuppressKeyPress = true;
}
}
To do:
Add invokes, more delegates, do some more QA and find out what breaks it.
Also, I believe there's still the possibility of packet loss due to the client addlist functions being in the read loop. I believe this is why the "crappy hack" using Thread.Sleep(10) in the server callback for name population is an issue.
I think it might be better to either pass the command off to another thread while continuing to read or have the client tell the server it's ready for another name.
Otherwise, there might be some data loss during name updates.
The other thing is that, as was said in the comments above, delegates should be used when updating the UI objects (chatbox and listbox). I wrote the code for these but ultimately removed it because there was no noticeable change and I wanted to keep it simple.
I do still use an object lock when outputting text to the chatbox, but there's no noticeable difference there.
The code should be added as not using delegates is potentially problematic, but I literally caught the chat box in an infinite loop of updates without issue.
I tried breaking it with telnet and was successful so I added a newConnection property to the StateObject to ensure that each client can only send "!!addlist" once.
There are, of course, other ways to abuse the server by creating a client that joins and leaves repeatedly, so ultimately I will probably end up passing the !!removelist handling to the server instead of leaving it up to the client.
I am working on this GUI for serial port application. I recently added stop and wait protocols to the application. Surprisingly my disconnect button stopped working. I have thought through the logic and I have not been able to find the problem.
namespace WindowsFormsApplication5
{
public partial class Form1 : Form
{
public bool packetreceived = false;
private SerialPort sp = null; //<---- serial port at form level
public delegate void AddDataDelegate(String myString);
public AddDataDelegate myDelegate;
//delegate variable to disconnect
public AddDataDelegate disconnectDelegate = null;
public void AddDataMethod(String myString)
{
richTextBox1.AppendText(myString);
}
/**
* Takes byte array and returns a string representation
*
*/
public String parseUARTData(byte[] data)
{
if (data.Length == 11)
{
String rv = "";
DataFields d = new DataFields();
if (!packetreceived)
{
d = mainLogic.parseData(data);
packetreceived = true;
}
//TODO
System.Threading.Thread.Sleep(5000);
if (d.sequence == 0)
{
sp.Write("1\r\n");
}
else
{
sp.Write("0\r\n");
}
packetreceived = false;
//now display it as a string
rv += STR_OPCODE + " = " + d.opcode + "\n";
rv += STR_CRC + " = " + d.crc + "\n";
rv += STR_SEQ + " = " + d.sequence + "\n";
rv += STR_FLAGS + " = " + d.flags + "\n";
rv += STR_TEMP + " = " + d.temperature + "\n";
rv += STR_HUMID + " = " + d.humidity + "\n";
rv += STR_PH + " = " + d.ph + "\n";
return rv + "\n\n";
}
else
{
return Encoding.ASCII.GetString(data);
}
}
private void sp_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string s = sp.ReadExisting();
if (disconnectDelegate != null)
{
disconnectDelegate.Invoke(s);
}
richTextBox1.Invoke(this.myDelegate, new Object[] { parseUARTData(Encoding.ASCII.GetBytes(s)) });
}
private void button1_Click(object sender, EventArgs e)
{
connect.Enabled = false;
try
{
// open port if not already open
// Note: exception occurs if Open when already open.
if (!sp.IsOpen)
{
//sp.PortName = this.comboBox1.SelectedItem.ToString();
sp.Open();
}
// send data to port
sp.Write("####,###########\r\n");
disconnect.Enabled = true;
}
catch (Exception)
{
// report exception to user
Console.WriteLine(e.ToString());
}
}
private void button2_Click(object sender, EventArgs e)
{
connect.Enabled = true;
try
{
// open port if not already open
// Note: exception occurs if Open when already open.
if (sp.IsOpen)
{
// send data to port
sp.Write("+++\r\n");
//add the delegate
disconnectDelegate = new AddDataDelegate(onDisconnect);
//sp.WriteTimeout = 500;
// sp.Write("####,0\r\n");
}
}
catch (Exception)
{
Console.WriteLine(e.ToString());
}
finally
{
disconnect.Enabled = false;
}
}
public void OnApplicationExit(object sender, EventArgs e)
{
sp.Close();
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
//foreach (string port in ports)
//{
// comboBoxSerialPorts.Items.Add(port);
//}
}
private void onDisconnect(string msg)
{
string trimmedMsg = msg.Trim();
if (trimmedMsg.Equals("OK"))
{
//send the second time
sp.Write("##,0\r\n");
//null the object
disconnectDelegate = null;
}
}
private void comPort_Click(object sender, EventArgs e)
{
try
{
if (sp.IsOpen)
{
//send data to port
sp.Write("1\r\n");
MessageBox.Show("bluetooth is transmitting data...");
//message box telling user that you are asking for data.
}
}
catch (Exception)
{
// report exception to user
Console.WriteLine(e.ToString());
}
}