Tcp socket client windows

Сокеты Sockets

Сокеты — это технология передачи данных низкого уровня, на основе которой реализованы многие сетевые протоколы. Sockets are a low-level data transfer technology on top of which many networking protocols are implemented. UWP предоставляет классы сокетов TCP и UDP для клиент-серверных или одноранговых приложений, если устанавливаются долгосрочные подключения или установленное подключение не требуется. UWP offers TCP and UDP socket classes for client-server or peer-to-peer applications, whether connections are long-lived or an established connection is not required.

В этом разделе основное внимание уделяется использованию классов сокетов универсальной платформы Windows (UWP), которые находятся в пространстве имен Windows.Networking.Sockets. This topic focuses on how to use the Universal Windows Platform (UWP) socket classes that are in the Windows.Networking.Sockets namespace. Кроме того, сокеты Windows 2 (WinSock) можно использовать в приложении UWP. But you can also use Windows Sockets 2 (Winsock) in a UWP app.

Как последствие сетевой изоляции WIndows запрещает установку подключения сокета (Sockets или WinSock) между двумя приложениями UWP, работающими на одном компьютере, через локальный петлевой адрес (127.0.0.0) либо путем явного указания локального IP-адреса. As a consequence of network isolation, Windows disallows establishing a socket connection (Sockets or WinSock) between two UWP apps running on the same machine; whether that’s via the local loopback address (127.0.0.0), or by explicitly specifying the local IP address. Дополнительные сведения о механизмах, с помощью которых приложения UWP могут взаимодействовать друг с другом, см. в разделе Связь между приложениями. For details about mechanisms by which UWP apps can communicate with one another, see App-to-app communication.

Создание базового клиента и сервера сокета TCP Build a basic TCP socket client and server

Для постоянных подключений сокет протокола TCP обеспечивает в сети низкоуровневую двунаправленную передачу данных. A TCP (Transmission Control Protocol) socket provides low-level network data transfers in either direction for connections that are long-lived. Сокеты TCP широко используются большинством сетевых протоколов в Интернете. TCP sockets are the underlying feature used by most of the network protocols used on the Internet. Чтобы продемонстрировать базовые операции TCP, в следующем примере кода реализованы отправка и получение данных через TCP объектами StreamSocket и StreamSocketListener, на основе которых создаются эхо-клиент и сервер. To demonstrate basic TCP operations, the example code below shows a StreamSocket and a StreamSocketListener sending and receiving data over TCP to form an echo client and server.

Чтобы начать с минимального количества составляющих (и пока не затрагивать проблемы сетевой изоляции), создайте новый проект и поместите код клиента и код сервера (см. ниже) в один проект. To begin with as few moving parts as possible—and to sidestep network isolation issues for the present—create a new project, and put both the client and the server code below into the same project.

Потребуется объявить возможность приложения в своем проекте. You’ll need to declare an app capability in your project. Откройте исходный файл манифеста пакета приложения (файл Package.appxmanifest ) и на вкладке «Возможности» установите флажок Частные сети (клиент и сервер). Open your app package manifest source file (the Package.appxmanifest file) and, on the Capabilities tab, check Private Networks (Client & Server). Вот как это выглядит в разметке Package.appxmanifest . This is how that looks in the Package.appxmanifest markup.

Вместо privateNetworkClientServer можно объявить internetClientServer , если подключение осуществляется по Интернету. Instead of privateNetworkClientServer , you can declare internetClientServer if you’re connecting over the internet. И StreamSocket, и StreamSocketListener требуют, чтобы была объявлена одна из этих возможностей приложения. Both StreamSocket and StreamSocketListener need one or other of these app capabilities to be declared.

Эхо-клиент и сервер на основе сокетов TCP An echo client and server, using TCP sockets

Создайте StreamSocketListener и начните слушать входящие подключения TCP. Construct a StreamSocketListener and begin listening for incoming TCP connections. Событие StreamSocketListener.ConnectionReceived создается всякий раз, когда клиент устанавливает подключение к прослушивателю StreamSocketListener. The StreamSocketListener.ConnectionReceived event is raised each time a client establishes a connection with the StreamSocketListener.

