Клиент-серверное взаимодействие на основе протоколов TCP и HTTP в C#

Цель занятия

Познакомиться с возможностями взаимодействия приложений на C# через локальную сеть на основе протоколов TCP и HTTP. Изучить способы реализации клиента и сервера. Сравнить способы реализации клиент-серверного взаимодействия в Java и C#. Дополнительно см. [3, 10].

Краткие теоретические сведения

В этом занятии надлежит написать программу сервера и программу клиента и запустить их как раздельные приложения. Программа-клиент вызовет метод программы-сервера и получит

результат работы последней. Как и ранее, можно для запуска приложения клиента и приложения сервера использовать один и тот же компьютер, задав сетевой адрес 127.0.0.1. Можно запустить эти приложения на разных компьютерах. В этом случае следует использовать сетевое имя компьютера сервера для указания его в клиентском приложении. Это имя можно получить через Мой компьютер | Свойства | Сетевая идентификация.

Сначала приведем и подробно разберем текст программысервера (листинг4.12). Это приложение реализует взаимодействие на основе протокола TCP.

Листинг 4.12. Приложение сервера

using System; using System.IO; using Sysem.Net.Sockets; namespace Server

public class ServerExample

private void Listen() // Это единственный метод сервера,

// который мы используем

IPAddress ipAddress =

Dns.Resolve("localhost").AddressList[0];

TcpListener tcpl = new TcpListener(50001); // Создаем

// прослушиватель // порта 50001

tcpl.Start(); // Запускаемпрослушиватель,

// ожидание подключение клиента Socket newSocket = tcpl.AcceptSocket(); // Прослушиватель // ожидает подключения клиента

if (newSocket.Connected) // Если соединение установлено, то // пересылаем данные клиенту

NetworkStream ns= new NetworkStream(newSocket);

// Пересылка данных

byte [] buf={(byte) ‘ S’, (byte) ‘0’, (byte) ‘ ‘, (byte) ‘M’, (byte)

‘U’, (byte) ‘S’, (byte) ‘ ‘, (byte) ‘T’, (byte) ‘ ‘,

(byte) ‘B’,

(byte) ‘E’, (byte) ‘ ‘, (byte) ‘I’, (byte) ‘ ‘, (byte)

‘S’, (byte)

‘A’, (byte) ‘Y’,};

ns.Write(buf,0,3); // Отправляем данные клиенту

// Очистка

ns.Flush();

ns.Close();

break;

}

}

static void Main()

{

//

// TODO: Add code to start application here ServerExample se=new ServerExample(); se.Listen();

}

}

}

Итак, чтобы сервер возвратил строку "so мизт вв i SAY", необходимо подключение к нему клиента через порт 50001. Номер порта можно использовать и другой. Мы видим, что механизм сервера весьма прост и во многом напоминает тот, который использует классический Java. Прослушивание сокета реализуется командой

Socket newSocket = tcpl.AcceptSocket();

Эта команда "зависает" до тех пор, пока клиент не соединится с сервером. Если соединение успешно, то срабатывает оператор if и осуществляется вывод строки на сторону клинета:

if (newSocket.Connected) // Если соединение установлено,

// то пересылаем данные клиенту

NetworkStream ns= new NetworkStream(newSocket); //пересылка данных

byte [] buf={(byte) ‘     S’, (byte)   ‘0’, (byte) ‘  ‘,

(byte) ‘M’,

(byte) ‘U’, (byte) ‘S’, (byte) ‘       ‘, (byte) ‘T’, (byte)

‘ ‘, (byte)

‘B’, (byte) ‘E’, (byte) ‘  ‘, (byte) ‘I’, (byte) ‘   ‘,

(byte) ‘S’,

(byte) ‘A’, (byte) ‘Y’,};

ns.Write(buf,0,3); //отправляем данные клиенту

Обратим внимание на то, что клиенту передается массив байтов. Байты получаются из объектов типа char путем явного преобразования типа.

Нужно теперь скомпилировать текст сервера таким образом: Пуск | Программы | Visual Studio Net 2003 | Command Prompt и

ввести команду компиляции:

csc server.cs

Теперь нужно создать новый проект — приложение клиента. Клиент должен знать сетевой адрес сервера и номер порта. Вот его текст (листинг 4.13).

Листинг 4.13. Приложение клиента

using System; using System.IO; using Sysem.Net.Sockets; class clientexample

public static void Main()

TcpClient newSocket=

new TcpClient("localhost",50001); // Создаем объект типа

// TcpClient // для связи с сервером

NetworkStream ns= newSocket.GetStream(); // ns — потоковая // переменная на базе сокета // Чтение массива байтов от сервера из входного потока: byte [] buf= new byte [20]; ns.Read(buf,0,10);

char [] buf2= new char[20]; // Теперь выполним

// преобразование байтов // в тип char:

for(int i=0; i<20;i++)

buf2[i]= (char) buf[i];

Console.WriteLine(buf2); // Выводим строку от сервера

