Ошибка в методе Socket.Select(...)
От: Nickolay Ch  
Дата: 19.06.04 15:47
Оценка:
При написании проекта типа клинет-сервер возникла проблема:
Сервер для обслуживания клиентов применяет метод Socket.Select(IList checkRead, IList checkWrite, IList checkError, int microSeconds);
При подсоединении 64го клинента происходит обвал программы по IndexOutOfRangeException.
Ниэе приведу код модели сервера(просто слушат сокет, acceptит входящие коннекты и добавляет клиентские сокеты в ArrayList checkList для прослушки):
В качестве клиента использовался telnet.
64ый коннект — и валится. Обвал происходит в приватном методе Socketа: SocketListTofileDescriptorSet(...)
На microsoft.com глухо — ни слова об этом.
Декомпильнул mscorelib, и там прям в коде прошита константа: 64 — размер входного множества для Select.
Так что большее число клиентов обслужить с помощью Selecta неудасться.
Даже причина этому быда найдена в хелпе по Microsoft Winsock 2 для Delphi :

Four macros are defined in the header file WINSOCK2.H for manipulating and checking the descriptor sets. The variable FD_SETSIZE determines the maximum number of descriptors in a set. (The default value of FD_SETSIZE is 64, which can be modified by #defining FD_SETSIZE to another value before #including WINSOCK2.H.)

Так вот — при программировании под ВинАпи можно опеределить сколько проге надо сокетов послушать. Под .Нет выходит, что нельзя.
Вопрос — поделитесь кто-нить, пожалуйста опытом — как писать сервер, рассчитанный на большое число клиентов(~ неск. тысяч).
Модель — на каждого клиента заводится отдельный поток/процесс — не годится.

Код модели сервера:

using System;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Collections;

namespace TestSock
{
    /// <summary>
    /// Summary description for Class1.
    /// </summary>
    class Class1
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {            
                        IPHostEntry ipHostEntry = Dns.Resolve("localhost");
            IPAddress ipAddress = ipHostEntry.AddressList[0];

    
            ArrayList listenList = new ArrayList();
            ArrayList acceptList = new ArrayList();

            Socket sock = new Socket(AddressFamily.InterNetwork,
                SocketType.Stream,
                ProtocolType.Tcp);
            sock.Bind(new IPEndPoint(ipAddress, 11000));
            sock.Listen(10);
            
            string msg = "hello";
            byte [] bytes = Encoding.ASCII.GetBytes(msg);
            while (true)
            {
                try
                {
                    listenList.Add(sock);
                    Socket.Select(listenList, null, null, 1000);
                    try
                    {
                    
                        foreach (Socket s in listenList )
                        {
                            Socket conn = s.Accept();
                            acceptList.Add(conn);
                            conn.Send(bytes);
                            Console.WriteLine("Connected clients: {0}", acceptList.Count);                
                        }
                        listenList.Clear();
                        foreach(Socket s in acceptList )
                        {
                            listenList.Add(s);
                        }
                    }
                    catch(SocketException ex)
                    {
                    
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception occured: {0}\nStackTrace:{1}\nPress any key to continue", ex.Message, ex.StackTrace);
                    Console.ReadLine();
                    break;
                }
            }
        }
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.