System.Net.Sockets.Socket

本文介绍如何使用Socket类实现Berkeley套接字接口,包括同步和异步通信方式,支持TCP和UDP协议。文章提供了示例代码,演示如何连接HTTP服务器并接收响应。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

实现 Berkeley 套接字接口。

命名空间:System.Net.Sockets汇编集:System(在 system.dll 中)
语法
public class Socket : IDisposable
备注

Socket 类为网络通信而提供了丰富的方法和属性。Socket 类允许你使用 ProtocolType 枚举中被列出的任何通信协议来完成同步数据传送和异步数据传送。Socket 还遵循了 .NET Framework 的异步方法命名模式;例如,同步的 Receive 方法就对应于异步的 BeginReceive 和 EndReceive 方法。

如果你的应用程序在执行的期间只能够请求到一个线程,就可以使用下列方法,这些方法是为了同步操作模式而设计的。

  • 如果你使用了一种面向连接的协议(比如 TCP),那么你的服务器就可以使用 Listen 方法来监听连接。而 Accept 方法则会处理任何输入的连接请求并且返回一个你可以用来与远程主机进行数据通信的 Socket。然后使用这个被返回的 Socket 来调用 Send 方法或者 Receive 方法。如果你需要指定本地 IP 地址和端口号,就需要在调用 Listen 方法之前调用 Bind 方法。如果你需要底层的服务提供者为你分配一个空闲的端口,就可以使用为 0 的端口号。如果你需要连接到一个正在监听的终端,就需要调用 Connect 方法。如果要进行数据通信,就需要调用 Send 方法或者 Receive 方法。
  • 如果你使用了一种无连接的协议(比如 UDP),那么你根本就不需要监听连接。而是直接调用 ReceiveFrom 方法来接收任何输入数据包。并且使用 SendTo 方法把数据包发送到远程终端。

如果要在执行的期间使用单独的线程来处理通信,就可以使用下列方法,这些方法是为了异步操作模式而设计的。

  • 如果你使用了一种面向连接的协议(比如 TCP),就可以使用 Socket、BeginConnect,和 EndConnect 方法来连接到一个正在监听的主机。使用 BeginSend 和 EndSend 或者 BeginReceive 和 EndReceive 方法来进行异步的数据通信。另外,输入的连接请求能够使用 BeginAccept 和 EndAccept 方法进行处理。
  • 如果你使用了一种无连接的协议(比如 UDP),那么你就可以使用 BeginSendTo 和 EndSendTo 来发送数据包,并且使用 BeginReceiveFrom 和 EndReceiveFrom 来接收数据包。

如果你在一个套接字上完成了多个异步操作,那么这些操作的完成顺序就不会与它们开始的时候完全一样。

在你完成发送和接收数据的时候,应该使用 Shutdown 方法来关闭 Socket。并且在调用 Shutdown 之后,调用 Close 方法来释放所有与该 Socket 相关的资源。

Socket 类允许你使用 SetSoekctOption 方法来配置你的 Socket。你还可以使用 GetSocketOption 方法来获取这些设定。

提示:如果你编写了一种相对简单的应用程序并且不需要考虑性能的最大化,就可以考虑使用 TcpClient、TcpListener,和 UdpClient。因为这些类为 Socket 的通信而提供了一种更加简单并且更加友好的接口。

Pocket PC 的 Windows Mobile、Smartphone 的 Windows Mobile,和 Windows CE Platform 的用户提示:并不是所有的设备操作系统都能够支持所有的套接字选项。

范例

下列代码说明了 Socket 类如何才能够用来把数据发送到 HTTP 服务器并且接收回应。并且这个范例在整个页面被接收完毕之前都是被阻塞的。

using System;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;

public class GetSocket
{
    private static Socket ConnectSocket(string server, int port)
    {
        Socket s = null;
        IPHostEntry hostEntry = null;
        
        // 获取与终端相关的信息。
        hostEntry = Dns.GetHostEntry(server);

        // 通过 AddressList 的循环来获取被支持的 AddressFamily。
        // 这样避免了在主机的 IPAddress 与地址家族(比如 IPv6)不兼容的时候会产生异常。
        foreach(IPAddress address in hostEntry.AddressList)
        {
            IPEndPoint ipe = new IPEndPoint(address, port);
            Socket tempSocket = 
                new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

            tempSocket.Connect(ipe);

            if(tempSocket.Connected)
            {
                s = tempSocket;
                break;
            }
            else
            {
                continue;
            }
        }
        return s;
    }

