【问题标题】:Convert TCP StreamReader/StreamWriter to SSLStream将 TCP StreamReader/StreamWriter 转换为 SSLStream
【发布时间】:2018-04-19 08:30:38
【问题描述】:

这是我的代码:

public class ServerClient
{
    public  TcpClient tcp;
    public StreamReader streamReader;
    public StreamWriter streamWriter;
    public int accountId;
    public int connectionId;
    public ServerClient(TcpClient clientSocket)
    {
        tcp = clientSocket;
        streamReader = new StreamReader(tcp.GetStream(), false);
        streamWriter = new StreamWriter(tcp.GetStream());
        clientSocket.NoDelay = true;
    }
}

这是我监听数据的方式,在 while 循环中调用:

// Check for message from Client.
NetworkStream s = c.tcp.GetStream();
if (s.DataAvailable)
{
    string data = c.streamReader.ReadLine();

    if (data != null)
    {
        if (ValidateJSON(data))
        {
            OnIncomingData(c, data);
        }                            
    }

}
//continue;

这是我检查客户端是否仍然连接的方法:

private bool IsConnected(TcpClient c)
{
    try
    {
        if (c != null && c.Client != null && c.Client.Connected)
        {
            if (c.Client.Poll(0, SelectMode.SelectRead))
            {
                return !(c.Client.Receive(new byte[1], SocketFlags.Peek) == 0);
            }

            return true;
        }
        else
        {
            return false;
        }
    }
    catch
    {
        return false;
    }
}

这是我将数据发送到流中的方式:

string JSonData = JsonConvert.SerializeObject(SendData);

c.streamWriter.WriteLine(JSonData);
c.streamWriter.Flush();

这是我的客户监听消息的方式:

public void ConnectToWorldServer()
{
    if (socketReady)
    {
        return;
    }
    //Default host and port values;
    string host = "127.0.0.1";
    int port = 8080;

    //ClientLoginServer ClientLoginServer = new ClientLoginServer();


    try
    {

        socket = new TcpClient(host, port);
        stream = socket.GetStream();
        socket.NoDelay = true;
        writer = new StreamWriter(stream);
        reader = new StreamReader(stream);
        socketReady = true;
        //Preserve the connection to worldserver thrue scenes
        UnityThread.executeInUpdate(() =>
        {
            DontDestroyOnLoad(worldserverConnection);
        });

        // Start listening for connections.
        while (true)
        {
            keepReading = true;

            while (keepReading)
            {
                keepReading = true;
                if (socketReady)
                {
                    if (stream.DataAvailable)
                    {
                        string data = reader.ReadLine();
                        if (data != null)
                        {
                            UnityThread.executeInUpdate(() =>
                            {
                                OnIncomingData(data);
                            });
                        }
                    }
                }
                System.Threading.Thread.Sleep(1);
            }
            System.Threading.Thread.Sleep(1);
        }
    }
    catch (Exception e)
    {
        Debug.Log("Socket error : " + e.Message);
    }

}

我对 SSL Stream 感到不满。这是我发现的:https://msdn.microsoft.com/en-us/library/system.net.security.sslstream(v=vs.110).aspx

我有几个问题:

  1. 我需要像购买网站证书一样购买 SSL 证书吗?
  2. 我可以生成自签名 SSL 证书吗?如果是这样并且需要它,您能否向我展示如何实现这一目标的任何参考?
  3. 是否可以将此 SSL 流附加到我的 StreamReader/StreamWriter ?甚至需要它还是我必须重新制作整个连接/通信的东西?
  4. 创建 SSLStream 时,服务器和客户端之间的整个通信都将被加密,因此任何人都无法停留在两者之间并收听/理解他们正在通信的内容?
  5. 如果我必须将证书文件附加到客户端,以便它可以与服务器建立成功的 SSL 连接,然后将该客户端发送给所有必须使用该客户端的人,这不会危及客户端的安全性SSL 连接,因为我也向他们发送证书?

这就是我想问的。你能做的最好的事情是帮助我回答你的问题,如果可能的话,请输入我必须应用的代码更改,以使 StreamReader/StreamWriter 通过加密的 SSL 工作。

【问题讨论】:

  • 对我来说,try .. catch ... return false 是一种非常奇怪的“异常处理”方式。

标签: c# ssl unity3d


【解决方案1】:
  1. 您需要证书; makecert 可以工作,但默认情况下它不会被信任,因此您要么需要向消费者提供自定义 RemoteCertificateValidationCallback,要么使用受信任的证书; Let's Encrypt 可能在那里有用
  2. makecertNew-SelfSignedCertificate
  3. SslStream 需要NetworkStreamStreamReader 之间;坦率地说,让StreamReader 在这里给你很多东西还不清楚——你可以在这里用Streaam API 做所有事情;所以不是WriteLine,而是手动编码,然后Write编码缓冲区;但是 - 你没有理由不能在两者中间敲击SslStream
  4. 是的
  5. 只有服务器需要证书(特别是只有服务器需要证书的私钥); 一些相关的称为“客户端证书”的东西用于验证客户端,但这是一个相关但不同的主题

作为一个从 SE.Redis 中提取的示例,并且变得难以辨认; SE.Redis 可选加密,基本上是:

Stream stream = // connect (get a NetworkStream)
if (config.Ssl) {
    var ssl = new SslStream(stream, ... cert check callbacks, etc ...);
    ssl.AuthenticateAsClient(expectedHost, allowedSslProtocols);
    stream = ssl;
}

所以如果你有类似的东西,你只需确保附加任何StreamReader/StreamWriter 你已经将NetworkStream 包裹在SslStream 中。但再说一遍:我真的认为您可以在此处删除 StreamReader/StreamWriter 而不会带来太多不便。

【讨论】:

  • 你能告诉我如何在 SslStream 中包装 NetworkStream 吗?所以你认为不需要NetwrokStream。最好只使用 SslStream 吧?
  • @TonyStark "你能告诉我如何在 SslStream 中包装 NetworkStream" - 点击刷新 :)
  • @TonyStark "所以你认为不需要 NetwrokStream" - 我根本没有这么说 - NetworkStream 是使用 SslStream 的关键组件,因为 SslStream 想要一个StreamNetworkStream 使 Socket 看起来像 Stream
  • 谢谢@Marc Gravel。这对我来说不是很清楚。我从未使用过 SSL Steam。如果我删除 StreamReader/StreamWritter 我将如何从流中发送和读取消息?
  • @TonyStark stream.Read(...)stream.Write(...) - 但是;嗯...您现有的 StreamReader / StreamWriter 代码应该没问题...如果您不熟悉那部分,也许就别管它了
猜你喜欢
  • 2014-05-22
  • 2011-08-17
  • 1970-01-01
  • 1970-01-01
  • 2010-10-08
  • 2013-12-17
  • 1970-01-01
  • 2012-01-26
  • 1970-01-01
相关资源
最近更新 更多