Разница между прослушивателем TCP и сокетом

Насколько я знаю, я могу создать сервер, используя как TCPListener, так и 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); }
    }
}

person Roman Ratskey    schedule 11.09.2012    source источник


Ответы (4)


Это просто разные классы, которые делают одно и то же, написанные на разных уровнях. Под капотом TCPListener, несомненно, вызывает что-то очень похожее на ваш первый код на основе сокетов. Это просто для того, чтобы скрыть вас от некоторых кровавых подробностей.

person user207421    schedule 11.09.2012

TcpListener — это удобная оболочка для TCP-коммуникаций. Это позволяет вам использовать TcpClient для принятых соединений, хотя вы можете принимать сокеты вместо клиентов, чтобы использовать Socket вместо TcpClient. Вы можете сделать то же самое с Socket; но вам придется иметь дело с некоторыми особенностями TCP (например, SocketType.Stream, ProtocolType.Tcp). TCP — это протокол на основе потоков, и TcpClient признает это, позволяя вам осуществлять потоковую связь, предоставляя поток с TcpClient.GetStream(). Socket находится на другом уровне более высокого и должен поддерживать множество различных протоколов, таких как UDP, которые не основаны на потоках.

TcpClient.GetStream возвращает объект NetworkStream, подходящий для SslStream; таким образом, это должно быть намного меньше работы, чем использование Socket напрямую. В документации для SslStream подробно описано использование TcpListener и TcpClient для связи SSL.

person Peter Ritchie    schedule 12.09.2012
comment
в моем классе асинхронных сокетов я использовал socket.BeginReceive, чтобы начать получать каждое сообщение, отправленное от клиента. но теперь, когда я обернул свой класс сокета sslstream, чтобы защитить идентификатор соединения, что эквивалентно .BeginReceive в ssl - person Roman Ratskey; 12.09.2012
comment
Поэтому, пожалуйста, я хочу, чтобы вы помогли мне с моим обновленным кодом выше в основном посте. - person Roman Ratskey; 12.09.2012
comment
@TorlanOther Если вы используете SslStream, вам лучше использовать SslStream.BeginRead - person Peter Ritchie; 12.09.2012
comment
каждый раз, когда я пытаюсь использовать это в приведенном выше коде, я не получаю данных, idk, почему вы могли видеть мой код, потому что мне действительно нужна ваша помощь, я слишком сбит с толку, почему это не сработало - person Roman Ratskey; 12.09.2012
comment
я не получаю сообщение, только я получаю пустое сообщение, 1000+++ пробелов - person Roman Ratskey; 12.09.2012
comment
значит ли это, что уровень Socket ниже, чем уровень TcpClient? Это единственный пункт вашего ответа, который меня смущает. - person Shawn Kovac; 27.06.2014
comment
да, плохой выбор слов, я полагаю. Я исправил это. - person Peter Ritchie; 27.06.2014

TcpListener оборачивает сокет и является серверным аналогом TcpClient (который также, конечно же, является оберткой для сокета).

TcpListener предварительно настроен на TCP (в отличие от Socket, который можно использовать с UDP, чистым IP, не-IP протоколами и т. д.) и предоставляет вам TcpClient при обработке соединения.

Если вы не уверены, нужен ли вам сокет и используете TCP, я настоятельно рекомендую начать с TcpListener/Client, так как это гораздо более простой в использовании интерфейс.

person Mark Brackett    schedule 11.09.2012
comment
Я хочу использовать SSL Stream, но не знаю, как я могу использовать .GetStream с классом сокета [Первый пример] - person Roman Ratskey; 11.09.2012
comment
@TorlanOther - во-первых, вам нужен поток поверх сокета: System.Net.NetworkStream даст вам это. Затем создайте SslStream поверх NetworkStream. - person Mark Brackett; 11.09.2012
comment
так что вы имеете в виду, что в обратном вызове AcceptConnections я создаю сетевой поток, который получает поток из AsyncResult, затем я использую .GetStream с SSLStream? - person Roman Ratskey; 11.09.2012
comment
посмотрите мой обновленный код, теперь я могу принимать соединения и аутентифицироваться с помощью потока SSL после редактирования моего кода, как вы мне сказали, но все еще не могу получать данные, поэтому, пожалуйста, помогите мне - person Roman Ratskey; 12.09.2012
comment
@TorlanOther - я не вижу нигде, чтобы вы на самом деле читали из потока. Я предполагаю, что это в непоказанных обработчиках событий? - person Mark Brackett; 13.09.2012
comment
@Timeless - в целом производительность известной абстракции более высокого уровня будет эквивалентной или лучше, чем наивная повторная реализация той же абстракции. Итак, вопрос на самом деле - хочу ли я (и могу ли позволить себе) эту абстракцию. Остальное - это вопрос, который лучше всего подходит для профилировщика.... - person Mark Brackett; 07.11.2017

На самом деле я не отвечаю на вопрос, но вам, кажется, больше нравится TcpClient, потому что у него есть GetStream(), который вы можете использовать с SslStream, но вы можете получить NetworkStream из Socket, передав Socket в качестве конструктора NetworkStream

i.e. NetworkStream myStream = new NetworkStream(mySocket);

person robbie    schedule 28.02.2016
comment
Я не помню, чтобы писал это. - person robbie; 23.04.2017