Кроме того, создайте сокет StreamSocket, установите подключение к серверу, отправьте запрос и получите ответ. Also construct a StreamSocket, establish a connection to the server, send a request, and receive a response.

Создайте новый объект Страница с именем StreamSocketAndListenerPage . Create a new Page named StreamSocketAndListenerPage . Поместите разметку XAML в StreamSocketAndListenerPage.xaml , а затем поместите императивный код внутрь класса StreamSocketAndListenerPage . Put the XAML markup in StreamSocketAndListenerPage.xaml , and the put the imperative code inside the StreamSocketAndListenerPage class.

Читайте также:  Установка модема irz mc52it windows 10

Ссылки на StreamSockets в продолжениях C++ PPL (в первую очередь применимо к C++/CX) References to StreamSockets in C++ PPL continuations (applies to C++/CX, primarily)

Это неприменимо в случае использования сопрограмм C++/WinRT и передачи параметров по значению. If you use C++/WinRT coroutines, and you pass parameters by value, then this issue doesn’t apply. Рекомендации по передаче параметров см. в разделе Параллельная обработка и асинхронные операции с помощью C++/WinRT. For parameter-passing recommendations, see Concurrency and asynchronous operations with C++/WinRT.

StreamSocket остается активным, пока в его потоке ввода/вывода выполняются активные операции чтения/записи (рассмотрим для примера StreamSocketListenerConnectionReceivedEventArgs.Socket, доступ к которому осуществляется в обработчике событий StreamSocketListener.ConnectionReceived). A StreamSocket remains alive as long as there’s an active read/write on its input/output stream (let’s take for example the StreamSocketListenerConnectionReceivedEventArgs.Socket that you have access to in your StreamSocketListener.ConnectionReceived event handler). При вызове DataReader.LoadAsync (или ReadAsync/WriteAsync/StoreAsync ) он хранит ссылку на сокет (через поток ввода сокета) до тех пор, пока обработчик событий Completed (при наличии) метода LoadAsync не завершит выполнение. When you call DataReader.LoadAsync (or ReadAsync/WriteAsync/StoreAsync ), then that holds a reference to the socket (via the socket’s input stream) until the Completed event handler (if any) of the LoadAsync is done executing.

Библиотека параллельных шаблонов (PPL) не планирует встроенное продолжение задач по умолчанию. The Parallel Patterns Library (PPL) doesn’t schedule task continuations inline by default. Другими словами, добавление задачи продолжения (с task::then() ) не гарантирует, что задача продолжения будет выполняться во встроенном режиме в качестве завершающего обработчика. In other words, adding a continuation task (with task::then() ) doesn’t guarantee that the continuation task will execute inline as the completion handler.

С точки зрения StreamSocket завершающий обработчик завершит выполнение (и сокет станет готовым к ликвидации) до запуска основной части продолжения. From the perspective of the StreamSocket, the completion handler is done executing (and the socket is eligible for disposal) before the continuation body runs. Таким образом, чтобы предотвратить удаление сокета, если вы хотите использовать его в этом продолжении, необходимо ссылаться на сокет напрямую (через захват лямбда-функции) и использовать его, или косвенно (продолжая осуществлять доступ к args->Socket внутри продолжения), или обеспечить принудительное выполнение задач продолжения в коде. So, to keep your socket from being disposed if you want to use it inside that continuation, you need to either reference the socket directly (via lambda capture) and use it, or indirectly (by continuing to access args->Socket inside continuations), or force continuation tasks to be inline. Эту первую технику можно наблюдать в действии (захват лямбда-функции) в примере StreamSocket. You can see the first technique (lambda capture) in action in the StreamSocket sample. Код C++/CX в разделе Создание базового клиента и сервера TCP-сокета выше использует второй способ. Он возвращает запрос в качестве ответа и осуществляет доступ к args->Socket из одного из продолжений самого глубокого уровня. The C++/CX code in the Build a basic TCP socket client and server section above uses the second technique—it echoes the request back as a response, and it accesses args->Socket from within one of the innermost continuations.

Третий способ подходит в тех случаях, когда не нужно выводить ответ. The third technique is appropriate when you’re not echoing a response back. Параметр task_continuation_context::use_synchronous_execution() используется для принудительного выполнения основной части продолжения внутри PPL. You use the task_continuation_context::use_synchronous_execution() option to force PPL to execute the continuation body inline. Этот пример кода демонстрирует, как это сделать. Here’s a code example showing how to do it.

