使用异步服务器套接字编程指南(微软MSDN)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 异步服务器套接字使用 .NET Framework 异步编程模型处理网络服务请求。Socket 类遵循标准 .NET Framework 异步命名模式;例如,同步 Accept 方法对应异步 BeginAccept 和 EndAccept 方法。
异步服务器套接字使用 .NET Framework 异步编程模型处理网络服务请求。Socket 类遵循标准 .NET Framework 异步命名模式;例如,同步 Accept 方法对应异步 BeginAccept 和 EndAccept 方法。
异步服务器套接字需要一个开始接受网络连接请求的方法,一个处理连接请求并开始接收网络数据的回调方法以及一个结束接收数据的回调方法。本节将进一步讨论所有这些方法。

在下面的示例中,为开始接受网络连接请求,方法 StartListening 初始化 Socket,然后使用 BeginAccept 方法开始接受新连接。当套接字上接收到新连接请求时,将调用接受回调方法。它负责获取将处理连接的 Socket 实例,并将 Socket 提交给将处理请求的线程。接受回调方法实现 AsyncCallback 委托;它返回 void,并带一个 IAsyncResult 类型的参数。下面的示例是接受回调方法的外壳程序。

[Visual Basic]

Sub acceptCallback(ar As IAsyncResult)
    ' Add the callback code here.
End Sub 'acceptCallback

