Программный код клиента, использующий для взаимодействия с сервером потоковый сокет, может выглядеть следующим образом:
// Настройка клиента, считывающего и отображающего информацию,
// получаемую от сервера
using System;
using System.Drawing;
using System.Collection;
using System.ComponentModel;
using System.Windows.Forms;
using System.Threading;
using System.Net.Sockets;
using System.IO;
// Соединение с сервером
public class Client: System.Windows.Forms.Form
{
TextBox inputTextBox, displayTextBox;
NetworkStream output;
BinaryWriter writer;
BinaryReader reader;
string message = "";
Thread readThread;
Container Components = null;
public Client() // Конструктор по умолчанию
{
InitializeComponent();
readThread = new ThreadStart(RunClient));
readThread.Start();
}
[STAThread]
static void Main() { Application.Run(new Client()); }
protected void Client_Closing(object sender, CancelEventArg e)
{ Environment.Exit(Environment.ExitCode); }
// отправляет введенный пользователем тест на сервер
protected void inputTextBox_KeyDown(object sender, KeyEventArg e)
{
if(e.keyCode == Keys.Enter)
{
Writer.Write("CLIENT>>> " + inputTextBox.Text);
displayTextBox.Text += "\r\nCLIENT>>> " + inputTextBox.Text;
inputTextBox.Clear();
}
}
// Соединение с сервером и отображение текста, сгенерированного сервером
public void RunClient()
{
TcpClient client;
|
|
displayTextBox.Text += "Попытка установить соединение\r\n";
// Создание сокета для отправки данных на сервер
// Шаг 1: Создание сокета и соединение с сервером
client = new TcpClient();
client.Connect("localhost", 5000);
// Шаг 2: Получение потока для работы с сокетом
Output = client.GetStream();
// Создание объектов для записи и считывания в потоке
writer = new BinaryWriter(output);
reader = new BinaryReader(output);
displayTextBox.Text += "\r\nПолучил потоки для ввода и вывода\r\n";
inputTextBox.readOnly = false;
do
{
// Шаг 3: Фаза обработки
message = reader.readString();
displayTextBox.Text += "\r\n" + message;
}
while(message!= "SERVER>>> TERMINATE");
displayTextBox.Text += "\r\nОтключение соединения.\r\n";
// Шаг 4: Закрытие соединения
writer.Close();
reader.Close();
output.Close();
client.Close();
Application.Exit();
}
}
Подобно объекту сервера, объект клиента создает в своем конструкторе поток для обработки всех входящих сообщений. Его метод RunClient () соединяется с объектом сервера, получает от него данные и отправляет и отправляет на сервер свою информацию (при нажатии пользователем на клавишу < ENTER >. На шаге 1, для установления соединения, создается объект типа TcpClient, а затем вызывается его метод Connect (). В данном случае первым аргументом этого метода является имя сервера " localhost ", означающее, что серверное приложение, размещено на той же самой машине, что и клиент. Имя localhost еще называют IP -адресом обратной связи и эквивалентно IP -адресу 127.0.0.1. Это значение направляет передачу данных на IP -адрес отправителя.
Вторым аргументом метода Connect () является номер порта сервера. Этот номер должен совпадать с номером порта, на котором сервер ожидает соединения от клиента.
Объект Client использует класс NetworkStream для передачи данных на сервер и для их получения с сервера. Клиент получает класс NetworkStream путем обращения к методу GetStream класса TcpClient (шаг 2). Цикл do/while повторяется до тех пор, пока не получит сообщения о прекращении соединения (" SERVER>>> TERMINATE "). Для получения с сервера текстового сообщения используется метод ReadString класса BinaryReader (шаг 3). После чего отображаются сообщения и закрываются объекты BinaryWriter, BinaryReader, NetworkStream и TcpClient (шаг 4).
|
|
Когда пользователь клиентского приложения вводит строку в текстовое поле и нажимает на клавишу < Enter >, то обработчик этого события inputTextBox_KeyDown считывает строку из текстового поля и отправляет ее серверу с помощью метода BinaryWriter.Write (). Следует отметить, что в данном случае объект сервера получает запрос на соединение, обрабатывает его, закрывает и ожидает следующего. В реальном приложении сервер получил бы запрос на соединение, установил его для обработки в виде отдельного потока и ожидал бы новых соединений. Отдельные потоки, обрабатывающие существующие соединения, могут продолжать свою работу, в то время как объект сервера ожидает новых запросов на соединение.