Это поведение применяется ко всем сокетам и классам WebSockets в пространстве имен Windows.Networking.Sockets. This behavior applies to all of the sockets and WebSockets classes in the Windows.Networking.Sockets namespace. Но для сценариев на стороне клиента сокеты обычно сохраняются в переменных-членах, так что эта проблема наиболее применима для сценария StreamSocketListener.ConnectionReceived, как описано выше. But client-side scenarios usually store sockets in member variables, so the issue is most applicable to the StreamSocketListener.ConnectionReceived scenario, as illustrated above.

Создание простейших клиента и сервера для UDP-сокетов Build a basic UDP socket client and server

Сокет протокола UDP схож с сокетом TCP в том плане, что он обеспечивает низкоуровневую передачу данных по сети в любом направлении. A UDP (User Datagram Protocol) socket is similar to a TCP socket in that it also provides low-level network data transfers in either direction. Однако если сокет TCP подходит для постоянных подключений, сокет UDP подходит для сценариев, где установленное подключение не требуется. But, while a TCP socket is for long-lived connections, a UDP socket is for applications where an established connection is not required. Поскольку сокеты UDP не поддерживают соединение на обеих конечных точках, они предоставляют быстрый и простой способ сетевого подключения между удаленными компьютерами. Because UDP sockets don’t maintain connection on both endpoints, they’re a fast and simple solution for networking between remote machines. Однако сокеты UDP не гарантируют целостность сетевых пакетов и даже их передачу удаленному адресату. But UDP sockets don’t ensure integrity of the network packets nor even whether packets make it to the remote destination at all. Поэтому необходимо учитывать это в приложении. So your app will need to be designed to tolerate that. Примеры приложений, использующих сокеты UDP: локальные клиенты обнаружения сети и локальные клиенты чатов. Some examples of applications that use UDP sockets are local network discovery, and local chat clients.

Читайте также:  Перезапустить службу rdp windows 10 cmd

Чтобы продемонстрировать базовые операции UDP, пример кода ниже показывает класс DatagramSocket, который используется для отправки и получения данных через UDP с целью формирования эхо-клиента и сервера. To demonstrate basic UDP operations, the example code below shows the DatagramSocket class being used to both send and receive data over UDP to form an echo client and server. Создайте новый проект и поместите представленный ниже код клиента и сервера в один проект. Create a new project, and put both the client and the server code below into the same project. Как и в случае с сокетом TCP, необходимо объявить возможность приложения Частные сети (клиент и сервер). Just as for a TCP socket, you’ll need to declare the Private Networks (Client & Server) app capability.

Создание эхо-клиента и эко-сервера с использованием сокетов UDP An echo client and server, using UDP sockets

Создайте сокет DatagramSocket, который будет выполнять роль эхо-сервера, привяжите его к определенному номеру порта, получите входящее сообщение UDP и передайте его обратно. Construct a DatagramSocket to play the role of the echo server, bind it to a specific port number, listen for an incoming UDP message, and echo it back. Событие DatagramSocket.MessageReceived создается, когда сокет получает сообщение. The DatagramSocket.MessageReceived event is raised when a message is receieved on the socket.

Создайте другой сокет DatagramSocket, который будет выполнять роль эхо-клиента, привяжите его к определенному номеру порта, отправьте сообщение UDP и получите ответ. Construct another DatagramSocket to play the role of the echo client, bind it to a specific port number, send a UDP message, and receive a response.

Создайте новый объект Страница с именем DatagramSocketPage . Create a new Page named DatagramSocketPage . Поместите разметку XAML в DatagramSocketPage.xaml , а затем поместите императивный код внутрь класса DatagramSocketPage . Put the XAML markup in DatagramSocketPage.xaml , and the put the imperative code inside the DatagramSocketPage class.

Фоновые операции и брокер сокета Background operations and the socket broker

Можно использовать посредник сокетов и контролировать триггеры канала, чтобы убедиться, что приложение должным образом получает подключения или данные в сокетах, не находясь на переднем плане. You can use the socket broker, and control channel triggers, to ensure that your app properly receives connections or data on sockets while it’s not in the foreground. Дополнительные сведения см. в статье о сетевом взаимодействии в фоновом режиме. For more info, see Network communications in the background.