    // 这个方法会请求指定服务器的主页内容。
    private static string SocketSendReceive(string server, int port) 
    {
        string request = "GET / HTTP/1.1\r\nHost: " + server + 
            "\r\nConnection: Close\r\n\r\n";
        Byte[] bytesSent = Encoding.ASCII.GetBytes(request);
        Byte[] bytesReceived = new Byte[256];
       
        // 创建指定服务器和端口的套接字连接。
        Socket s = ConnectSocket(server, port);

        if (s == null)
            return ("Connection failed");
      
        // 发送请求到服务器。
        s.Send(bytesSent, bytesSent.Length, 0);  
        
        // 接收服务器的主页内容。
        int bytes = 0;
        string page = "Default HTML page on " + server + ":\r\n";

        // 下列代码直到页面被传送完毕之前都是被阻塞的。
        do {
            bytes = s.Receive(bytesReceived, bytesReceived.Length, 0);
            page = page + Encoding.ASCII.GetString(bytesReceived, 0, bytes);
        }
        while (bytes > 0);
        
        return page;
    }
    
    public static void Main(string[] args) 
    {
        string host;
        int port = 80;

        if (args.Length == 0)
            // 如果没有服务器名称被传递成该程序的参数,
            // 就使用当前主机名称来作为默认值。
            host = Dns.GetHostName();
        else
            host = args[0];

        string result = SocketSendReceive(host, port); 
        Console.WriteLine(result);
    }
}
.NET Framework 安全性
  • SocketPermission:建立一个输出连接或者接受一个输入请求。
继承层次
System.Object 
  System.Net.Sockets.Socket

转载于:https://www.cnblogs.com/Laeb/archive/2007/03/10/670202.html

### 如何关闭Socket连接并退出Accept方法的阻塞状态 当使用 `System.Net.Sockets.Socket` 进行网络编程时,在完成数据传输后应当正确地关闭 Socket 并释放相关资源。为了实现这一点,可以采用如下方式: 对于服务器端接受新连接的情况,如果想要停止监听新的连接请求并且让当前处于等待状态下的 `Accept()` 调用返回,则可以通过调用侦听套接字上的 `Close()` 方法来达到目的。这会使得任何正在执行中的 `Accept()` 操作立即抛出异常从而结束阻塞。 而对于已经建立好的特定客户端连接来说,在完成了所有的读写操作之后,应该先调用 `Shutdown(SocketShutdown.Both)` 来通知对方不再有更多数据到来,并允许剩余的数据被处理完毕;随后再通过 `Close()` 函数彻底断开连接并清理资源[^2]。 下面是一个简单的例子展示如何优雅地中止服务端程序运行的同时确保所有已打开的 socket 都能正常关闭: ```csharp using System; using System.Net; using System.Net.Sockets; public class Server { private static readonly int Port = 5151; // 定义使用的端口号 public static void Main(string[] args){ var listener = new TcpListener(IPAddress.Any, Port); try{ listener.Start(); Console.WriteLine($"Server started on port {Port}. Waiting for connections..."); while (true){ using(var clientSock = listener.AcceptTcpClient()){ HandleClient(clientSock); } } }catch(Exception ex){ Console.Error.WriteLine(ex.Message); }finally{ listener.Stop(); // 停止监听器 Console.WriteLine("Server stopped."); } } private static async Task HandleClient(TcpClient tcpClient){ NetworkStream stream = null; try{ stream = tcpClient.GetStream(); byte[] buffer = new byte[1024]; int bytesRead; do{ bytesRead = await stream.ReadAsync(buffer.AsMemory(0,buffer.Length)); string receivedText = Encoding.UTF8.GetString(buffer[..bytesRead]); Console.WriteLine(receivedText); // Echo back the message to the sender. await stream.WriteAsync(buffer.AsMemory(0,bytesRead)); }while(bytesRead != 0); } catch(ObjectDisposedException){ // The connection was closed by either party or an error occurred during communication. } finally{ if(stream is not null && !stream.IsClosed) stream.Close(); tcpClient?.Close(); // Ensure that we close our side of the TCP connection as well. Console.WriteLine("Connection with a client has been terminated."); } } } ``` 在这个示例里,一旦决定要终止整个应用程序,只需简单地中断循环即可触发 `listener.Stop()` 的调用,进而使后续尝试进入 accept 循环体内的线程因捕获到异常而跳出。与此同时,每一个单独的客户机处理器都会在其自身的上下文中妥善处置它们所管理的对象实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值