Практическая работа № 14 «Создание сетевого сервера и сетевого клиента»

Дисциплина «Разработка кода информационных систем»

Рассмотрим, как создать сервер, работающий по протоколу TCP, с помощью сокетов. Общая схема работы серверного сокета TCP будет следующей:

Сервер на сокетах TCP в C# и .NET

Код программы сервера будет таким:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace SocketTcpServer
{
class Program
{
static int port = 8005; // порт для приема входящих запросов
static void Main(string[] args)
{
// получаем адреса для запуска сокета
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(«127.0.0.1»), port);

        // создаем сокет
        Socket listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        try
        {
            // связываем сокет с локальной точкой, по которой будем принимать данные
            listenSocket.Bind(ipPoint);

            // начинаем прослушивание
            listenSocket.Listen(10);

            Console.WriteLine("Сервер запущен. Ожидание подключений...");

            while (true)
            {
                Socket handler = listenSocket.Accept();
                // получаем сообщение
                StringBuilder builder = new StringBuilder();
                int bytes = 0; // количество полученных байтов
                byte[] data = new byte[256]; // буфер для получаемых данных

                do
                {
                    bytes = handler.Receive(data);
                    builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
                }
                while (handler.Available>0);

                Console.WriteLine(DateTime.Now.ToShortTimeString() + ": " + builder.ToString());

                // отправляем ответ
                string message = "ваше сообщение доставлено";
                data = Encoding.Unicode.GetBytes(message);
                handler.Send(data);
                // закрываем сокет
                handler.Shutdown(SocketShutdown.Both);
                handler.Close();
            }
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
}

}

Вначале после создания сокета связываем его с локальной точкой методом Bind:

1listenSocket.Bind(ipPoint);

Сокет будет прослушивать подключения по 8005 порту на локальном адресе 127.0.0.1. То есть клиент должен будет подключаться к локальному адресу и порту 8005.

Далее начинаем прослушивание:

1listenSocket.Listen(10);

Метод Listen вызывается только после метода Bind. В качестве параметра он принимает количество входящих подключений, которые могут быть поставлены в очередь сокета.

После вызова метода Listen начинается прослушивание входящих подключений, и если подключения приходят на сокет, то их можно получить с помощью метода Accept:

1Socket handler = listenSocket.Accept();

Метод Accept извлекает из очереди ожидающих запрос первый запрос и создает для его обработки объект Socket. Если очередь запросов пуста, то метод Accept блокирует вызывающий поток до появления нового подключения.

Для обработки запроса сначала в цикле do..while получаем данные с помощью метода Receive:

123456do{bytes = handler.Receive(data);builder.Append(Encoding.Unicode.GetString(data, 0, bytes));}while (handler.Available > 0);

Метод Receive в качестве параметра принимает массив байтов, в который считываются полученные данные, и возвращает количество полученных байтов.

Если отсутствуют данные, доступные для чтения, метод Receive блокирует вызывающий поток до тех пор, пока не станут доступны данные, если не было установлено значение тайм-аута путем использования объекта Socket.ReceiveTimeout. Если значение тайм-аута было превышено, объект Receive выдаст исключение SocketException. Чтобы отследить наличие данных в потоке, используется свойство Available.

После получения данных клиенту посылается ответное сообщение с помощью метода Send, который в качестве параметра принимает массив байтов:

1handler.Send(data);

В конце обработки запроса надо закрыть связанный с ним сокет:

12handler.Shutdown(SocketShutdown.Both);handler.Close();

Вызов метода Shutdown() перед закрытием сокета гарантирует, что не останется никаких необработанных данных. Этот метод в качестве параметра принимает значение из перечисления SocketShutdown:

  • Both: остановка как отправки, так и получения данных сокетом
  • Receive: остановка получения данных
  • Send: остановка отправки данных

Клиент

Теперь добавим проект для клиента. Общая схема работы клиента на сокетах будет немного отличаться:

Клиент TCP на сокетах в C# и .NET

Полный код клиента:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace SocketTcpClient
{
class Program
{
// адрес и порт сервера, к которому будем подключаться
static int port = 8005; // порт сервера
static string address = «127.0.0.1»; // адрес сервера
static void Main(string[] args)
{
try
{
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(address), port);

            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // подключаемся к удаленному хосту
            socket.Connect(ipPoint);
            Console.Write("Введите сообщение:");
            string message = Console.ReadLine();
            byte[] data = Encoding.Unicode.GetBytes(message);
            socket.Send(data);

            // получаем ответ
            data = new byte[256]; // буфер для ответа
            StringBuilder builder = new StringBuilder();
            int bytes = 0; // количество полученных байт

            do
            {
                bytes = socket.Receive(data, data.Length, 0);
                builder.Append(Encoding.Unicode.GetString(data, 0, bytes));
            }
            while (socket.Available > 0);
            Console.WriteLine("ответ сервера: " + builder.ToString());

            // закрываем сокет
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }
        catch(Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
        Console.Read();
    }
}

}

Для клиента характерно все то же самое, только теперь после создания сокета вызывается метод Connect(), в который передается адрес сервера:

12IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(address), port);socket.Connect(ipPoint);

Теперь запустим программы сервера и клиента. Консоль клиента:

Введите сообщение: привет мир
ответ сервера: ваше сообщение доставлено

Консоль сервера:

Сервер запущен. Ожидание подключений...
22:34: привет мир

Оставить комментарий

avatar
  Подписаться  
Уведомление о