TCP监听器和Socket的区别

47

据我所知,我可以使用TCPListener和Socket创建服务器,那么它们两者之间有什么区别?

Socket

private Socket MainSock;
MainSock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
MainSock.Bind(new IPEndPoint(IPAddress.Any, port));
MainSock.Listen(500);
MainSock.BeginAccept(AcceptConnections, new Wrapper());
TCPListener
    Int32 port = 13000;
    IPAddress localAddr = IPAddress.Parse("127.0.0.1");
    TcpListener server = new TcpListener(localAddr, port);
    server.Start();

我真的很困惑。这两个都在监听连接,那它们之间有什么区别呢?

更新代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.IO;

public class Wrapper
{
    public byte[] buffer;
    public SslStream sslStream;
    public object connector;
}

public class Sock
{
    private Dictionary<string, byte> Connections;
    public event Action<Wrapper> AnnounceNewConnection;
    public event Action<Wrapper> AnnounceDisconnection;
    public event Action<byte[], Wrapper> AnnounceReceive;
    private Socket _sock;

    private X509Certificate certificate = X509Certificate.CreateFromCertFile("exportedcertificate.cer");

    public Sock(int port)
    {
        try
        {
            Connections = new Dictionary<string, byte>();
            _sock = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            _sock.Bind(new IPEndPoint(IPAddress.Any, port));
            _sock.Listen(500);
            _sock.BeginAccept(AcceptConnections, new Wrapper());
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }

    private void AcceptConnections(IAsyncResult result)
    {
        Wrapper wr = (Wrapper)result.AsyncState;
        try
        {
            wr.sslStream = new SslStream(new NetworkStream(_sock.EndAccept(result), true));
            wr.sslStream.BeginAuthenticateAsServer(certificate, AcceptAuthenticate, wr);

            _sock.BeginAccept(AcceptConnections, new Wrapper());
        }
        catch (Exception e) { Console.WriteLine(e); }
    }

    private void AcceptAuthenticate(IAsyncResult result)
    {
        Wrapper wr = (Wrapper)result.AsyncState;
        try
        {
            wr.sslStream.EndAuthenticateAsServer(result);
            if (wr.sslStream.IsAuthenticated == true)
            {
                AnnounceNewConnection.Invoke(wr);
            }
        }
        catch (Exception e) { Console.WriteLine(e); }
    }

    private void ReceiveData(IAsyncResult result)
    {
        Wrapper wr = (Wrapper)result.AsyncState;
        try
        {
            AnnounceReceive.Invoke(wr.buffer, wr);
        }
        catch (Exception e) { Console.WriteLine(e); AnnounceDisconnection.Invoke(wr); }
    }
}
5个回答

43

TcpListener 是 TCP 通信的便捷包装器。这允许您使用 TcpClient 来接受连接,虽然您也可以接受套接字而不是客户端,以使用 Socket 代替 TcpClient。您也可以使用 Socket 完成同样的事情,但需要处理一些特定于 TCP 的细节(如 SocketType.Stream, ProtocolType.Tcp)。TCP 是基于流的协议,TcpClient 可以通过提供一个带有 TcpClient.GetStream() 的流来识别它。而 Socket 处于不同的级别并且需要支持许多不基于流的协议,例如 UDP。

TcpClient.GetStream 返回适用于 SslStreamNetworkStream 对象,因此应该比直接使用 Socket 更加省力。关于使用 TcpListenerTcpClient 进行 SSL 通信的详细信息,请参阅SslStream 的文档


在我的异步套接字类中,我曾经使用socket.BeginReceive来开始接收客户端发送的每个消息。但是现在,在我用sslstream包装我的套接字类以保护连接之后,我不知道ssl中的等效方法是什么。 - Roman Ratskey
1
如果您正在使用SslStream,则应使用SslStream.BeginRead - Peter Ritchie
每次我尝试在上面的代码中使用它,我都得不到任何数据,我不知道为什么。你能看一下我的代码吗?因为我真的需要你的帮助,我太困惑了,不知道为什么它没有起作用。 - Roman Ratskey
我没有收到消息,只是得到了一个空消息,有1000多个空格。 - Roman Ratskey
是的,我想我的措辞不太恰当。我已经更正了。 - Peter Ritchie
显示剩余2条评论

25

它们只是不同的类,用不同的级别编写,但执行的功能相同。在底层,TCPListener无疑调用了类似于您第一个基于Socket的代码的东西。它只是为了让你避免一些令人不快的细节。


21
一个TcpListener包装了一个socket,并且是服务器端对应TcpClient(当然,也是包装了一个socket)的类。
TcpListener使用TCP进行预配置(相比之下,Socket可以用于UDP,纯IP,非IP协议等),并在处理连接时提供TcpClient。
如果您不确定是否需要Socket,并且使用TCP - 我强烈建议首先使用TcpListener / Client,因为它是一个更易于使用的接口。

我想使用SSL Stream,但不知道如何在socket类中使用.GetStream [第一个例子]。 - Roman Ratskey
@TorlanOther - 首先,你需要在套接字上建立一个流:System.Net.NetworkStream 可以提供这个功能。然后,在 NetworkStream 上构建一个 SslStream。 - Mark Brackett
那么你的意思是在AcceptConnections回调函数中创建一个网络流,该流从AsyncResult获取,然后使用SSLStream的.GetStream方法? - Roman Ratskey
请看我的更新代码,现在我可以接受连接并通过SSL流进行身份验证,就像您告诉我的那样进行了编辑。但是仍然无法接收数据,请帮帮我。 - Roman Ratskey
@TorlanOther - 我没有看到你从流中读取的任何地方。我假设这是在未显示的事件处理程序中? - Mark Brackett
@Timeless - 一般来说,一个众所周知的高级抽象的性能将等同或优于天真地重新实现相同的抽象。因此问题实际上是 - 我是否想要(并且能够负担得起)这个抽象。其余部分最好由分析器来处理... - Mark Brackett

0

我并没有真正回答你的问题,但是你似乎更喜欢 TcpClient 是因为它有一个可以与 SslStream 一起使用的 GetStream() 方法,但你也可以通过将 Socket 作为构造函数传递给 NetworkStream 来获取一个 NetworkStream

例如: NetworkStream myStream = new NetworkStream(mySocket);


14
我不记得写过这个。 - robbie

0
我知道答案已经给出了,但只是为了说明,当你查看TcpListener的源代码时,你会发现它是一个套接字的包装器,并预配置为使用Tcp流。

enter image description here


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接