简体   繁体   English

C#将两个TCP套接字连接在一起

[英]C# Connecting two tcp sockets together

I'm not sure if the title is all that informative. 我不确定标题是否能提供全部信息。

I am trying to find/write a socket server that will accept a connection from the client (telnet) and then on behalf of the connected client, connect to one of four telnet servers inside the network. 我试图查找/编写一个套接字服务器,该服务器将接受来自客户端(telnet)的连接,然后代表已连接的客户端,连接到网络中的四个telnet服务器之一。

Once connected I keep a counter of how many connections there are, and then if there are 4 total connections, disallow any new connections until one of the four is available. 建立连接后,我会记录有多少个连接,然后如果总共有4个连接,则禁止任何新连接,直到四个可用之一为止。

I have written this: 我写了这个:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;

namespace ConsoleApplication1
{
class Program
{
    static int nodeCount = 4;
    static int currentNode = 1;

    static void Main(string[] args)
    {
        ServerProgram server = new ServerProgram();
    }

    class ServerProgram
    {
        private TcpListener tcpPrimaryListener;
        private Thread listenThread;

        public ServerProgram()
        {
            this.tcpPrimaryListener = new TcpListener(IPAddress.Any, 23);
            Console.WriteLine("Telnet BBS Port Concentrator Server Started.");
            Console.WriteLine("--------------------------------------------");

            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        private void ListenForClients()
        {
            this.tcpPrimaryListener.Start();

            while (true)
            {
                TcpClient client = this.tcpPrimaryListener.AcceptTcpClient();
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }
        }

        private void HandleClientComm(object client)
        {
            if (currentNode <= nodeCount)
            {
                Console.WriteLine("Connection thread created.");

                StreamWriter swStream;
                StreamWriter swStream2;
                StreamReader srStream;
                StreamReader srStream2;

                TcpClient tcpClient = (TcpClient)client;
                NetworkStream tcpClientStream = tcpClient.GetStream();

                TcpClient telnet = new TcpClient("192.168.100.5" + currentNode, 23);
                NetworkStream telnetStream = telnet.GetStream();

                currentNode++;

                while (true)
                {
                    srStream = new StreamReader(tcpClient.GetStream());
                    swStream2 = new StreamWriter(tcpClient.GetStream());

                    srStream2 = new StreamReader(telnet.GetStream());
                    swStream = new StreamWriter(telnet.GetStream());

                    swStream.Write(srStream.ReadToEnd());
                    swStream2.Write(srStream2.ReadToEnd());

                }
            }
        }
    }
}
}

I've changed this example multiple times, so I don't really know anymore what I have and have not tried. 我已经多次更改了此示例,所以我真的不知道自己拥有什么并且没有尝试过。 I'm willing to try anything. 我愿意尝试任何事情。

The purpose is actually running this to allow one telnet port open through the firewall, and allowing connections into a small network of DOS machines running telnet fossil driver BBS software. 目的实际上是在运行此操作,以便允许一个telnet端口通过防火墙打开,并允许连接到运行telnet化石驱动程序BBS软件的DOS计算机的小型网络中。 I would just like to redirect telnet traffic to an available system using only one port. 我只想使用一个端口将telnet通信重定向到可用系统。

The problem is that I cannot figure out how to actually connect the two sockets together and pass data between them as it happens. 问题是我无法弄清楚如何将两个套接字实际连接在一起,以及如何在它们之间传递数据。 The incoming socket and the socket I created on behalf of the server to the server. 传入的套接字和我代表服务器创建的套接字到服务器。

Thanks. 谢谢。

UPDATE: 更新:

This is what is working for me, I'm still looking over for bugs but it's working so far. 这就是对我有用的东西,我仍在寻找错误,但到目前为止,它仍然有效。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Threading;
using System.Net;
using System.IO;
using System.Threading.Tasks;

namespace ConsoleApplication1
{
class Program
{
    static int nodeCount = 2;
    static int currentNode = 1;

    static void Main(string[] args)
    {
        ServerProgram server = new ServerProgram();
    }

