Сетевое программирование в .NET Работа с сокетами Сокеты Сокет - это один конец двустороннегo канала связи между двумя прогpаммами, работающими в сети. Соединяя вместе два сокета, можно передавать данные между разными процессами (локальными или удаленными). Реализация сокетов обеспечивает инкапсуляцию протоколов ceтeвoгo и транспортного уровней. Существуют два основных типа сокетов потоковые сокеты и дейтаграммные. Потоковый сокет это сокет с установленным соединением, состоящий из потока байтов, который может быть двунаправленным. т. е. через эту конечную точку приложение может и передавать, и получать данные. Потоковый сокет гaрантирует исправление ошибок, обрабатывает доставку и сохраняет последовательность дaнных. На нeгo можно положиться в доставке упорядоченных, недублированных дaнных. Потоки базируются на явных соединениях: сокет А запрашивает соединение с сокетом В, а сокет В либо соrлашается с запросом на установление соединения, либо отверraет ero. - Порты Порт определен, чтобы разрешить задачу одновременноrо взаимодействия с несколькими приложениями. По существу, с ero помощью расширяется понятие IP aдреса. Компьютер, на котором в одно время выполняется несколько приложений, получая пакет из сети, может идентифицировать целевой процесс. пользуясь уникальным номером порта. определенным при установлении соединения. Порты Сокет состоит из IP aдpeca машины и номера порта, используемоrо приложением ТСР. Поскольку IP-aдpec уникален в Интернете, а номера портов уникальны на отдельной машине, номера сокетов также уникальны во всем Интернете. Эта характеристика позволяет процессу общаться через сеть с дрyrим процессом исключительно на основании номера сокета. За определенными службами номера портов зарезервированы (80, 3306, 8080 и т.п.) Работа с сокетами в .NET MulticastOption устанавливает значение IP aдpeca для присоединения к IР-rруппе или для выхода из нее. TcpClient строится на классе Socket, чтобы обеспечить ТСР обслуживание на более высоком уровне. TcpClient предоставляет несколько методов для отправки и получения данных через сеть. TcpListener также построен на низкоуровневом классе Socket. Ero основное назначение - серверные приложения. Он ожидает входящие запросы на соединения от клиентов и уведомляет приложение о любых соединениях. NetworkStream реализует базовый класс потока, из котоporo данные отправляются и в котором они получаются. Это абстракция высокого уровня, представляющая соединение с каналом связи TCP/IP. Работа с сокетами в .NET UdpClient UDP - это протокол, не орrанизующий соединение, следовательно, для реализации UDР-обслуживания в .NEТ требуется друrая функциональность. Класс UdpClient предназначен для реализации UDР обслуживания. Socket Exception Socket это исключение порождается, коrда в сокете возникает ошибка. обеспечивает базовую функциональность приложения сокета. Класс System.Net.Sockets.Socket Свойство AddressFamlly Available Blocking Connected LocalEndPoint ProtocolType RemoteEndPoint SocketType Описание Дает семейство адресов сокета - значение из перечисления Socket.AddressFamily. Возвращает объем доступных для чтения данных. Дает или устанавливает значение, показывающее, находится ли сокет в блокирующем режиме. Возвращает значение, информирующее, соединен ли сокет с удаленным хостом. Дает локальную конечную точку Дает тип протокола сокета. Дает удаленную конечную точку сокета. Дает тип сокета Класс System.Net.Sockets.Socket Метод Accept() Bind() Close() Connect() Listen() Receive() Poll() Send() ShutDown() Описание Создает новый сокет для обработки входящего запроса на соединение Связывает сокет с локальной конечной точкой для ожидания входящих запросов на соединение Закрывает сокет Устанавливает соединение с удаленным хостом Помещает сокет в режим прослушивания Получает данные от соединенного сокета Определяет статус сокета Отправляет данные соединенному сокету Запрещает операции отправки и получения данных на сокете Создание сервера Не забудем подключить System.Net.Sockets и System.Net // создаем конечную точку подключения IPHostEntry ipHost = Dns.GetHostEntry("localhost"); IPAddress ipAddr = ipHost.AddressList[0]; IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000); // создаем сокет Socket sListener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // и связываем его с точкой подключения sListener.Bind(ipEndPoint); Создание сервера sListener.Listen(10); // запускаем прослушивание while(true) { Console.WriteLine("start"); Socket handler = sListener.Accept(); string data = null; // подключился клиент byte [] bytes = new byte[1024]; int bytesRec = handler.Receive(bytes); // принимаем от него сообщение data= Encoding.ASCII.GetString(bytes, 0, bytesRec); Console.WriteLine(data); string theReply = "thanks!"; byte[] msg= Encoding.ASCII.GetBytes(theReply); handler.Send(msg); // и отправляем ответ handler.Shutdown(SocketShutdown.Both); // завершаем сеанс handler.Close(); } Создание клиента byte [] bytes = new byte[1024]; // таким же образом создаем конечную точку подключения IPHostEntry ipHost = Dns.GetHostEntry("127.0.0.1"); IPAddress ipAddr = ipHost.AddressList[0]; IPEndPoint ipEndPoint = new IPEndPoint(ipAddr, 11000); // создаем сокет Socket sender = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); // устанавливаем соединение sender.Connect(ipEndPoint); Создание клиента // отправляем сообщение string message = "Hello!"; int bytesSend = sender.Send(Encoding.ASCII.GetBytes(message)); // получаем ответ от сервера int bytesRec = sender.Receive(bytes); Console.WriteLine("Server:"+Encoding.ASCII.GetString(bytes, 0, bytesRec)); // завершаем работу sender.Shutdown(SocketShutdown.Both); sender.Close(); Не забудьте в приложениях обработать исключения! Классы TcpListener и TcpClient В отличие от класса Socket, в котором для отправки и получения данных применяется побайтовый подход, классы TcpClient и TcpListener придерживаются потоковой модели. В этих классах все взаимодействие между клиентом и сервером базируется на потоке с использованием класса NetworkStream. Однако при необходимости можно работать и с байтами. Класс TcpListener // Создать объект класса TcpListener и запустить // его на прослушивание порта 65125 IPHostEntry ipHost = Dns.GetHostEntry("127.0.0.1"); IPAddress ipAddr = ipHost.AddressList[0]; TcpListener tcpListener = new TcpListener(ipAddr,65125); tcpListener.Start(); Console.WriteLine("Start of listening"); while( true ) { // Ожидание запроса приемника // По запросу приемника установить соединение и возвратить новый // объект класса сокета, который используется для установки связи с // приемником; тем временем tcpListener продолжает прослушивание Socket clientSocket = tcpListener.AcceptSocket(); Класс TcpListener // теперь можно создать сетевой поток данных и // объект для работы с ним – например, бинарный поток NetworkStream netStream = new NetworkStream(clientSocket); BinaryWriter binWriter = new BinaryWriter(netStream); ... // в конце работы с клиентом не забудем закрыть сокет: clientSocket.Close(); Класс TcpClient // создать объект TcpClient для работы с сервером TcpClient serverSocket; serverSocket = new TcpClient("localhost", 65125); // создать сетевой поток данных и объект для чтения из него NetworkStream netStream = serverSocket.GetStream(); BinaryReader binReader = new BinaryReader(netStream); Не забывайте в приложениях обработать исключения! Задание Создайте простые приложения клиент и сервер на основе классов TcpListener и TcpClient. Пусть, например, клиент отправляет сообщение, сервер его принимает и в ответ тоже отправляет сообщение, и на этом сеанс клиента завершается.