将TCP StreamReader/StreamWriter转换为SSLStream

Ven*_*lev 2 c# ssl unity-game-engine

这是我的代码:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我在监听数据的方式,这是在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;
Run Code Online (Sandbox Code Playgroud)

以下是我如何检查客户端是否仍然连接:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

以下是我如何将数据发送到流中:

string JSonData = JsonConvert.SerializeObject(SendData);

c.streamWriter.WriteLine(JSonData);
c.streamWriter.Flush();
Run Code Online (Sandbox Code Playgroud)

这是我的客户端如何监听消息:

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);
    }

}
Run Code Online (Sandbox Code Playgroud)

我对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工作.

Mar*_*ell 5

  1. 你需要证书; makecert可行,但默认情况下不会受信任,因此您需要向RemoteCertificateValidationCallback消费者提供自定义,或使用受信任的证书; 我们的加密可能在那里很有用
  2. makecert 要么 New-SelfSignedCertificate
  3. SslStream需要去之间NetworkStreamStreamReader; 坦率地说,StreamReader在这里给你带来很多东西并不清楚- 你可以用StreaamAPI 来做所有事情; 所以不是WriteLine手动编码,而是Write编码缓冲区; 但是 - 没有理由你不能SslStream在两者中间敲打
  4. 只有服务器需要证书(特别是,只有服务器需要证书的私钥); 还有就是相关的一些所谓的用于验证"客户端证书" 的客户,但是这是一个相关但不同的主题

作为一个例子,从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;
}
Run Code Online (Sandbox Code Playgroud)

所以你有这样的东西,你只需要确保你附上任何StreamReader/ StreamWriter 你包裹NetworkStream之后SslStream.但同样:我真的认为你可以删除StreamReader/ StreamWriter这里没有太多的不便.