Пакетные отправки Batched sends

Каждый раз, когда вы выполняется запись в поток, связанный с сокетом, происходит переход из режима пользователя (обычный код) в режим ядра (где работает сетевой стек). Whenever you write to the stream associated with a socket, a transition happens from user mode (your code) to kernel mode (where the network stack is). Если записывается много буферов одновременно, повторяющиеся переходы создают значительную нагрузку. If you’re writing many buffers at a time then these repeated transitions compound into substantial overhead. Чтобы отправлять несколько буферов данных одновременно, избегая такой нагрузки, можно собирать отправляемые данные в пакеты. Batching your sends is a way to send multiple buffers of data together, and avoid that overhead. Это особенно полезно, если ваше приложение поддерживает VoIP, VPN или другие задачи, предполагающие максимально эффективное перемещение больших объемов данных. It’s especially useful if your app is doing VoIP, VPN, or other tasks that involve moving a lot of data as efficiently as possible.

В этом разделе показано несколько техник пакетных отправок, которые можно использовать с сокетом StreamSocket или подключенным сокетом DatagramSocket. This section demonstrates a couple of batched sends techniques that you can use with a StreamSocket or a connected DatagramSocket.

Чтобы получить общее представление о процессе, рассмотрим, как эффективно отправить большое число буферов. To get a baseline, let’s see how to send a large number of buffers in an inefficient way. Вот минимальная демонстрация, в которой используется StreamSocket. Here’s a minimal demo, using a StreamSocket.

Первый пример использует более эффективную технику, но подходит только для C#. This first example of a more efficient technique is only appropriate if you’re using C#. Измените OnNavigatedTo , чтобы вызвать BatchedSendsCSharpOnly вместо SendMultipleBuffersInefficiently или SendMultipleBuffersInefficientlyAsync . Change OnNavigatedTo to call BatchedSendsCSharpOnly instead of SendMultipleBuffersInefficiently or SendMultipleBuffersInefficientlyAsync .

Следующий пример подходит для любого языка UWP, а не только для C#. This next example is appropriate for any UWP language, not just for C#. В его основе — поведение потоков StreamSocket.OutputStream и DatagramSocket.OutputStream, объединяющих отправки. It relies on the behavior in StreamSocket.OutputStream and DatagramSocket.OutputStream that batches sends together. Эта техника вызывает метод FlushAsync в потоке вывода, который начиная с Windows 10 гарантированно возвращается только после того, как все операции потока вывода завершены. The technique calls FlushAsync on that output stream which, as of Windows 10, is guaranteed to return only after all operations on the output stream have completed.

Существуют некоторые важные ограничения, связанные с использованием пакетных отправок в вашем коде. There are some important limitations imposed by using batched sends in your code.

  • Вы не можете изменять содержимое экземпляров IBuffer, записанных до завершения асинхронной записи. You cannot modify the contents of the IBuffer instances being written until the asynchronous write is complete.
  • Шаблон FlushAsync работает только с StreamSocket.OutputStream и DatagramSocket.OutputStream. The FlushAsync pattern only works on StreamSocket.OutputStream and DatagramSocket.OutputStream.
  • Шаблон FlushAsync работает только в Windows 10 и более поздних версиях. The FlushAsync pattern only works in Windows 10 and onward.
  • В других случаях следует использовать Task.WaitAll вместо шаблона FlushAsync. In other cases, use Task.WaitAll instead of the FlushAsync pattern.
Читайте также:  Как смонтировать образ windows с alcohol

Совместное использование порта для DatagramSocket Port sharing for DatagramSocket

Можно настроить сокет DatagramSocket для совместного существования с другими многоадресными сокетами Win32 или UWP, связанными с тем же адресом/портом. You can configure a DatagramSocket to coexist with other Win32 or UWP multicast sockets bound to the same address/port. Для этого необходимо задать для DatagramSocketControl.MulticastOnly значение true , прежде чем привязывать или подключать сокет. You do this by setting the DatagramSocketControl.MulticastOnly to true before binding or connecting the socket. Доступ к экземпляру DatagramSocketControl осуществляется из объекта DatagramSocket через свойство DatagramSocket.Control. You access an instance of DatagramSocketControl from the DatagramSocket object itself via its DatagramSocket.Control property.