    class ServerProgram
    {
        private TcpListener tcpPrimaryListener;
        private Thread listenThread;

        public ServerProgram()
        {
            this.tcpPrimaryListener = new TcpListener(IPAddress.Any, 23);
            Console.WriteLine("Telnet BBS Port Concentrator Server Started.");
            Console.WriteLine("--------------------------------------------");

            this.listenThread = new Thread(new ThreadStart(ListenForClients));
            this.listenThread.Start();
        }

        private void ListenForClients()
        {
            this.tcpPrimaryListener.Start();

            while (true)
            {
                TcpClient client = this.tcpPrimaryListener.AcceptTcpClient();
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            }
        }

        private void HandleClientComm(object client)
        {
            string noNodes = "Sorry all nodes are occupied.";

            if (currentNode <= nodeCount)
            {
                Console.WriteLine("Client connected.");

                TcpClient tcpClient = (TcpClient)client;
                NetworkStream tcpClientStream = tcpClient.GetStream();

                TcpClient telnet = new TcpClient("10.24.9.11", 23);
                //TcpClient telnet = new TcpClient("192.168.100.5" + currentNode, 23);
                NetworkStream telnetStream = telnet.GetStream();

                currentNode++;

                ByPass linkedSockets = new ByPass(tcpClientStream, telnetStream);
            }
            else
            {
                TcpClient tcpClient = (TcpClient)client;
                NetworkStream tcpClientStream = tcpClient.GetStream();

                ASCIIEncoding encoder = new ASCIIEncoding();
                tcpClientStream.Write(Encoding.ASCII.GetBytes(noNodes), 0, noNodes.Length);
            }
        }
    }

    public class ByPass
    {
        public ByPass(Stream s1, Stream s2)
        {
            var cTokenSource = new CancellationTokenSource();
            var cToken = cTokenSource.Token;
            Task.Factory.StartNew(() => Process(s1, s2, cToken, cTokenSource), cToken);
            Task.Factory.StartNew(() => Process(s2, s1, cToken, cTokenSource), cToken);
            cToken.Register(() => cancelNotification());
        }

        public void Process(Stream s1, Stream s2, CancellationToken ct, CancellationTokenSource cTokenSource)
        {
            byte[] buf = new byte[0x10000];

            while (true)
            {
                if (ct.IsCancellationRequested)
                {
                    break;
                }

                try
                {
                    int len = s1.Read(buf, 0, buf.Length);
                    s2.Write(buf, 0, len);
                }
                catch
                {
                    s1.Close(); s2.Close();
                    cTokenSource.Cancel();
                    break;
                }
            }
        }
    }

    static void cancelNotification()
    {
        Console.WriteLine("Client disconnected.");
        currentNode--;
    }
}
}

I think, you can create a class similar to below to pass data between two streams 我认为,您可以创建类似于以下内容的类以在两个流之间传递数据

public class ByPass
{
    public ByPass(Stream s1, Stream s2)
    {

        Task.Factory.StartNew(() => Process(s1, s2));
        Task.Factory.StartNew(() => Process(s2, s1));
    }

    public void Process(Stream sIn, Stream sOut)
    {
        byte[] buf = new byte[0x10000];
        while (true)
        {
            int len = sIn.Read(buf, 0, buf.Length);
            sOut.Write(buf, 0, len);
        }
    }
}

I have made little changes and it works perfect on my side 我所做的改动很小,在我这方面效果很好

    public class StreamTransmitter
    {
        static TaskCompletionSource<bool> ts;

        public static async Task Start(Stream s1, Stream s2, CancellationToken token)
        {
            ts = new TaskCompletionSource<bool>();

            Process(s1, s2, token);
            Process(s2, s1, token);

            await ts.Task;
        }

        private static async Task Process(Stream sIn, Stream sOut, CancellationToken token)
        {
            byte[] buf = new byte[0x10000];
            int len = 0;
            do
            {
                len = await sIn.ReadAsync(buf, 0, buf.Length, token);
                await sOut.WriteAsync(buf, 0, len, token);
            }
            while (len > 0 && !token.IsCancellationRequested);

            ts.SetResult(true);
        }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM