【问题标题】:Multithreading socket connections C#?多线程套接字连接C#?
【发布时间】:2014-09-02 19:47:24
【问题描述】:

您好 StackOverFlow 社区,我正在开发一个 C# 程序,该程序依赖于同一服务器的许多套接字连接。
我想在我的连接类上进行多线程处理,这样我就可以在不创建很多类的情况下创建任意数量的连接
然而,代码将解释它:
网关(连接线程)

using SilkroadSecurityApi;
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;

namespace ConsoleLogin1
{
    public class Gateway
    {
        public static MainClass MainWindow;
        public static ServerEnum Server = ServerEnum.None;
        public static List<Packet> GatewayPackets = new List<Packet>();
        public static TransferBuffer GatewayRecvBuffer = new TransferBuffer(0x1000, 0, 0);
        public static Security GatewaySecurity = new Security();
        public static Socket GatewaySocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        public static Thread loop;
        public enum ServerEnum
        {
            None,
            Gateway,
            Agent
        }
        public void Gateway_thread()
        {
            while (true)
            {
                SocketError success;
                byte[] bytes;
                GatewayRecvBuffer.Size = GatewaySocket.Receive(GatewayRecvBuffer.Buffer, 0, GatewayRecvBuffer.Buffer.Length, SocketFlags.None, out success);
                if (success != SocketError.Success)
                {
                    if (success != SocketError.WouldBlock)
                    {
                        return;
                    }
                }
                else if (GatewayRecvBuffer.Size > 0)
                {
                    GatewaySecurity.Recv(GatewayRecvBuffer);
                }
                else
                {
                    return;
                }
                List<Packet> collection = GatewaySecurity.TransferIncoming();
                if (collection != null)
                {
                    GatewayPackets.AddRange(collection);
                }
                if (GatewayPackets.Count > 0)
                {
                    foreach (Packet packet in GatewayPackets)
                    {
                        //incoming packets
                    }
                    GatewayPackets.Clear();
                }
                List<KeyValuePair<TransferBuffer, Packet>> list2 = GatewaySecurity.TransferOutgoing();
                if (list2 != null)
                {
                    foreach (KeyValuePair<TransferBuffer, Packet> pair in list2)
                    {
                        TransferBuffer key = pair.Key;
                        Packet packet = pair.Value;
                        success = SocketError.Success;
                        while (key.Offset != key.Size)
                        {
                            int num19 = GatewaySocket.Send(key.Buffer, key.Offset, key.Size - key.Offset, SocketFlags.None, out success);
                            if ((success != SocketError.Success) && (success != SocketError.WouldBlock))
                            {
                                break;
                            }
                            key.Offset += num19;
                            Thread.Sleep(1);
                        }
                        if (success != SocketError.Success)
                        {
                            break;
                        }
                        bytes = packet.GetBytes();
                    }
                    if (success != SocketError.Success)
                    {
                        return;
                    }
                }
                Thread.Sleep(1);
            }
        }
        public static void SendToServer(Packet packet)
        {
            GatewaySecurity.Send(packet);
        }

        public void Connect(string IP, string Port)
        {
            loop = new Thread(new ThreadStart(this.Gateway_thread));
            GatewaySocket.Connect(IP, int.Parse(Port));
            loop.Start();
            GatewaySocket.Blocking = false;
            GatewaySocket.NoDelay = true;
        }
    }
}

主类

using System;
using System.Threading.Tasks;
using SilkroadSecurityApi;
using System.Threading;

namespace ConsoleLogin1
{
    public class MainClass
    {
        public string ip = "25.122.17.189";
        public string port = "15779";
        public string locale = "22";
        public string version = "190";
        static void Main(string[] args)
        {
            new MainClass().Start();
        }
        public void Start()
        {
            Gateway.MainWindow = this;
            new Gateway().Connect(ip, port);
        }
    }
}

但是我尝试了很多方法,例如:

Gateway G1 = new Gateway();  
Gateway G2 = new Gateway(); 

也开始了新的线程

Thread G1 = new Thread(new ThreadStart(Gateway.Connect))
Thread G2 = new Thread(new ThreadStart(Gateway.Connect))

但是没有办法,当已经有一个打开的连接时,永远不能创建新的 GatewaySocket。 无论如何,我的问题又是:我如何为网关进行多线程处理,并且每个人都有自己的连接?

