多线程套接字连接C#?

时间:2014-09-02 19:47:25

标签: c# multithreading sockets

Hello StackOverFlow社区,我正在开发一个C#程序,它取决于同一服务器的许多套接字连接。
我想在我的连接类上进行多线程处理,这样我就可以创建尽可能多的连接,而无需创建多个类。 但是Code会解释它的具体情况:
网关(连接线程)

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。 无论如何,我的问题是:我如何为Gateway做多线程,每个人都有自己的连接?

提前致谢。

1 个答案:

答案 0 :(得分:0)

所以我会这样做:

  1. 我会定义各种类:

    • 连接
    • 命令
    • ActionController的
    • GUI
  2. Connection类:

    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 GUI取决于你的想象力;)

  5. 我认为代码是一种不言自明的问题,如果有什么不清楚的话