Тема: Чат з використанням класів TcpClient та TcpListener
У мене завдання написати чат, використовуючи класи TcpClient та TcpListener. Чат має бути мультиклієнтний.
Я маю сторону сервера та сторону клієнта у різних програмах.
Ось код програми серверної частини (програма консольна):
▼Прихований текст
class Program
{
/*
* This dictionary for saving all logins and password in it
*/
static Dictionary<string, string> logins = new Dictionary<string, string>();
/*
*This dictionary for saving ip asddresses in it
*/
static Dictionary<string, string> addresses = new Dictionary<string, string>();
/*
*This list for saving users whose online
*/
static List<string> userOnline = new List<string>();
static TcpListener listener;
/*
* This method gets from user's message user's login, password
*/
static void parseUserMessage(string userMessage, ref string userLogin, ref string userPassword)
{
userMessage = userMessage.Substring(userMessage.IndexOf(':') + 1);
string[] userInfo = userMessage.Split('/');
userLogin = userInfo[0];
userPassword = userInfo[1];
}
static void getUserLogin(string userMessage, ref string userLogin)
{
userMessage = userMessage.Substring(userMessage.IndexOf(':') + 1);
string[] userInfo = userMessage.Split('/');
userLogin = userInfo[0];
}
static string getMd5Hash(MD5 md5Hash, string input)
{
byte[] data = md5Hash.ComputeHash(Encoding.ASCII.GetBytes(input));
StringBuilder sBuilder = new StringBuilder();
for (int i = 0; i < data.Length; ++i)
{
sBuilder.Append(data[i].ToString("x2"));
}
return sBuilder.ToString();
}
static bool isCorrectUser(string login, string password)
{
MD5 md5Hash = MD5.Create();
string hash = getMd5Hash(md5Hash, password);
for (int i = 0; i < logins.Count; ++i)
{
if(String.Compare(logins[login],hash) == 0)
{
return true;
}
}
return false;
}
/*
* This method check whether exists user with this login
* in base
* If user exists than method returns true, else false
*/
static bool isExistUser(string login)
{
for (int i = 0; i < logins.Count; ++i)
{
if (logins.ContainsKey(login))
return true;
}
return false;
}
static void HandleClient()
{
string userLogin = null;
string userPassword = null;
string userAddress = null;
TcpClient client = listener.AcceptTcpClient();
Socket stream = client.Client;
byte[] buffer = new byte[2048];
stream.Receive(buffer);
userAddress = (client.Client.RemoteEndPoint as IPEndPoint).Address.ToString();
string userMessage = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
string request = userMessage.Substring(0, userMessage.IndexOf(':'));
/*
* This part for debugging
*/
StreamWriter file = File.AppendText("log.txt");
file.WriteLine(request);
file.Close();
switch (request)
{
case "Login":
parseUserMessage(userMessage, ref userLogin, ref userPassword);
if (isExistUser(userLogin))
{
if (isCorrectUser(userLogin, userPassword))
{
stream.Send(Encoding.ASCII.GetBytes("Good"));
userOnline.Add(userLogin);
}
else
{
stream.Send(Encoding.ASCII.GetBytes("Wrong"));
}
}
else
{
MD5 md5Hash = MD5.Create();
string hashPassword = getMd5Hash(md5Hash, userPassword);
stream.Send(Encoding.ASCII.GetBytes("Good"));
logins.Add(userLogin, hashPassword);
addresses.Add(userLogin, userAddress);
userOnline.Add(userLogin);
}
break;
/*
* Just for testing. There is must be another code
*/
case "Send":
stream.Send(Encoding.ASCII.GetBytes("Good"));
break;
case "GetListOnline":
string loginsForSend = null;
for (int i = 0; i < userOnline.Count; ++i)
{
loginsForSend += userOnline[i];
loginsForSend += "/";
}
loginsForSend += userOnline[userOnline.Count - 1];
stream.Send(Encoding.ASCII.GetBytes(loginsForSend));
break;
case "Disconnect":
getUserLogin(userMessage, ref userLogin);
userOnline.Remove(userLogin);
break;
}
client.Close();
}
static void Main(string[] args)
{
try
{
listener = new TcpListener(IPAddress.Any, 1024);
listener.Start();
while (true)
{
if (listener.Pending())
{
Thread thread = new Thread(new ThreadStart(HandleClient));
thread.Start();
}
}
}
catch (SocketException sockEx)
{
Console.WriteLine("Socket's error " + sockEx.Message);
}
catch (Exception ex)
{
Console.WriteLine("Error: " + ex.Message);
}
finally
{
listener.Stop();
}
}
}
І сторона кліента. Вона з інтерфейсом, що має дві форми: одна для логування,
▼Прихований текст
public partial class Form1 : Form
{
string userLogin;
string userPassword;
TcpClient client;
public Form1()
{
InitializeComponent();
}
private void b_login_Click(object sender, EventArgs e)
{
try
{
client = new TcpClient();
client.Connect("192.168.1.8", 1024);
Socket stream = client.Client;
if (tb_login.Text != "")
{
userLogin = tb_login.Text;
}
if (tb_password.Text != "")
{
userPassword = tb_password.Text;
}
string sendMessage = "Login:" + userLogin + "/" + userPassword;
stream.Send(Encoding.ASCII.GetBytes(sendMessage));
byte[] buffer = new byte[1024];
stream.Receive(buffer);
string serverAnswer = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
if (serverAnswer == "Good")
{
this.Visible = false;
Chat chat = new Chat(this, client, userLogin);
chat.ShowDialog();
this.Visible = true;
tb_login.Text = "";
tb_password.Text = "";
}
else
{
MessageBox.Show("Wrong! Try again");
tb_login.Text = "";
tb_password.Text = "";
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void b_cancel_Click(object sender, EventArgs e)
{
this.Close();
}
}
друга для чату.
▼Прихований текст
public partial class Chat : Form
{
Form1 parent;
string userLogin;
Thread thread;
TcpClient client;
public Chat()
{
InitializeComponent();
}
public Chat(Form1 parent, TcpClient client, string userLogin): this()
{
this.parent = parent;
this.client = client;
this.userLogin = userLogin;
thread = new Thread(new ParameterizedThreadStart(getUserOnline));
thread.IsBackground = true;
thread.Start(client);
}
private void getUserOnline(object obj)
{
try
{
TcpClient threadClient = (TcpClient)obj;
while (true)
{
Socket threadStream = threadClient.Client;
if (lbox_Online.Items.Count > 0)
lbox_Online.Invoke(new Action(() => lbox_Online.Items.Clear()));
threadStream.Send(Encoding.ASCII.GetBytes("GetListOnline:"));
StreamWriter file = File.AppendText("C:\\temp\\client_log.txt");
file.WriteLine(111);
file.Close();
byte[] buffer = new byte[2048];
threadStream.Receive(buffer);
string serverAnswer = Encoding.ASCII.GetString(buffer).TrimEnd('\0');
string[] usersLogins = serverAnswer.Split('/');
lbox_Online.Invoke(new Action(() =>
{
for (int i = 0; i < usersLogins.Length; ++i)
{
lbox_Online.Items.Add(usersLogins[i]);
}
}
));
Thread.Sleep(2000);
}
}
catch(Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void Chat_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
Socket stream = client.Client;
string sendMessage = "Disconnect:" + userLogin + "/";
stream.Send(Encoding.ASCII.GetBytes(sendMessage));
client.Close();
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
private void b_Send_Click(object sender, EventArgs e)
{
try
{
Socket stream = client.Client;
string whom = userLogin;
string sendMessage = "Send:" + userLogin + ":" + textBox2.Text;
stream.Send(Encoding.ASCII.GetBytes(sendMessage));
byte[] data = new byte[1024];
stream.Receive(data);
string serverAnswer = Encoding.ASCII.GetString(data);
if (serverAnswer == "good")
{
lbox_Message.Items.Add(sendMessage);
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}
}
}
І, власне, сама проблема: Коли клієнт надсилає до серевера перше повідомлення (у моєму випадку це при логуванні),
то все ніби працює. Але коли намагаюсь відправляти наступні ( наприклад отримати список корстувачів чи просто відправити повідомлення) виникає виключення: An established connection was aborted by the software in your host machine.
З чим це може бути пов'язано?