提前致谢。

【问题讨论】:

  • 您不能同时为同一个端口创建多个套接字。您需要让每个套接字侦听不同的端口。
  • 如果你开始监听一个端口。它为 .NET 中的每个套接字锁定。您可以使用 WinAPI 解决问题,但这是另一个不为人知的故事
  • @Servy 没有更好更快的方法吗?
  • @BugsBunny 肯定有比你正在做的更好的方式来运行服务器。创建两个线程,每个线程都创建单独的套接字,不是吗。如何创建一个设计良好的服务器应用程序远远超出了 SO 答案中可以描述的范围。
  • @BugsBunny 你的申请是关于什么的?你想通过多重连接实现什么?每个“连接”也会收到相同的数据

标签: c# multithreading sockets


【解决方案1】:

这就是我的做法:

  1. 我会定义各种类:

    • 连接
    • 命令
    • 动作控制器
    • 图形界面
  2. 连接类:

    public class Connection
    {
        public string ip = "";
        public string port = "";
        public bool listening = false;
    
        public TcpClient tcpClient;
        private BackgroundWorker bw = new BackgroundWorker();
        private NetworkStream stream;
    
        public delegate DataReceivedEvent(Byte[] data, TcpEventArgs e);
        public DataReceivedEvent dataReceived;
    
        public List<Command> commands = new List<Command>();
    
        //for Debugging purpose
        public string lastError = "";
    
        public Connection(string ip, string port)
        {
            this.ip = ip;
            this.port = port;
            bw.WorkerSupportsCancellation = true;
    
            if(!Connect())
            {
                return;
                //maybe do something here?
            }                
        }
    
        public bool Connect()
        {
            try
            {
                tcpClient.Connect(ip, port);
                stream = tcpClient.GetStream();
                return true;
            }
            catch(Exception ex)
            {
                lastError = ex.Message + " - " + ex.StackTrace;
                return false;
            }
        }
    
        public void BeginListening()
        {
            bw.DoWork += listenToNetwork();
            bw.RunWorkerAsync();
        }
    
        public void EndListening()
        {
            bw.CancelAsync();
        }
    
        private void listenToNetwork(Object sender, DoWorkEventArgs e)
        {
            while(!PendingCancellation)
            {
                Byte[] bytes = new Byte[preferedLenghth];
                listening = true;
                Int32 bytesRead = stream.Read(bytes, 0, bytes.Length);
                if(dataReceived != null)
                {
                    dataReceived(bytes, new TcpEventArgs(bytesRead));
                }
            }
            listening = false;
        }
    
        public void SendCommands()
        {
            foreach(Command cmd in commands)
            {
                cmd.Execute(ref stream);
            }
        }
    }
    
  3. Command 类:

    // i made a seperate class of Command because it is easy to expand without getting monsterclasse
    public class Command
    {
        private CommandEnum cmd;
    
        public Command(CommandEnum cmd)
        {
            this.cmd = cmd;
        }
    
        public void Execute(ref NetworkStream stream)
        {
            switch(cmd)
            {
                //insert commands like stream.write(bytesToSend, 0, bytesToSend.Length);
                default:
                break;
            }
        }
    }
    
  4. ActionController 类:

    public ActionController
    {
        public Connection conn;
    
        public ActionController(string ip, string port)
        {
            conn = new Connection(ip, port)
            conn.dataReceived += dataReceivedevent;
        }
    
        public void dataReceivedevent(Byte[] data, TcpEventArgs e)
        {
             //Do something with the received data here
        }
        //Do everything here! the Controller is here to provide necessary information for the GUI
    }
    

    .5 图形用户界面随你的想象;)

我认为代码是一种不言自明的询问是否有不清楚的地方

【讨论】:

  • 对不起塞巴斯蒂安,但这甚至不会连接到丝绸之路的游戏服务器本身。不知何故,丝绸之路游戏服务器和客户端的连接方式不同,即使有一个用于登录的端口和另一个用于播放的端口..
  • @Bugs Bunny 然后使用两个不同端口的连接,你只需要创建两个连接实例
猜你喜欢
  • 2019-10-14
  • 1970-01-01
  • 2016-03-16
  • 2012-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多