Міністерство освіти та науки України
Національний університет «Львівська політехніка»
Інститут комп’ютерних наук та інформаційних технологій
Кафедра ПЗ
З В І Т
Лабораторна робота №5
з курсу «Програмне забезпечення мережених технологій»
Тема: «Створення клієнт-серверних програм
за допомогою бібліотек C#»
Лектор:
Проф. каф. ПЗ
Мельник Р.А.
Львів-2010
Мета роботи:
Ознайомитися з концепціями програмування мовою C#, а також засвоїти основні стандартні класи і методи бібліотек System.Net, System.Net.Sockets; навчитись створювати об’єкти клієнта та сервера, встановлювати між ними з’єднання і забезпечувати обмін повідомленнями між ними.
Теоретичні відомості
Клас Socket
Реалізує інтерфейс сокетів.
Простір імен: System.Net.Sockets
public class Socket : IDisposable
Клас Socket забезпечує широкий набір методів і властивостей для мережевих взаємодій. Клас Socket дозволяє виконувати як синхронну, так і асинхронну передачу даних з використанням будь-якого з комунікаційних протоколів, наявних в перерахуванні ProtocolType.
Клас Socket дотримується шаблону імен платформи .NET Framework для асинхронних методів. Наприклад, синхронний метод Receive відповідає асинхронним методам BeginReceive і EndReceive.
Якщо додатку при його виконанні потрібний лише один потік, можна скористатися приведеними нижче методами, які розроблені для роботи в синхронному режимі.
Якщо використовується протокол, орієнтований на встановлення з'єднання, такий як протокол TCP, сервер повинен виконувати прослухування підключень, використовуючи метод Listen. Метод Accept обробляє будь-які вхідні запити на підключення і повертає об'єкт Socket, який може використовуватися для передачі даних з віддаленого вузла. Слід використовувати цей повернений об'єкт Socket для виклику методу Send або Receive. Слід викликати метод Bind, перш ніж робити звернення до методу Listen, якщо необхідно вказати локальну IP-адрес або номер порту. Якщо потрібно під’єднатись підключення до вузла, слід викликати метод Connect. Для обміну даними слід викликати метод Send або Receive.
Якщо використовується протокол, не орієнтований на встановлення з'єднання, такий як протокол UDP, немає необхідності у відстежуванні підключень. Для прийому всіх дейтаграм, що поступають, слід викликати метод ReceiveFrom. Для посилки дейтаграм на віддалений вузол слід використовувати метод SendTo.
Якщо на сокеті виконується декілька асинхронних операцій, вони не обов'язково повинні завершуватися в тому ж порядку, в якому ці операції запускаються.
Коли прийом і відправка даних завершені, слід використовувати метод Shutdown для того, щоб відключити об'єкт Socket. Після виклику методу Shutdown слід звернутися до методу Close, аби звільнити всі пов'язані з об'єктом Socket ресурси.
Клас TcpClient
Забезпечує клієнтські підключення для мережевих служб TCP.
Простір імен: System.Net.Sockets
public class TcpClient : IDisposable
Клас TcpClient забезпечує прості методи для підключення, а також відправки і отримання потоків даних в мережі в синхронному режимі.
Для того, щоб об'єкт TcpClient міг виконати підключення і обмін даними, об'єкт TcpListener або Socket, створений з використанням протоколу ProtocolType TСР, повинен очікувати на вхідні запити на підключення. Підключитися до даного прослуховувача можна одним з наступних двох способів:
Створити об'єкт TcpClient і викликати один з трьох наявних методів Connect.
Створити об'єкт TcpClient, використовуючи ім'я вузла і номер порту віддаленого вузла. Цей конструктор автоматично робитиме спроби встановлення підключення.
Клас TcpListener
Чекає підключення від TCP-клієнтів мережі.
Простір імен: System.Net.Socketspublic class TcpListener
Клас TcpListener надає прості методи, призначені для очікування і прийому в блокуючому синхронному режимі вхідних запитів на підключення. Можна використовувати об'єкт TcpClient або Socket, аби підключитися до об'єкту TcpListener. Об'єкт TcpListener можна створити, використовуючи об'єкт IPEndPoint, локальну IP-адрес і номер локального порту або ж лише номер порту.
Слід використовувати метод Start, щоб почати очікування вхідних запитів на підключення. Метод Start ставитиме в чергу вхідні підключення до тих пір, поки не буде викликаний метод Stop або в чергу не буде поставлено кількість запитів, задану параметром MaxConnections. Для прийняття підключень з вхідної черги підключень слід використовувати метод AcceptSocket або AcceptTcpClient.
Щоб закрити об’єкт TcpListener, слід викликати метод Stop.
Завдання до лабораторної роботи
Створити клас клієнта.
Створити клас сервера.
Забезпечити клієнт-серверне з’єднання.
Забезпечити обмін повідомленнями між клієнтом та сервером.
Текст програми
//------------------------------------ Реалізація Сервера ----------------------------------------//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace PZMTLab5
{
public partial class Form1 : Form
{
Socket listener;
Socket server;
SqlConnection SqlCon;
SqlDataReader SqlDReader;
SqlCommand SqlComnd;
IPHostEntry HostInfo;
IPAddress IpAddr;
IPEndPoint EndPoint;
public Form1()
{
InitializeComponent();
}
private void button1_Click_1(object sender, EventArgs e)
{
HostInfo = Dns.Resolve(Dns.GetHostName());
IpAddr = HostInfo.AddressList[0];
EndPoint = new IPEndPoint(IpAddr, 35000);
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
listener.Bind(EndPoint);
button1.Enabled = false;
button1.Text = ("Сервер працює");
backgroundWorker1.RunWorkerAsync();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
listener.Listen(10);
server = listener.Accept();
SqlCon = new SqlConnection("Data Source=ABORUGEN-CAE305;Initial Catalog=PZMTLab5;Integrated Security=True");
while (true)
{
try
{
byte[] bytes = new byte[1024];
int MessSize = server.Receive(bytes);
if (MessSize < 1)
{
server = listener.Accept();
continue;
}
SqlCon.Open();
string SqlQuery = Encoding.Unicode.GetString(bytes, 0, MessSize);
if (SqlQuery.Contains("SELECT"))
{
SqlComnd = new SqlCommand(SqlQuery, SqlCon);
SqlDReader = SqlComnd.ExecuteReader();
int RowCount = 0;
byte[] tmp = new byte[10];
while (SqlDReader.Read())
{
RowCount++;
}
SqlDReader.Close();
server.Send(Encoding.Unicode.GetBytes(RowCount.ToString()));
server.Receive(tmp);
SqlDReader = SqlComnd.ExecuteReader();
while (SqlDReader.Read())
{
for (int i = 0; i < 3; i++)
{
server.Send(Encoding.Unicode.GetBytes(SqlDReader[i].ToString()));
server.Receive(tmp);
}
}
SqlDReader.Close();
SqlCon.Close();
continue;
}
else
{
SqlComnd = new SqlCommand(SqlQuery, SqlCon);
SqlComnd.ExecuteNonQuery();
server.Send(Encoding.Unicode.GetBytes("OK"));
SqlDReader.Close();
SqlCon.Close();
continue;
}
}
catch (Exception ex)
{
SqlDReader.Close();
SqlCon.Close();
continue;
}
}
}
private void button4_Click(object sender, EventArgs e)
{
Close();
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
}
}
}
//------------------------------------ Реалізація Клієнта ----------------------------------------//
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
namespace PZMTLab5cl
{
public partial class Form1 : Form
{
IPAddress adrr;
IPEndPoint EndPoint;
Socket client;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
client.Connect(EndPoint);
if (checkBox1.Checked == true)
client.Send(Encoding.Unicode.GetBytes("SELECT * FROM Workman WHERE Surname = '" + textBox2.Text.ToString() + "'"));
else
client.Send(Encoding.Unicode.GetBytes("SELECT * FROM Workman"));
byte[] k = new byte[10];
client.Receive(k);
client.Send(Encoding.Unicode.GetBytes("OK"));
textBox1.Text = "Список Робітників сервісу:" + Environment.NewLine;
for (int i = 0; i < Convert.ToInt16(Encoding.Unicode.GetString(k)); i++)
{
for (int j = 0; j < 2; j++)
{
byte[] RecvBytes = new byte[1024];
int size = client.Receive(RecvBytes);
string recMes = Encoding.Unicode.GetString(RecvBytes, 0, size);
textBox1.Text += recMes + Environment.NewLine;
client.Send(Encoding.Unicode.GetBytes("OK"));
}
textBox1.Text += Environment.NewLine;
}
client.Disconnect(false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Close();
}
}
private void button2_Click(object sender, EventArgs e)
{
try
{
IPHostEntry host = Dns.GetHostByName(textBox6.Text);
adrr = host.AddressList[0];
EndPoint = new IPEndPoint(adrr, 35000);
button2.Enabled = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Close();
}
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
try
{
if (client != null) client.Disconnect(false);
}
catch { }
}
private void button3_Click(object sender, EventArgs e)
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
client.Connect(EndPoint);
byte[] k = new byte[10];
if (radioButton1.Checked)
{
byte[] ins = Encoding.Unicode.GetBytes("INSERT INTO Workman(Name, Surname, Telefon)" +
"VALUES('" +
textBox4.Text + "','" +
textBox5.Text + "','" +
textBox8.Text + "')");
client.Send(ins);
client.Receive(k);
}
else
{
byte[] upt = Encoding.Unicode.GetBytes("UPDATE Workman SET Name='" + textBox4.Text +
"', Surname='" + textBox5.Text +
"', Telefon ='" + textBox8.Text +
"' WHERE Surname='" + textBox3.Text + "'");
client.Send(upt);
client.Receive(k);
}
client.Disconnect(false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Close();
}
tabControl1.SelectTab(0);
checkBox1.Checked = false;
button1.PerformClick();
tabControl1.SelectTab(1);
}
private void button4_Click(object sender, EventArgs e)
{
client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
byte[] k = new byte[10];
client.Connect(EndPoint);
byte[] del = Encoding.Unicode.GetBytes("DELETE FROM Workman WHERE Surname='" + textBox7.Text + "'");
client.Send(del);
client.Receive(k);
client.Disconnect(false);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
Close();
}
tabControl1.SelectTab(0);
checkBox1.Checked = false;
button1.PerformClick();
tabControl1.SelectTab(2);
}
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
textBox3.Enabled = false;
}
private void radioButton2_CheckedChanged_1(object sender, EventArgs e)
{
textBox3.Enabled = true;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
if (textBox2.Enabled == false)
textBox2.Enabled = true;
else
textBox2.Enabled = false;
}
private void button5_Click(object sender, EventArgs e)
{
try
{
if (client != null) client.Disconnect(false);
}
catch { }
Close();
}
private void textBox3_TextChanged(object sender, EventArgs e)
{
}
}
}
//------------------------------------------------------------------------------------------------//
Протокол роботи програми
Висновок:
На цій лабораторній роботі я засвоїв основні стандартні класи і методи бібліотек System.Net, System.Net.Sockets; навчився створювати об’єкти клієнта та сервера, встановлювати між ними з’єднання і забезпечувати обмін повідомленнями між ними. Створивши програму, що реалізує клієнт-серверне з’єднання, я використав такі класи як TcpClient – для забезпечення роботи клієнта, який зв’язується із сервером; TcpListener – для забезпечення роботи сервера, який встановлюється на прослуховування певного порту для подальшого встановлення зв’язку з клієнтом; Socket – для забезпечення обміну повідомленнями між сервером та клієнтом. При цьому на сервері обмін повідомленнями з клієнтами реалізований у вигляді окремого потоку.