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

异步服务器套接字使用 .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();
    }
}

时间: 2024-08-30 12:34:02

使用异步服务器套接字编程指南(微软MSDN)的相关文章

VC中TCP实现 异步套接字编程的原理+代码

所谓的异步套接字编程就是  调用了 如下函数   WSAAsyncSelect   设置了 套接字的状态为异步,有关函数我会在下面详细介绍... 异步套接字解决了 套接字编程过程中的堵塞问题 ...... 什么是堵塞?请看下面  你可能有过这样的体会  在  VC编写基于界面的网路程序时候  ,调用 recv recvfrom   accept  等函数的时候 整个程序的主线程进入堵塞状态直到 有连接或者信息的到来.  我们可以利用多线程的方法解决主线程堵塞的问题,但是我们如果一个程序需要多个套

C# 网络编程之套接字编程基础知识

      最近阅读了周存杰编写的<C#网络编程实例教程>并阅读了很多相关方面的资料,同时自己也做了一些套接字编程方面的C#程序,所以根据它的知识总结了最近的套接字编程的一些知识点,方便自己的理解与他人的学习,同时也有一些自己以前学习的计算机网络.操作系统等相关知识. 一.   套接字编程的概念       套接字(Winsock)是一种独立于协议的网络编程接口,在OSI中集中在会话层和传输层.(补充知识)简单回归网络知识,计算机网络中的"五层协议的体系结构"和"

《UNIX网络编程 卷1:套接字联网API(第3版)》——第8章 基本UDP套接字编程 8.1概述

第8章 基本UDP套接字编程 8.1 概述 在使用TCP编写的应用程序和使用UDP编写的应用程序之间存在一些本质差异,其原因在于这两个传输层之间的差别:UDP是无连接不可靠的数据报协议,非常不同于TCP提供的面向连接的可靠字节流.然而相比TCP,有些场合确实更适合使用UDP,我们将在22.4节探讨这个设计选择.使用UDP编写的一些常见的应用程序有:DNS(域名系统).NFS(网络文件系统)和SNMP(简单网络管理协议). 图8-1给出了典型的UDP客户/服务器程序的函数调用.客户不与服务器建立连

PHP套接字编程

编程 作者:久隆信息/张晓刚 套接字编程,一般使用c或c++.特别的在web应用程序开发中,常用perl实现套接字.除此以外,用php进行套接字编程也是一个选择.Php可以胜任吗?当然可以.Php是一门高质量的web应用程序开发语言,他的许多特性可以处理众多的任务,网络编程也不例外. 1. 理解套接字 Mail.ftp.telnet.name和finger这些服务都是在一个专用的公开的端口上提供的,通过连接到这些端口,客户程序就能够访问这些服务.这与现实生活是相似的--当需要干洗衣服的时候,找干

Windows Socket网络编程(二) 套接字编程原理

一.客户机/服务器模式 在TCP/IP网络中两个进程间的相互作用的主机模式是客户机/服务器模式(Client/Server model).该模式的建立基于以下两点:1.非对等作用:2.通信完全是异步的.客户机/服务器模式在操作过程中采取的是主动请示方式: 首先服务器方要先启动,并根据请示提供相应服务:(过程如下) 1.打开一通信通道并告知本地主机,它愿意在某一个公认地址上接收客户请求. 2.等待客户请求到达该端口. 3.接收到重复服务请求,处理该请求并发送应答信号. 4.返回第二步,等待另一客户

基于多线程的客户端/服务器套接字类

这篇文章主要介绍如何设计基于多线程的客户端/服务器套接字(socket)类.开发者/设计者可以根据具体的 需要决定是否选用另外的线程.在网络上有许多其它的套接字类,但是没有一个能够向这个类一样为你的应用程序 提供回调功能(事件监测).本文设计的类能够为你提供如下的事件监测:完成建立链接.放弃链接.链接失败和 接收数据(包括0字节数据包). 描述: 本文提供一种新的,同时支持TCP和UDP通讯的套接字类,与你可能在本站或其它地方发现的套接字编程文章相 比,本文设计的类有很多优点.首先,这个类没有像

套接字编程简介

套接字编程简介 项目:UNIX网络编程学习 作者:曾金龙 供职:(深圳迅雷网络技术股份有限公司) 领域:迅雷下载库研发 日期:2014-07-25 1, TCP连接图 socket编程,过眼烟云的去看,无外乎就那么几个API,但是,如果想登堂入室,必须注重里面的每一个细节. 对于TCP编程而言,最重要的是记住这么一幅图.死记的基础上理解. windows下有visio,ubuntu下只好用Dia,不是很习惯,而且不支持中文输入. 图1 TCP连接的数据包交换图 你特别需要注意的是: 1)哪个地方

windows和linux的tcp套接字编程实例代码

windows下面的代码如下面 //Server.cpp #include <iostream> #include <windows.h> #define IP "127.0.0.1" #define PORT 8888 #pragma comment(lib,"ws2_32.lib") using namespace std; char* GetTime(); int main() {     WSADATA wsaData;     WO

TCP套接字编程模型及实例

摘要:     本文讲述了TCP套接字编程模块,包括服务器端的创建套接字.绑定.监听.接受.读/写.终止连接,客户端的创建套接字.连接.读/写.终止连接.先给出实例,进而结合代码分析.   PS:本文权当复习套接字编程的读书笔记.   一.TCP套接字编程模型     同一台计算机上运行的进程可以利用管道.消息队列.信号量.共享内存等进行相互通信,不同计算机上运行的进程可以通过套接字网络IPC接口进行相互通信.套接字编程基本步骤如下图所示: 图 TCP套接字编程模型[1] 二.源代码     本