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

Код программы сервера будет таким:
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:
| 1 | listenSocket.Bind(ipPoint); |
Сокет будет прослушивать подключения по 8005 порту на локальном адресе 127.0.0.1. То есть клиент должен будет подключаться к локальному адресу и порту 8005.
Далее начинаем прослушивание:
| 1 | listenSocket.Listen(10); |
Метод Listen вызывается только после метода Bind. В качестве параметра он принимает количество входящих подключений, которые могут быть поставлены в очередь сокета.
После вызова метода Listen начинается прослушивание входящих подключений, и если подключения приходят на сокет, то их можно получить с помощью метода Accept:
| 1 | Socket handler = listenSocket.Accept(); |
Метод Accept извлекает из очереди ожидающих запрос первый запрос и создает для его обработки объект Socket. Если очередь запросов пуста, то метод Accept блокирует вызывающий поток до появления нового подключения.
Для обработки запроса сначала в цикле do..while получаем данные с помощью метода Receive:
| 123456 | do{bytes = handler.Receive(data);builder.Append(Encoding.Unicode.GetString(data, 0, bytes));}while (handler.Available > 0); |
Метод Receive в качестве параметра принимает массив байтов, в который считываются полученные данные, и возвращает количество полученных байтов.
Если отсутствуют данные, доступные для чтения, метод Receive блокирует вызывающий поток до тех пор, пока не станут доступны данные, если не было установлено значение тайм-аута путем использования объекта Socket.ReceiveTimeout. Если значение тайм-аута было превышено, объект Receive выдаст исключение SocketException. Чтобы отследить наличие данных в потоке, используется свойство Available.
После получения данных клиенту посылается ответное сообщение с помощью метода Send, который в качестве параметра принимает массив байтов:
| 1 | handler.Send(data); |
В конце обработки запроса надо закрыть связанный с ним сокет:
| 12 | handler.Shutdown(SocketShutdown.Both);handler.Close(); |
Вызов метода Shutdown() перед закрытием сокета гарантирует, что не останется никаких необработанных данных. Этот метод в качестве параметра принимает значение из перечисления SocketShutdown:
Both: остановка как отправки, так и получения данных сокетомReceive: остановка получения данныхSend: остановка отправки данных
Клиент
Теперь добавим проект для клиента. Общая схема работы клиента на сокетах будет немного отличаться:

Полный код клиента:
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(), в который передается адрес сервера:
| 12 | IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse(address), port);socket.Connect(ipPoint); |
Теперь запустим программы сервера и клиента. Консоль клиента:
Введите сообщение: привет мир ответ сервера: ваше сообщение доставлено
Консоль сервера:
Сервер запущен. Ожидание подключений... 22:34: привет мир

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