Предоставление сертификата клиента с классом StreamSocket Providing a client certificate with the StreamSocket class

Класс StreamSocket поддерживает возможность использования протокола SSL/TLS для проверки подлинности сервера, к которому обращается клиентское приложение. StreamSocket supports using SSL/TLS to authenticate the server that the client app is talking to. В некоторых случаях клиентское приложение также должно пройти проверку подлинности на сервере с помощью сертификата клиента SSL/TLS. In some cases, the client app needs to authenticate itself to the server using an SSL/TLS client certificate. Можно предоставить клиентский сертификат со свойством StreamSocketControl.ClientCertificate, прежде чем привязывать или подключать сокет (его необходимо задать до начала подтверждения протокола SSL/TLS). You can provide a client certificate with the StreamSocketControl.ClientCertificate property before binding or connecting the socket (it must be set before the SSL/TLS handshake is started). Доступ к экземпляру StreamSocketControl осуществляется из объекта StreamSocket через свойство StreamSocket.Control. You access an instance of StreamSocketControl from the StreamSocket object itself via its StreamSocket.Control property. Если сервер запрашивает сертификат клиента, Windows ответит, воспользовавшись предоставленным клиентским сертификатом. If the server requests the client certificate then Windows will respond with the client certificate that you provided.

Используйте переопределение метода StreamSocket.ConnectAsync, которое принимает значение SocketProtectionLevel, как показано в примере минимального кода. Use an override of StreamSocket.ConnectAsync that takes a SocketProtectionLevel, as shown in this minimal code example.

Как указано в комментарии в примерах кода ниже, чтобы код работал, в проекте должна быть объявлена возможность приложения sharedUserCertificates. As indicated by the comment in the code examples below, your project needs to declare the sharedUserCertificates app capability for this code to work.

Обработка исключений Handling exceptions

Ошибка, обнаруженная в операции DatagramSocket, StreamSocket или StreamSocketListener, возвращается в виде значения HRESULT. An error encountered on a DatagramSocket, StreamSocket, or StreamSocketListener operation is returned as an HRESULT value. Можно передать значение HRESULT методу SocketError.GetStatus, чтобы преобразовать его в значение перечисления SocketErrorStatus. You can pass that HRESULT value to the SocketError.GetStatus method to convert it into a SocketErrorStatus enumeration value.

Большинство значений перечисления SocketErrorStatus соответствуют ошибке, возвращаемой стандартной операцией с сокетами Windows. Most SocketErrorStatus enumeration values correspond to an error returned by the native Windows sockets operation. Ваше приложение может включать значения перечисления SocketErrorStatus, чтобы по-разному действовать в зависимости от причины исключения. Your app can switch on SocketErrorStatus enumeration values to modify app behavior depending on the cause of the exception.

Для ошибок при проверке параметров можно использовать также значение HRESULT из исключения, чтобы получить подробные сведения об ошибке. For parameter validation errors, you can use the HRESULT from the exception to learn more detailed information about the error. Возможные значения HRESULT перечислены в Winerror.h , который находится в вашей установке SDK (например, в папке C:\Program Files (x86)\Windows Kits\10\Include\ \shared ). Possible HRESULT values are listed in Winerror.h , which can be found in your SDK installation (for example, in the folder C:\Program Files (x86)\Windows Kits\10\Include\ \shared ). Для многих ошибок при проверке параметров HRESULT возвращает значение E_INVALIDARG. For most parameter validation errors, the HRESULT returned is E_INVALIDARG.

Конструктор HostName может создать исключение, если переданная строка не является допустимым именем узла. The HostName constructor can throw an exception if the string passed is not a valid host name. Например, он содержит недопустимые символы, что вероятно, если имя узла вводится в приложении пользователем. For example, it contains characters that are not allowed, which is likely if the host name is typed in to your app by the user. Создайте HostName внутри блока try/catch. Construct a HostName inside a try/catch block. В этом случае приложение может сообщить пользователю об ошибке и запросить новое имя узла. That way, if an exception is thrown, the app can notify the user and request a new host name.

Оцените статью