[C#]

void acceptCallback( IAsyncResult ar) {
    // Add the callback code here.
}

BeginAccept 方法带两个参数:指向接受回调方法的 AsyncCallback 委托和一个用于将状态信息传递给回调方法的对象。在下面的示例中,侦听 Socket 通过状态参数传递给回调方法。本示例创建一个 AsyncCallback 委托并开始接受网络连接。

[Visual Basic]

listener.BeginAccept( _
    New AsyncCallback(SocketListener.acceptCallback),_
    listener)

[C#]

listener.BeginAccept(
    new AsyncCallback(SocketListener.acceptCallback), 
    listener);

异步套接字使用系统线程池中的线程处理传入的连接。一个线程负责接受连接,另一线程用于处理每个传入的连接,还有一个线程负责接收连接数据。这些线程可以是同一个线程,具体取决于线程池所分配的线程。在下面的示例中,System.Threading.ManualResetEvent 类挂起主线程的执行并在执行可以继续时发出信号。

下面的示例显示在本地计算机上创建异步 TCP/IP 套接字并开始接受连接的异步方法。它假定以下内容:存在一个名为 allDone 的全局 ManualResetEvent,该方法是一个名为 SocketListener 的类的成员,以及定义了一个名为 acceptCallback 的回调方法。

[Visual Basic]

Public Sub StartListening()
    Dim ipHostInfo As IPHostEntry = Dns.Resolve(Dns.GetHostName())
    Dim localEP = New IPEndPoint(ipHostInfo.AddressList(0), 11000)
    
    Console.WriteLine("Local address and port : {0}", localEP.ToString())
    
    Dim listener As New Socket(localEP.Address.AddressFamily, _
       SocketType.Stream, ProtocolType.Tcp)
    
    Try
        listener.Bind(localEP)
        s.Listen(10)
        
        While True
            allDone.Reset()
            
            Console.WriteLine("Waiting for a connection...")
            listener.BeginAccept(New _
                AsyncCallback(SocketListener.acceptCallback), _
                listener)
            
            allDone.WaitOne()
        End While
    Catch e As Exception
        Console.WriteLine(e.ToString())
    End Try
    Console.WriteLine("Closing the listener...")
End Sub 'StartListening


[C#]

public void StartListening() {
    IPHostEntry ipHostInfo = Dns.Resolve(Dns.GetHostName());
    IPEndPoint localEP = new IPEndPoint(ipHostInfo.AddressList[0],11000);

    Console.WriteLine("Local address and port : {0}",localEP.ToString());

    Socket listener = new Socket( localEP.Address.AddressFamily,
        SocketType.Stream, ProtocolType.Tcp );

    try {
        listener.Bind(localEP);
        s.Listen(10);

        while (true) {
            allDone.Reset();

            Console.WriteLine("Waiting for a connection...");
            listener.BeginAccept(
                new AsyncCallback(SocketListener.acceptCallback), 
                listener );

            allDone.WaitOne();
        }
    } catch (Exception e) {
        Console.WriteLine(e.ToString());
    }

    Console.WriteLine( "Closing the listener...");
}

接受回调方法(即前例中的 acceptCallback)负责向主应用程序发出信号,让它继续执行处理、建立与客户端的连接并开始异步读取客户端数据。下面的示例是 acceptCallback 方法实现的第一部分。该方法的此节向主应用程序线程发出信号,让它继续处理并建立与客户端的连接。它采用一个名为 allDone 的全局 ManualResetEvent。

[Visual Basic]

Public Sub acceptCallback(ar As IAsyncResult)
    allDone.Set()
    
    Dim listener As Socket = CType(ar.AsyncState, Socket)
    Dim handler As Socket = listener.EndAccept(ar)

    ' Additional code to read data goes here.
End Sub 'acceptCallback

[C#]

public void acceptCallback(IAsyncResult ar) {
    allDone.Set();

    Socket listener = (Socket) ar.AsyncState;
    Socket handler = listener.EndAccept(ar);

    // Additional code to read data goes here.  
}

从客户端套接字读取数据需要一个在异步调用之间传递值的状态对象。下面的示例实现一个用于从远程客户端接收字符串的状态对象。它包含以下各项的字段:客户端套接字,用于接收数据的数据缓冲区,以及用于创建客户端发送的数据字符串的 StringBuilder。将这些字段放在该状态对象中,使这些字段的值在多个调用之间得以保留,以便从客户端套接字读取数据。

[Visual Basic]

Public Class StateObject
    Public workSocket As Socket = Nothing
    Public BufferSize As Integer = 1024
    Public buffer(BufferSize) As Byte
    Public sb As New StringBuilder()
End Class 'StateObject

[C#]

public class StateObject {
    public Socket workSocket = null;
    public const int BufferSize = 1024;
    public byte[] buffer = new byte[BufferSize];
    public StringBuilder sb = new StringBuilder();
}

开始从客户端套接字接收数据的 acceptCallback 方法的此节首先初始化 StateObject 类的一个实例,然后调用 BeginReceive 方法以开始从客户端套接字异步读取数据。

下面的示例显示了完整的 acceptCallback 方法。它假定以下内容:存在一个名为 allDone 的 ManualResetEvent,定义了 StateObject 类,以及在名为 SocketListener 的类中定义了 readCallback 方法。

[Visual Basic]

Public Shared Sub acceptCallback(ar As IAsyncResult)
    ' Get the socket that handles the client request.
    Dim listener As Socket = CType(ar.AsyncState, Socket)
    Dim handler As Socket = listener.EndAccept(ar)
    
    ' Signal the main thread to continue.
    allDone.Set()
    
    ' Create the state object.
    Dim state As New StateObject()
    state.workSocket = handler
    handler.BeginReceive(state.buffer, 0, state.BufferSize, 0, _
        AddressOf AsynchronousSocketListener.readCallback, state)
End Sub 'acceptCallback


[C#]

    public static void acceptCallback(IAsyncResult ar) {
        // Get the socket that handles the client request.
        Socket listener = (Socket) ar.AsyncState;
        Socket handler = listener.EndAccept(ar);

        // Signal the main thread to continue.
        allDone.Set();

        // Create the state object.
        StateObject state = new StateObject();
        state.workSocket = handler;
        handler.BeginReceive( state.buffer, 0, StateObject.BufferSize, 0,
            new AsyncCallback(AsynchronousSocketListener.readCallback), state);
    }

需要为异步套接字服务器实现的 final 方法是返回客户端发送的数据的读取回调方法。与接受回调方法一样,读取回调方法也是一个 AsyncCallback 委托。该方法将来自客户端套接字的一个或多个字节读入数据缓冲区,然后再次调用 BeginReceive 方法,直到客户端发送的数据完成为止。从客户端读取整个消息后,在控制台上显示字符串,并关闭处理与客户端的连接的服务器套接字。

下面的示例实现 readCallback 方法。它假定定义了 StateObject 类。

[Visual Basic]

Public Shared Sub readCallback(ar As IAsyncResult)
    Dim state As StateObject = CType(ar.AsyncState, StateObject)
    Dim handler As Socket = state.workSocket
    
    ' Read data from the client socket. 
    Dim read As Integer = handler.EndReceive(ar)
    
    ' Data was read from the client socket.
    If read > 0 Then
        state.sb.Append(Encoding.ASCII.GetString(state.buffer, 0, read))
        handler.BeginReceive(state.buffer, 0, state.BufferSize, 0, _
            AddressOf readCallback, state)
    Else
        If state.sb.Length > 1 Then
            ' All the data has been read from the client;
            ' display it on the console.
            Dim content As String = state.sb.ToString()
            Console.WriteLine("Read {0} bytes from socket." + _
                ControlChars.Cr + " Data : {1}", content.Length, content)
        End If
    End If
End Sub 'readCallback


[C#]

public void readCallback(IAsyncResult ar) {
    StateObject state = (StateObject) ar.AsyncState;
    Socket handler = state.WorkSocket;

    // Read data from the client socket.
    int read = handler.EndReceive(ar);

    // Data was read from the client socket.
    if (read > 0) {
        state.sb.Append(Encoding.ASCII.GetString(state.buffer,0,read));
        handler.BeginReceive(state.buffer,0,StateObject.BufferSize, 0,
            new AsyncCallback(readCallback), state);
    } else {
        if (state.sb.Length > 1) {
            // All the data has been read from the client;
            // display it on the console.
            string content = state.sb.ToString();
            Console.WriteLine("Read {0} bytes from socket./n Data : {1}",
               content.Length, content);
        }
        handler.Close();
    }
}

目录
相关文章
|
5月前
|
缓存 监控 Java
Java Socket编程最佳实践:优化客户端-服务器通信性能
【6月更文挑战第21天】Java Socket编程优化涉及识别性能瓶颈,如网络延迟和CPU计算。使用非阻塞I/O(NIO)和多路复用技术提升并发处理能力,减少线程上下文切换。缓存利用可减少I/O操作,异步I/O(AIO)进一步提高效率。持续监控系统性能是关键。通过实践这些策略,开发者能构建高效稳定的通信系统。
169 1
|
2月前
|
安全 Java 调度
Java编程时多线程操作单核服务器可以不加锁吗?
Java编程时多线程操作单核服务器可以不加锁吗?
44 2
|
5月前
|
Java 应用服务中间件 开发者
【实战指南】Java Socket编程:构建高效的客户端-服务器通信
【6月更文挑战第21天】Java Socket编程用于构建客户端-服务器通信。`Socket`和`ServerSocket`类分别处理两端的连接。实战案例展示了一个简单的聊天应用,服务器监听端口,接收客户端连接,并使用多线程处理每个客户端消息。客户端连接服务器,发送并接收消息。了解这些基础,加上错误处理和优化,能帮你开始构建高效网络应用。
423 10
|
5月前
|
IDE Java 开发工具
从零开始学Java Socket编程:客户端与服务器通信实战
【6月更文挑战第21天】Java Socket编程教程带你从零开始构建简单的客户端-服务器通信。安装JDK后,在命令行分别运行`SimpleServer`和`SimpleClient`。服务器监听端口,接收并回显客户端消息;客户端连接服务器,发送“Hello, Server!”并显示服务器响应。这是网络通信基础,为更复杂的网络应用打下基础。开始你的Socket编程之旅吧!
84 3
|
1月前
|
网络协议 Unix Linux
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
|
5月前
|
Java
Java Socket编程与多线程:提升客户端-服务器通信的并发性能
【6月更文挑战第21天】Java网络编程中,Socket结合多线程提升并发性能,服务器对每个客户端连接启动新线程处理,如示例所示,实现每个客户端的独立操作。多线程利用多核处理器能力,避免串行等待,提升响应速度。防止死锁需减少共享资源,统一锁定顺序,使用超时和重试策略。使用synchronized、ReentrantLock等维持数据一致性。多线程带来性能提升的同时,也伴随复杂性和挑战。
101 0
|
5月前
|
安全 Java 网络安全
Java Socket编程教程:构建安全可靠的客户端-服务器通信
【6月更文挑战第21天】构建安全的Java Socket通信涉及SSL/TLS加密、异常处理和重连策略。示例中,`SecureServer`使用SSLServerSocketFactory创建加密连接,而`ReliableClient`展示异常捕获与自动重连。理解安全意识,如防数据截获和中间人攻击,是首要步骤。通过良好的编程实践,确保网络应用在复杂环境中稳定且安全。
102 0
|
5月前
|
Java 数据安全/隐私保护
深入剖析:Java Socket编程原理及客户端-服务器通信机制
【6月更文挑战第21天】Java Socket编程用于构建网络通信,如在线聊天室。服务器通过`ServerSocket`监听,接收客户端`Socket`连接请求。客户端使用`Socket`连接服务器,双方通过`PrintWriter`和`BufferedReader`交换数据。案例展示了服务器如何处理每个新连接并广播消息,以及客户端如何发送和接收消息。此基础为理解更复杂的网络应用奠定了基础。
67 13
|
4月前
|
Java 数据格式
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
Java面试题:简述Java Socket编程的基本流程,包括客户端和服务器的创建与通信。
86 0
|
5月前
|
监控 前端开发 JavaScript
JS Navigator.sendBeacon 可靠的、异步地向服务器发送数据
Navigator.sendBeacon 是一个用于发送少量数据到服务器的 API,尤其适用于在页面即将卸载时发送数据,如日志记录、用户行为分析等。 与传统的 AJAX 请求不同,sendBeacon 方法的设计目标是确保数据在页面卸载(例如用户关闭标签页或导航到新页面)时能够可靠地发送。 Navigator.sendBeacon 方法可用于通过 HTTP POST 将少量数据异步传输到 Web 服务器。 它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:XMLHttpRequest)发送分析数据的一些问题。
123 1