简体   繁体   English

C#套接字服务器-并发连接问题

[英]C# Socket Server - Issue with Concurrent Connections

hey all, I have made a socket server in C# for a flash game that I am developing, I got the code from somewhere and I am a beginner in c# and .net development . 嘿,我已经用C#为正在开发的Flash游戏制作了一个套接字服务器,我从某个地方获得了代码,并且我是c#和.net开发的初学者。 It works fine in practice when connections are made and the server functions correctly. 实际上,当建立连接并且服务器正常运行时,它可以正常工作。 Get 2 concurrent connections at the same time and we have a problem. 同时获得2个并发连接,我们遇到了问题。

here is the basic aspects of the socket server below: (alot taken out for obvious reasons) 以下是套接字服务器的基本方面:(出于明显的原因而取出)

how can I alter this so that it can handle concurrent connections? 我怎样才能改变它,使其可以处理并发连接? Should I be threading each response? 我应该在每个响应中添加线索吗?

Thanks 谢谢

class TcpSock { int tcpIndx = 0; int tcpByte = 0;

  byte[] tcpRecv = new byte[1024]; //////////////////////////////////////// public Socket tcpSock; //////////////////////////////////////// public int Recv(ref string tcpRead) { tcpByte = tcpSock.Available; if (tcpByte > tcpRecv.Length - tcpIndx) tcpByte = tcpRecv.Length - tcpIndx; tcpByte = tcpSock.Receive(tcpRecv, tcpIndx, tcpByte, SocketFlags.Partial); tcpRead = Encoding.ASCII.GetString (tcpRecv, tcpIndx, tcpByte); tcpIndx += tcpByte; return tcpRead.Length; } public int RecvLn(ref string tcpRead) { tcpRead = Encoding.ASCII.GetString (tcpRecv, 0, tcpIndx); tcpIndx = 0; return tcpRead.Length; } public int Send(string tcpWrite) { return tcpSock.Send(Encoding.ASCII.GetBytes(tcpWrite)); } public int SendLn(string tcpWrite) { return tcpSock.Send(Encoding.ASCII.GetBytes(tcpWrite + "\\r\\n")); } } 

[STAThread] static void Main() {

  Thread Server1 = new Thread(RunServer); Server1.Start(); } static void RunServer() { ///class IPHostEntry : Stores information about the Host and is required ///for IPEndPoint. ///class IPEndPoint : Stores information about the Host IP Address and ///the Port number. ///class TcpSock : Invokes the constructor and creates an instance. ///class ArrayList : Stores a dynamic array of Client TcpSock objects. IPHostEntry Iphe = Dns.Resolve(Dns.GetHostName()); IPEndPoint Ipep = new IPEndPoint(Iphe.AddressList[0], 4444); Socket Server = new Socket(Ipep.Address.AddressFamily,SocketType.Stream, ProtocolType.Tcp); ///Initialize ///Capacity : Maximux number of clients able to connect. ///Blocking : Determines if the Server TcpSock will stop code execution ///to receive data from the Client TcpSock. ///Bind : Binds the Server TcpSock to the Host IP Address and the Port Number. ///Listen : Begin listening to the Port; it is now ready to accept connections. ArrayList Client = new ArrayList(); string[,] Users = new string[1000,9]; string rln = null; string[] Data; Client.Capacity = 1000; Server.Blocking = false; Server.Bind(Ipep); Server.Listen(32); Console.WriteLine("Server 1 {0}: listening to port {1}", Dns.GetHostName(), Ipep.Port); //////////////////////////////////////////////////////////////////////////////////////////// ///Main loop ///1. Poll the Server TcpSock; if true then accept the new connection. ///2. Poll the Client TcpSock; if true then receive data from Clients. while (true) { //Accept - new connection #region new connection if (Server.Poll(0, SelectMode.SelectRead)) { int i = Client.Add(new TcpSock()); ((TcpSock)Client[i]).tcpSock = Server.Accept(); Console.WriteLine("Client " + i + " connected."); Users[i, 0] = i.ToString(); } #endregion for (int i = 0; i < Client.Count; i++) { //check for incoming data if (((TcpSock)Client[i]).tcpSock.Poll(0, SelectMode.SelectRead)) { //receive incoming data if (((TcpSock)Client[i]).Recv(ref rln) > 0) { Console.WriteLine(rln.ToString()); Data = rln.Split('|'); // 1) initial connection #region InitialConnection if (Data[0] == "0000") { } } } } } 

}

您无需使用同步函数,而可以使用诸如Socket.BeginReceive之类的异步函数。

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
public static partial class TcpServer
{
    public static void Main()
    {
        // Setup listener on "localhost" port 12000
        IPAddress ipAddr = Dns.GetHostEntry("localhost").AddressList[0];
        TcpListener server = new TcpListener(ipAddr, 12000);
        server.Start(); // Network driver can now allow incoming requests 

        // Accept up to 1 client per CPU simultaneously
        Int32 numConcurrentClients = Environment.ProcessorCount;

        for (Int32 n = 0; n 

    private static Byte[] ProcessData(Byte[] inputData)
    {
        String inputString = Encoding.UTF8.GetString(inputData, 1, inputData[0]);
        String outputString = inputString.ToUpperInvariant();

        Console.WriteLine("Input={0}", inputString);
        Console.WriteLine("   Output={0}", outputString);
        Console.WriteLine();

        Byte[] outputStringBytes = Encoding.UTF8.GetBytes(outputString);
        Byte[] outputData = new Byte[1 + outputStringBytes.Length];
        outputData[0] = (Byte)outputStringBytes.Length;
        Array.Copy(outputStringBytes, 0, outputData, 1, outputStringBytes.Length);
        return outputData;
    }
}
public static partial class TcpServer
{
    private sealed class ClientConnectionApm
    {
        private TcpListener m_server;
        private TcpClient m_client;
        private Stream m_stream;
        private Byte[] m_inputData = new Byte[1];
        private Byte m_bytesReadSoFar = 0;
        public ClientConnectionApm(TcpListener server)
        {
            m_server = server;
            m_server.BeginAcceptTcpClient(AcceptCompleted, null);
        }
        private void AcceptCompleted(IAsyncResult ar)
        {
            // Connect to this client
            m_client = m_server.EndAcceptTcpClient(ar);

            // Accept another client
            new ClientConnectionApm(m_server);

            // Start processing this client
            m_stream = m_client.GetStream();
            // Read 1 byte from client which contains length of additional data
            m_stream.BeginRead(m_inputData, 0, 1, ReadLengthCompleted, null);
        }
        private void ReadLengthCompleted(IAsyncResult result)
        {
            // If client closed connection; abandon this client request
            if (m_stream.EndRead(result) == 0) { m_client.Close(); return; }

            // Start to read 'length' bytes of data from client
            Int32 dataLength = m_inputData[0];
            Array.Resize(ref m_inputData, 1 + dataLength);
            m_stream.BeginRead(m_inputData, 1, dataLength, ReadDataCompleted, null);
        }
private void ReadDataCompleted(IAsyncResult ar) { // Get number of bytes read from client Int32 numBytesReadThisTime = m_stream.EndRead(ar); // If client closed connection; abandon this client request if (numBytesReadThisTime == 0) { m_client.Close(); return; } // Continue to read bytes from client until all bytes are in m_bytesReadSoFar += (Byte)numBytesReadThisTime; if (m_bytesReadSoFar private void WriteDataCompleted(IAsyncResult ar) { // After result is written to client, close the connection m_stream.EndWrite(ar); m_client.Close(); } } }

First of all: Stop using non-blocking sockets. 首先:停止使用非阻塞套接字。 In .NET you should either stick to the synchronous methods Receive / Send or asynchronous methods BeginReceive / BeginSend . 在.NET中,您应该坚持使用同步方法Receive / Send或异步方法BeginReceive / BeginSend

You should only stick with sync methods if you will have only a handful of clients. 如果只有少数几个客户端,则只应坚持使用同步方法。 Then launch each new client in a new thread. 然后在新线程中启动每个新客户端。 This is the easiest option to get everthing running. 这是一切运行的最简单选择。

Simply do like this: 只需这样做:

public void AcceptClients()
{
     TcpListener listener = new TcpListener(IPAddress.Any, 5566);
     listener.Start();

     while (_serverRunning)
     {
          var socket = listener.AcceptSocket();
          new Thread(ClientFunc).Start(socket);
     }
}

public void ClientFun(object state)
{
    var clientSocket = (Socket)state;
    var buffer = new byte[65535];
    while (_serverRunning)
    {
        //blocking read.
        clientSocket.Receive(buffer, 0, buffer.Length, SocketFlags.None);

        //check packet.

        // handle packet

        // send respons.
        clientSocket.Send(alalalal);
    }
}

You should refactor the methods so that they follow SRP. 您应该重构这些方法,以便它们遵循SRP。 The code is just a small guide to get you going. 该代码只是帮助您入门的一个小指南。

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

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