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.
Related
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!!
I've got an intra-PC communication server / client set up to send and receive data from one program to another - in this case, a custom server that is listening to text commands and Unity3D.
For the most part, it works, however every once in awhile, it will drop packets, and Unity will not get them without multiple attempts. The packets seem to be sent but lost, as I do see the "Sent message" console log. The following is the code for the server and client:
SERVER:
class TCPGameServer
{
public event EventHandler Error;
public Action<Data> ADelegate;
TcpListener TCPListener;
TcpClient TCPClient;
Client ActiveClient;
NetworkStream networkStream;
StreamWriter returnWriter;
StreamReader streamReader;
Timer SystemTimer = new Timer();
Timer PingTimer = new Timer();
int Port = 8637;
public TCPGameServer()
{
TCPListener = new TcpListener(IPAddress.Loopback, Port);
SystemTimer.Elapsed += StreamTimer_Tick;
SystemTimer.AutoReset = true;
SystemTimer.Interval = 2000;
PingTimer.Elapsed += PingTimer_Tick;
PingTimer.AutoReset = true;
PingTimer.Interval = 30000;
}
public void OpenListener()
{
TCPListener.Start();
TCPListener.BeginAcceptTcpClient(AcceptTCPCallBack, null);
Console.WriteLine("Network Open.");
}
public void GameLogout()
{
SystemTimer.AutoReset = false;
SystemTimer.Stop();
PingTimer.AutoReset = false;
PingTimer.Stop();
ActiveClient = null;
returnWriter.Dispose();
streamReader.Dispose();
Console.WriteLine("The client has logged out successfully.");
}
private void AcceptTCPCallBack(IAsyncResult asyncResult)
{
TCPClient = null;
ActiveClient = null;
returnWriter = null;
streamReader = null;
try
{
TCPClient = TCPListener.EndAcceptTcpClient(asyncResult);
TCPListener.BeginAcceptTcpClient(AcceptTCPCallBack, null);
ActiveClient = new Client(TCPClient);
networkStream = ActiveClient.NetworkStream;
returnWriter = new StreamWriter(TCPClient.GetStream());
streamReader = new StreamReader(TCPClient.GetStream());
Console.WriteLine("Client Connected Successfully.");
Data Packet = new Data();
Packet.cmdCommand = Command.Login;
Packet.strName = "Server";
Packet.strMessage = "LOGGEDIN";
SendMessage(Packet);
SystemTimer.AutoReset = true;
SystemTimer.Enabled = true;
SystemTimer.Start();
Ping();
PingTimer.AutoReset = true;
PingTimer.Enabled = true;
PingTimer.Start();
} catch (Exception ex)
{
OnError(TCPListener, ex);
return;
}
}
private void StreamTimer_Tick(object source, System.Timers.ElapsedEventArgs e)
{
CheckStream();
}
private void PingTimer_Tick(object source, System.Timers.ElapsedEventArgs e)
{
Ping();
}
private void Ping()
{
if (TCPClient.Connected)
{
Data Packet = new Data();
Packet.cmdCommand = Command.Ping;
Packet.strName = "Server";
Packet.strMessage = "PING";
SendMessage(Packet);
}
}
public void CheckStream()
{
try
{
if (TCPClient.Available > 0 || streamReader.Peek() >= 0)
{
string PacketString = streamReader.ReadLine();
Data packet = JsonConvert.DeserializeObject<Data>(PacketString);
switch (packet.cmdCommand)
{
case Command.Logout:
GameLogout();
break;
case Command.Message:
if (ADelegate != null)
{
ADelegate(packet);
}
break;
case Command.Ping:
Console.WriteLine("PONG!");
break;
}
}
} catch (IOException e)
{
Console.WriteLine(e.Message);
} catch (NullReferenceException e)
{
Console.WriteLine(e.Message);
}
}
public void SendMessage(Data packet)
{
if (ActiveClient != null)
{
string packetMessage = JsonConvert.SerializeObject(packet);
returnWriter.WriteLine(packetMessage);
returnWriter.Flush();
}
}
public void OnError(object sender, Exception ex)
{
EventHandler handler = Error;
if (handler != null)
{
ErrorEventArgs e = new ErrorEventArgs(ex);
handler(sender, e);
}
}
public void RegisterActionDelegate(Action<Data> RegisterDelegate)
{
ADelegate += RegisterDelegate;
}
public void UnRegisterActionDelegate(Action<Data> UnregisterDelegate)
{
ADelegate -= UnregisterDelegate;
}
}
CLIENT:
public class TCPNetworkClient
{
public Action<Data> PacketDelegate;
public TcpClient TCPClient;
int Port = 8637;
StreamReader streamReader;
StreamWriter streamWriter;
Timer StreamTimer = new Timer();
public bool LoggedIn = false;
public void Start()
{
if (LoggedIn == false)
{
TCPClient = null;
StreamTimer.AutoReset = true;
StreamTimer.Interval = 2000;
StreamTimer.Elapsed += StreamTimer_Tick;
try
{
TCPClient = new TcpClient("127.0.0.1", Port);
streamReader = new StreamReader(TCPClient.GetStream());
streamWriter = new StreamWriter(TCPClient.GetStream());
StreamTimer.Enabled = true;
StreamTimer.Start();
}
catch (Exception ex)
{
Debug.Log(ex.Message);
}
}
}
private void StreamTimer_Tick(System.Object source, System.Timers.ElapsedEventArgs e)
{
if (TCPClient.Available > 0 || streamReader.Peek() >= 0)
{
string PacketString = streamReader.ReadLine();
Data packet = JsonConvert.DeserializeObject<Data>(PacketString);
PacketDelegate(packet);
}
}
public void Logout()
{
Data Packet = new Data();
Packet.cmdCommand = Command.Logout;
Packet.strMessage = "LOGOUT";
Packet.strName = "Game";
SendMessage(Packet);
if (streamReader != null && streamWriter != null)
{
streamReader.Dispose();
streamWriter.Dispose();
TCPClient.Close();
TCPClient = null;
streamReader = null;
streamWriter = null;
}
StreamTimer.Stop();
}
public void SendMessage(Data packet)
{
string packetMessage = JsonConvert.SerializeObject(packet);
try
{
streamWriter.WriteLine(packetMessage);
streamWriter.Flush();
} catch (Exception e)
{
}
}
public void RegisterActionDelegate(Action<Data> RegisterDelegate)
{
PacketDelegate += RegisterDelegate;
}
public void UnRegisterActionDelegate(Action<Data> UnregisterDelegate)
{
PacketDelegate -= UnregisterDelegate;
}
}
I'm not really sure what's going on, or if there are any more additional checks that I need to add into the system. Note: It's TCP so that "when" this fully works, I can drop the client into other programs that I might write that may not fully rely or use Unity.
new TcpClient("127.0.0.1", Port) is not appropriate for the client. Just use TcpClient(). There is no need to specify IP and port, both of which will end up being wrong.
TCPClient.Available is almost always a bug. You seem to assume that TCP is packet based. You can't test whether a full message is incoming or not. TCP only offers a boundaryless stream of bytes. Therefore, this Available check does not tell you if a whole line is available. Also, there could be multiple lines. The correct way to read is to have a reading loop always running and simply reading lines without checking. Any line that arrives will be processed that way. No need for timers etc.
The server has the same problems.
Issue (2) might have caused the appearance of lost packets somehow. You need to fix this in any case.
I have been facing slow client message consuming in client/server app using TCP sockets in c#. Whenever slow client is connected to server, it affects the processing of other clients.
After reading some literature regarding tcp/ip stack in c#, i concluded that due to RCV_BUFFER full at client side and SND_BUFFER full at server side, other clients are affecting.
Although i couldn't produce the scenario in real environment, so here is what i have done for simulating slow client message processing.
Created sample application for client and implemented the sleep for 1 to 10 seconds before reading it from RCV_BUFFER (so it can be full).
Connecting two clients (one with varying sleep time while other with no sleep time).
I saw that client with no sleep time is affecting but i couldn't determine the pattern of this problem.
Here are some queries, i want to clear confusion on my side.
1. How to determine the size of SND_BUFFER before sending the data to TCP SEND_WINDOW at server side.
2. What steps should i take to determine the pattern of problem. So i can proceed to solution.
Here are code snippets for Server Side.
public bool Start()
{
try
{
_listener.Bind(new IPEndPoint(IPAddress.Any, _port));
_listener.Listen(2000);
_listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 5000);
_listener.BeginAccept(ConnectionReady, null);
LogHelper.ErrorLogger.Debug("Listening started");
return true;
}
catch
{
return false;
}
}
public void createSession(object obj)
{
Socket conn = (Socket)obj;
try
{
LogHelper.ErrorLogger.Debug("Creating Session");
ConnectionState st = new ConnectionState(conn); // Custom class for maintaining the socket object
st._server = this;
st._provider = _provider;
st._buffer = new byte[4];
st._provider.OnAcceptConnection(st);
AcceptConnection.BeginInvoke(st, null, st);
LogHelper.ErrorLogger.Debug("Session Created");
}
catch (Exception ex)
{
try
{
conn.Close();
}
catch { }
LogHelper.ErrorLogger.Debug("Session aborted - >" + ex.ToString());
}
}
private void AcceptConnection_Handler(object state)
{
try
{
ConnectionState st = state as ConnectionState;
try
{
st.AuthenticateSocket();
//Starts the ReceiveData callback loop
if (st._conn.Connected)
st._conn.BeginReceive(st._buffer, 0, 0, SocketFlags.None, ReceivedDataReady, st);
}
catch
{
DropConnection(st);
}
}
catch { }
}
private void ReceivedDataReady_Handler(IAsyncResult ar)
{
try
{
ConnectionState st = ar.AsyncState as ConnectionState;
try
{
try
{
int bytesRcv = st._conn.EndReceive(ar);
//Encoding.UTF8.GetString(buffer, 0, readBytes);
//state.msgBuffer.Append(_receivedStr);
}
catch
{
DropConnection(st); return;
}
//Im considering the following condition as a signal that the
//remote host droped the connection.
if (st._conn.Available == 0)
{
DropConnection(st);//##SHARIQ
return;
}
else
{
try
{
st._provider.OnReceiveData(st);
}
catch
{
return;
}
//Resume ReceivedData callback loop
if (st._conn.Connected)
st._conn.BeginReceive(st._buffer, 0, 0, SocketFlags.None, ReceivedDataReady, st);
}
}
catch { DropConnection(st); return; }
}
catch { }
}
Message is fetched from MSMQ (a thread is running to fetch messages from MSMQ through receiver object), and whenever message is fetched following event is fired and extracts ip addresses from messages and send one message to socket(s).
private void m_broker_OnMessage(object obj)
{
try
{
Message m = (Message)obj;
m.Formatter = new BinaryMessageFormatter();
ConnectionState tstate = null;
bool containststate = false;
string TempLabels = string.Empty;
string BodyMessage = string.Empty;
if (m.Body.ToString().StartsWith("="))
{
BodyMessage = (string)m.Body;
TempLabels = BodyMessage.Substring(1, BodyMessage.IndexOf('#') - 1);
BodyMessage = BodyMessage.Substring(BodyMessage.IndexOf('#') + 1);
}
if (!string.IsNullOrEmpty(TempLabels))
{
string[] labels = TempLabels.Split(',');
foreach (string label in labels)
{
lock (cons)
{
containststate = cons.Contains(label);
if (containststate)
{
tstate = (ConnectionState)cons[label];
}
}
if (containststate)
{
ConnectionState state = tstate;
if (!state.WriteLine(BodyMessage + "1057=" + label + "#"))
{
OnDropConnection(state);
continue;
}
if (ConfigurationSettings.AppSettings["FullLog"] == "1")
{
eventLogger.Debug("OUT " + label + " " + BodyMessage);
}
}
else
{
long result;
if (!lastResolve.Contains(label))
{
if ((!string.IsNullOrEmpty(label)) && long.TryParse(label, out result))
{
if (ConfigurationSettings.AppSettings["FullLog"] == "1")
{
eventLogger.Info("Label not found: " + label);
}
string msg = "8=EXX.1.0#35=C7#1057=" + label + "#";
this.Send(msg, label, "0.0.0.0");
eventLogger.Info("Connection Disconnected: " + label);
//Nothing to clean here
lock (cons)
{
if (cons.Contains(label))
{
try
{
string ipaddress = ((ConnectionState)cons[label]).RemoteEndPoint.ToString().Split(':')[0];
connectionGroups[ipaddress]--;
}
catch { }
}
cons.Remove(label);
lastResolve.Add(label);
}
}
}
continue;
}
}
}
else
{
lock (cons)
{
containststate = cons.Contains(m.Label);
if (containststate)
{
tstate = (ConnectionState)cons[m.Label];
}
}
if (containststate)
{
ConnectionState state = tstate;
if (!state.WriteLine((string)m.Body + "1057=" + m.Label + "#"))
{
OnDropConnection(state);
return;
}
if (ConfigurationSettings.AppSettings["FullLog"] == "1")
{
eventLogger.Debug("OUT " + m.Label + " " + m.Body.ToString());
}
}
else
{
long result;
if (!lastResolve.Contains(m.Label))
{
if ((!string.IsNullOrEmpty(m.Label)) && long.TryParse(m.Label, out result))
{
if (ConfigurationSettings.AppSettings["FullLog"] == "1")
{
eventLogger.Info("Label not found: " + m.Label);
}
string msg = "8=EXX.1.0#35=C7#1057=" + m.Label + "#";
this.Send(msg, m.Label, "0.0.0.0");
eventLogger.Info("Connection Disconnected: " + m.Label);
//Nothing to clean here
lock (cons)
{
if (cons.Contains(m.Label))
{
try
{
string ipaddress = ((ConnectionState)cons[m.Label]).RemoteEndPoint.ToString().Split(':')[0];
connectionGroups[ipaddress]--;
}
catch { }
}
cons.Remove(m.Label);
lastResolve.Add(m.Label);
}
}
}
return;
}
}
}
catch (Exception e)
{
errorLogger.Error(e.Message, e);
}
}
Sending is done in blocking manner
public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags)
{
lock (sendObject)
{
try
{
if (_innerSocketStream.IsUsingSsl)
{
myStream.Write(buffer, offset, size);
}
else
{
_innerSocketStream.Socket.Send(buffer, offset, size, SocketFlags.None);
}
}
catch (SocketException)
{
return 0;
}
return size;
}
}
This is my scenario:
Client :
Send xml data in pieces continuously 24/7 - (It is working fine and it is not in my control).
Server - My Code:
1. Listen continuously.
2. Receive the incoming message, buffer it and create valid xml from buffer.
3. Send it to the MSMQ ( Host will do this )
I wrote a tcp server code (adding pieces of code from google), which will be hosted in windows service. Everything works fine when I run the service in local but when I place it PROD, it listens upto 73K messages and it stops receiving. It is not throwing any exception. It just blocks at BeginReceive function. I have tried using ReceiveTimeOut also. I have seen netstat also and the connections is still in established stat.
When I restart the service, it again works fine. Here I am posting my server code. Please help on this.
StringBuilder content = new StringBuilder();
public event MessageReceiveEventHandler MessageReceived;
// An ArrayList is used to keep track of worker sockets that are designed
// to communicate with each connected client. Make it a synchronized ArrayList
// For thread safety
private System.Collections.ArrayList workerSocketList =
ArrayList.Synchronized(new System.Collections.ArrayList());
private int m_clientCount = 0;
private Socket m_mainSocket = null;
private AsyncCallback ReadCallback;
private AsyncCallback ConnectionCallback;
public MedDeviceListener(string ipAddress, int port, int maxConnections=100)
{
ProfileProvider.Instance.LogInformationIf(_debug);
this._port = port;
this._ipAddress = ipAddress;
this._maxConnections = maxConnections;
ReadCallback = new AsyncCallback(Receive_handler);
ConnectionCallback = new AsyncCallback(Connection_handler);
lenghtofStartMsg = header.Length;
lengthOfEndMsg = footer.Length;
}
public void Start()
{
ProfileProvider.Instance.LogInformationIf(_debug);
// Data buffer for incoming data.
byte[] bytes = new Byte[_bufferSize];
// Establish the local endpoint for the socket.
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse(_ipAddress), _port);
// Create a TCP/IP socket.
m_mainSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
m_mainSocket.Bind(localEndPoint);
m_mainSocket.Listen(100);
InstrumentationProvider.Instance.LogInformation("MedDeviceListener successfully connected to IP:" + _ipAddress+"\nPort :"+_port);
m_mainSocket.BeginAccept(ConnectionCallback, m_mainSocket);
}
catch (Exception e)
{
InstrumentationProvider.Instance.LogException("MedDeviceListener.Start", e);
throw e;
}
}
private void Connection_handler(IAsyncResult ar)
{
try
{
ProfileProvider.Instance.LogInformationIf(_debug);
Socket listener = (Socket)ar.AsyncState;
Socket workerSocket = listener.EndAccept(ar);
// Now increment the client count for this client
// in a thread safe manner
Interlocked.Increment(ref m_clientCount);
// Add the workerSocket reference to our ArrayList
workerSocketList.Add(workerSocket);
SendConnectedAck(_clientConnectAckMessage, m_clientCount);
WaitForData(workerSocket, m_clientCount);
//Resume the listening callback loop
listener.BeginAccept(Connection_handler, listener);
}
catch (ObjectDisposedException)
{
InstrumentationProvider.Instance.LogInformation("The listener socket has been closed");
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("Connection_handler", ex);
throw;
}
}
private void Receive_handler(IAsyncResult ar)
{
ProfileProvider.Instance.LogInformationIf(_debug);
StateObject state = (StateObject)ar.AsyncState;
try
{
// Retrieve the state object and the handler socket
// from the asynchronous state object.
Socket workSocket = state.workSocket;
// Read data from the client socket.
int bytesRead = workSocket.EndReceive(ar);
if (bytesRead > 0)
{
//InstrumentationProvider.Instance.LogInformationIf(_debug, bytesRead+" read..");
// There might be more data, so parse the data received so far.
string data= Encoding.ASCII.GetString(state.buffer, 0, bytesRead);
try
{
ParseIncomingMessage(data, workSocket);
}
catch(Exception parseEx)
{
content.Clear();
InstrumentationProvider.Instance.LogException("ParseIncomingMessage", parseEx);
}
}
WaitForData(state.workSocket, state.clientNumber);
}
catch (ObjectDisposedException)
{
InstrumentationProvider.Instance.LogInformation("Receive_handler: The listener socket has been closed");
}
catch (SocketException se)
{
//close the existing connection
CloseSockets();
//restart it again
this.Start();
}
}
private void WaitForData(Socket workerSocket, int clientNumber)
{
ProfileProvider.Instance.LogInformationIf(_debug);
try
{
StateObject theSocPkt = new StateObject(workerSocket, clientNumber);
workerSocket.ReceiveTimeout = 2000;
workerSocket.BeginReceive(theSocPkt.buffer, 0,
theSocPkt.buffer.Length,
SocketFlags.None,
Receive_handler,
theSocPkt);
}
catch(TimeoutException ex)
{
InstrumentationProvider.Instance.LogException("WaitForData - TimeOutException", ex);
}
catch (SocketException se)
{
InstrumentationProvider.Instance.LogException("MedDeviceListener.WaitForData", se);
//close the existing connection
CloseSockets();
//restart it again
this.Start();
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("WaitForData",ex);
//close the existing connection
CloseSockets();
//restart it again
this.Start();
}
}
private void ParseIncomingMessage(string msg,Socket wrkSocket)
{
Socket workSocket = wrkSocket;
bool hasStartTag = isMsgContainsStartTag(msg);
bool hasEndTag = isMsgContainsEndTag(msg);
int startTagIndex = indexOfStartTag(msg);
int endTagIndex = indexOfEndTag(msg);
// If the incomming message dont have either start or end tag
if (hasStartTag == false && hasEndTag == false)
{
content.Append(msg);
}
//check for the starttag first
//if message contains startTag
else if (hasStartTag)
{
if (startTagIndex != 0)//there is something before starttag
{
string subStr = msg.Substring(0, startTagIndex);
content.Append(subStr);
//Check and send the content
CheckSendMessage(workSocket);
//Parse the remaining message from start tag to end of the message
ParseIncomingMessage(msg.Substring(startTagIndex, msg.Length - subStr.Length), wrkSocket);
}
else if (startTagIndex == 0)
{
content.Clear();
if (hasEndTag)
{
int endOfEndTag = endTagIndex + lengthOfEndMsg;
string subStr = msg.Substring(0, endOfEndTag); //message statrs with start tag and ends contains full end tag so first get that string and send that.
content.Append(subStr);
CheckSendMessage(workSocket);
//Parse the remaining message from endtag+1 to end
ParseIncomingMessage(msg.Substring(endOfEndTag, msg.Length - endOfEndTag), wrkSocket);
}
else
{
content.Append(msg);
}
}
}
//if message contains EndTag ALONE
else if (hasEndTag)
{
int endOfEndTag = endTagIndex + lengthOfEndMsg;
string subStr = msg.Substring(0, endOfEndTag);
content.Append(subStr);
CheckSendMessage(workSocket);
//Parse remaining message after end tag
ParseIncomingMessage(msg.Substring(endOfEndTag, msg.Length - endOfEndTag), wrkSocket);
}
}
private void CheckSendMessage(Socket workSocket)
{
string msg=content.ToString().Trim();
//if content contains both start and end tag then send the content
if (isMsgContainsStartTag(msg) && isMsgContainsEndTag(msg) &&
indexOfStartTag(msg) == 0 && indexOfEndTag(msg) + lengthOfEndMsg == msg.Length)
{
//Send the message
using (MedDeviceListenerEventArgs e = new MedDeviceListenerEventArgs(msg))
{
OnReceiveComplete(e);
SendReceiveAck(workSocket, _receiveAckMessage);
}
}
}
private void SendReceiveAck(Socket handler, String data)
{
try
{
ProfileProvider.Instance.LogInformationIf(_debug);
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
handler.Send(byteData);
InstrumentationProvider.Instance.LogInformationIf(_debug, "Message received acknowledgement:" + _receiveAckMessage + " has been sent successfully");
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("SendReceiveAck", ex);
}
}
private void SendConnectedAck(string msg, int clientNumber)
{
ProfileProvider.Instance.LogInformationIf(_debug);
try
{
// Convert the reply to byte array
byte[] byData = System.Text.Encoding.ASCII.GetBytes(msg);
Socket workerSocket = (Socket)workerSocketList[clientNumber - 1];
workerSocket.Send(byData);
InstrumentationProvider.Instance.LogInformationIf(_debug, "Client Connected acknowledgement:" + _clientConnectAckMessage + " has been sent successfully");
}
catch (Exception ex)
{
InstrumentationProvider.Instance.LogException("SendConnectedAck", ex);
throw;
}
}
public void CloseSockets()
{
try
{
ProfileProvider.Instance.LogInformationIf(_debug);
if (m_mainSocket != null)
{
if (m_mainSocket.Connected)
{
m_mainSocket.Shutdown(SocketShutdown.Both);
m_mainSocket.Close();
m_mainSocket = null;
}
}
Socket workerSocket = null;
for (int i = 0; i < workerSocketList.Count; i++)
{
workerSocket = (Socket)workerSocketList[i];
if (workerSocket != null)
{
workerSocket.Shutdown(SocketShutdown.Both);
workerSocket.Close();
workerSocket = null;
}
}
}
catch(Exception ex)
{
InstrumentationProvider.Instance.LogException("CloseSockets",ex);
}
}
protected virtual void OnReceiveComplete(MedDeviceListenerEventArgs e)
{
if (MessageReceived != null)
{
MessageReceived(this, e);
}
}
private int indexOfStartTag(string msg)
{
return msg.IndexOf(header);
}
private int indexOfEndTag(string msg)
{
return msg.IndexOf(footer);
}
private bool isMsgContainsStartTag(string msg)
{
return msg.Contains(header);
}
private bool isMsgContainsEndTag(string msg)
{
return msg.Contains(footer);
}
public delegate void MessageReceiveEventHandler(object sender,MedDeviceListenerEventArgs e);
public class MedDeviceListenerEventArgs : EventArgs,IDisposable
{
private string _receivedData;
public MedDeviceListenerEventArgs(string receivedData)
{
_receivedData = receivedData;
}
public string ReceivedData
{
get
{
return _receivedData;
}
}
public void Dispose()
{ }
}
}
I have read similar posts, tried everything but with no luck. Please help :)
Thanks
-MM
I have one server and client application using socket programming in c#. In this, max. 10 clients can be connected to the server at a time. But my requirement is that I have to block one of the clients via IP address when i'm sending messages through server.. Please help with blocking. The program is given below..
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
namespace Server
{
public partial class SocketServer : Form
{
const int MAX_CLIENTS = 10;
public AsyncCallback pfnWorkerCallBack;
private Socket m_mainSocket;
private Socket[] m_workerSocket = new Socket[10];
private int m_clientCount = 0;
private byte[] byData;
public SocketServer()
{
InitializeComponent();
textBoxIP.Text = GetIP();
}
String GetIP()
{
String strHostName = Dns.GetHostName();
// Find host by name
IPHostEntry iphostentry = Dns.GetHostByName(strHostName);
// Grab the first IP addresses
String IPStr = "";
foreach (IPAddress ipaddress in iphostentry.AddressList)
{
IPStr = ipaddress.ToString();
ip = IPStr;
return IPStr;
}
ip = IPStr;
return IPStr;
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void buttonStartListen_Click(object sender, EventArgs e)
{
try
{
// Check the port value
if (textBoxPort.Text == "")
{
MessageBox.Show("Please enter a Port Number");
return;
}
string portStr = textBoxPort.Text;
int port = System.Convert.ToInt32(portStr);
// Create the listening socket...
m_mainSocket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);
// Bind to local IP Address...
m_mainSocket.Bind(ipLocal);
// Start listening...
m_mainSocket.Listen(4);
// Create the call back for any client connections...
m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
UpdateControls(true);
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
private void UpdateControls(bool listening)
{
buttonStartListen.Enabled = !listening;
buttonStopListen.Enabled = listening;
}
public delegate void UpdateTextCallback(string message, object obj);
public void OnClientConnect(IAsyncResult asyn)
{
try
{
// Here we complete/end the BeginAccept() asynchronous call
// by calling EndAccept() - which returns the reference to
// a new Socket object
m_workerSocket[m_clientCount] = m_mainSocket.EndAccept(asyn);
// Let the worker Socket do the further processing for the
// just connected client
WaitForData(m_workerSocket[m_clientCount]);
// Now increment the client count
++m_clientCount;
// Display this client connection as a status message on the GUI
String str = String.Format("Client # {0} connected", m_clientCount);
//textBoxMsg.Text = str;
textBoxMsg.BeginInvoke(new UpdateTextCallback(UpdateText), new object[] { str, textBoxMsg });
// Since the main Socket is now free, it can go back and wait for
// other clients who are attempting to connect
m_mainSocket.BeginAccept(new AsyncCallback(OnClientConnect), null);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\n OnClientConnection: Socket has been closed\n");
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
private void UpdateText(string message, object ctrl)
{
if (ctrl is TextBox)
textBoxMsg.Text = message;
if(ctrl is RichTextBox)
richTextBoxReceivedMsg.AppendText(message);
}
public class SocketPacket
{
public System.Net.Sockets.Socket m_currentSocket;
public byte[] dataBuffer = new byte[1];
}
public void WaitForData(System.Net.Sockets.Socket soc)
{
try
{
if (pfnWorkerCallBack == null)
{
// Specify the call back function which is to be
// invoked when there is any write activity by the
// connected client
pfnWorkerCallBack = new AsyncCallback(OnDataReceived);
}
SocketPacket theSocPkt = new SocketPacket();
theSocPkt.m_currentSocket = soc;
// Start receiving any data written by the connected client
// asynchronously
soc.BeginReceive(theSocPkt.dataBuffer, 0,
theSocPkt.dataBuffer.Length,
SocketFlags.None,
pfnWorkerCallBack,
theSocPkt);
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
public void OnDataReceived(IAsyncResult asyn)
{
try
{
SocketPacket socketData = (SocketPacket)asyn.AsyncState;
int iRx = 0;
// Complete the BeginReceive() asynchronous call by EndReceive() method
// which will return the number of characters written to the stream
// by the client
iRx = socketData.m_currentSocket.EndReceive(asyn);
char[] chars = new char[iRx + 1];
System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
int charLen = d.GetChars(socketData.dataBuffer,
0, iRx, chars, 0);
System.String szData = new System.String(chars);
//richTextBoxReceivedMsg.AppendText(szData);
richTextBoxReceivedMsg.BeginInvoke(new UpdateTextCallback(UpdateText), new object[] { szData, richTextBoxReceivedMsg });
// Continue the waiting for data on the Socket
WaitForData(socketData.m_currentSocket);
}
catch (ObjectDisposedException)
{
System.Diagnostics.Debugger.Log(0, "1", "\nOnDataReceived: Socket has been closed\n");
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
private void buttonStopListen_Click(object sender, EventArgs e)
{
CloseSockets();
UpdateControls(false);
}
void CloseSockets()
{
if (m_mainSocket != null)
{
m_mainSocket.Close();
}
for (int i = 0; i < m_clientCount; i++)
{
if (m_workerSocket[i] != null)
{
m_workerSocket[i].Close();
m_workerSocket[i] = null;
}
}
}
private void buttonSendMsg_Click(object sender, EventArgs e)
{
try
{
Object objData = richTextBoxSendMsg.Text;
byData = System.Text.Encoding.ASCII.GetBytes(objData.ToString());
for (int i = 0; i < m_clientCount; i++)
{
if (m_workerSocket[i] != null)
{
if (m_workerSocket[i].Connected)
{
m_workerSocket[i].Send(byData);
}
}
}
}
catch (SocketException se)
{
MessageBox.Show(se.Message);
}
}
private void Form1_Minimize(object sender, System.EventArgs e)
{
if (FormWindowState.Minimized == WindowState)
{
Hide();
this.notify.Visible = true;
}
}
private void Form1_Resize(object sender, System.EventArgs e)
{
Show();
WindowState = FormWindowState.Normal;
this.notify.Visible = false;
}
This is somewhat easy to do, you just need to look a little more at the client connection routine... Replace the 127.0.0.1 below with the IP address you want to deny and throw an exception or simply close the connection and return.
public void OnClientConnect(IAsyncResult asyn)
{
try
{
TcpListener listener = (TcpListener)ar.AsyncState;
System.Net.Sockets.TcpClient client = listener.EndAcceptTcpClient(ar);
IPEndPoint clientEndPoint = (IPEndPoint)client.Client.RemoteEndPoint;
if (clientEndPoint.Address == new IPAddress("127.0.0.1"))
throw new InvalidOperationException();