// на консоль клиента

ns.Close(); newSocket.Close();

Скомпилируйте приложение клиента:

csc dientexample.es Вот собственно и все.

В результате компиляции приложений клиента и сервера строятся файлы с расширением exe.

Сначала из командной строки запустите программу-сервер (рис. 4.8), затем отдельно запустите клиента (рис. 4.9).

Рис. 4.8. Запуск приложения сервера

Рис. 4.9. Запуск приложения клиента

Убедитесь в правильности работы программы.

Имеется возможность связи клиента и сервера через протокол HTTP (этот протокол использует Internet Explorer). Рассмотрим, как осуществить такую связь. Отметим, что теперь нет необходимости указывать номер порта. Сервер реализуется как уцаленный объект, так что нам потребуется посредник между этим объектом и клиентом — так называемый интерфейс. В интерфейсе нужно объявить методы сервера, которые мы хотим сделать доступными из клиента. Вот пример очень простого интерфейса:

using System;

public interface ISimpleObject String ToUpper(String inString);

Мы видим, что единственным методом сервера является метод Toupper, который получает в качестве входного аргумента строку instring. Реализацию данного метода следует перенести в сервер. Вот, собственно, и само приложение сервера (листинг 4.14).

Листинг 4.14. Приложение сервера на основе протокола HTTP

using System;

using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; namespace Server

public class SimpleObject: MarshalByRefObject, ISimpleObject {

public String ToUpper(String inString)

{

return(inString.ToUpper());

}

class Example8_8 {

static void Main(string[] args)

{

//

// TODO: Add code to start application here HttpChannel channel = new HttpChannel(54321); ChannelServices.RegisterChannel(channel); RemotingConfiguration.RegisterWellKnownServiceType( typeof(SimpleObject),

"SOEndPoint", WellKnownObjectMode.Singleton);

Console.WriteLine("Press To Stop Server");

Console.ReadLine();

}

}

}

Этот сервер не совсем обычен. Обратим внимание на то, что в объявление класса сервера подключены уже созданный нами интерфейс и еще один интерфейс: MarshalByRefObject. Дальше следует реализация метода ToUpper(). Метод Main() сервера занимается созданием соединения с клиентом:

HttpChannel channel = new HttpChannel(54321); // Создаем канал // связи снова через порт!

ChannelServices.RegisterChannel(channel); // Регистрируем // канал в операционной системе

RemotingConfiguration.RegisterWellKnownServiceType( typeof(SimpleObject),

"SOEndPoint", WellKnownObjectMode.Singleton);

//определяем тип соединения "Simple Object End Point"

// и режим

// его работы Singleton (обслуживание одного клиента // одним удаленным объектом)

Наконец, рассмотрим сторону клиента (листинг 4.15).

Листинг 4.15. Приложение клиента на основе протокола HTTP

using System;

using System.Runtime.Remoting; using System.Runtime.Remoting.Channels; using System.Runtime.Remoting.Channels.Http; class client

public static void Main()

HttpChannel hl=new HttpChannel(0); ChannelServices.RegisterChannel(hl);

Object remoteOb=

RemotingServices.Connect(typeof(ISimpleObject), "http://localhost:54 321/SOEndPoint");

ISimpleObject so=remoteOb as ISimpleObject; Console.WriteLine(so.ToUpper("so must be I say"));

Клиент должен получить доступ к удаленному объекту сервера. Это делается с помощью команды:

RemotingServices.Connect(typeof(ISimpleObject),

"http://localhost:54 321/SOEndPoint");

Здесь использовано сетевое имя iocaihost и через двоеточие — номер порта. Сетевое имя уникально идентифицирует компьютер в сети. Команда:

ISimpleObject so=remoteOb as ISimpleObject;

создает у клиента экземпляр объекта сервера. Отметим при этом, что используется имя интерфейса, а имя класса сервера вовсе не задействуется. Ну и наконец, обращение к методу выполняется так:

Console.WriteLine(so.ToUpper("so must be I say"));

Не правда ли, весьма оригинальное взаимодействие двух распределенных приложений!

Задание

Напишите свои собственные приложения клиента и сервера, которые обмениваются:

□               текущим временем;

□               содержимым файла, имя которого передает серверу клиент.

Контрольные вопросы

1.             Объяснить программы из листингов 4.12 и 4.13.

2.             Как передать информацию от клиента серверу?

3.             Как вы понимаете работу удаленного объекта на сервере?

4.             В чем особенности клиент-серверного приложения на основе протокола HTTP?

Источник: Герман О. B., Герман Ю. О., Программирование на Java и C# для студента. — СПб.: БХВ-Петербург, 2005. — 512 c.: ил.

Вы можете следить за любыми ответами на эту запись через RSS 2.0 ленту. Вы можете оставить ответ, или trackback с вашего собственного сайта.

Оставьте отзыв

XHTML: Вы можете использовать следующие теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

 
Rambler's Top100