Форум программистов, компьютерный форум, киберфорум
C# .NET
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.63/8: Рейтинг темы: голосов - 8, средняя оценка - 4.63
28 / 29 / 3
Регистрация: 26.07.2010
Сообщений: 297
1
.NET 4.x

Оптимизация кода сервера (игра "Мафия")

12.06.2012, 14:52. Показов 1580. Ответов 5
Метки нет (Все метки)

Здравствуйте, пишу сервер для игры мафия.
Я только начал, так что это ещё не весь код. Подскажите пожалуйста, можно ли его как-нибудь оптимизировать? Сервер пишу впервые.
Если вкратце, то создаю отдельный поток, в котором принимаю клиентов в бесконечном цикле, их добавляю в Queue для обработки и в List для посылания сообщений, всяких данных и т.д.
В основном потоке в бесконечном цикле, если Queue пуст, то ждем 100 миллисекунд и начинаем цикл с начала. Если Queue не пуст, то в отдельном потоке запускаю метод для его обработки.
Вот сам код:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Net;
using System.Net.Sockets;
 
namespace Mafia_Server
{
    class Program
    {
        public static List<TcpClient> ClientList=new List<TcpClient>();  //Список подключённых клиентов
        public static Queue<TcpClient> ClientQueue=new Queue<TcpClient>();  //Для работы с клиентами
        private static TcpListener _bossHostListener;
        static void Main(string[] args)
        {
            _bossHostListener = Initializate(); //Возвращает TcpListener
            _bossHostListener.Start(10);
            Task clientAccepter=new Task(AcceptTcpClient); //Прослушиваем и принимаем в отдельном потоке
            clientAccepter.Start();
            while(true)
            {
                if(ClientQueue.Count==0)
                {
                    Thread.Sleep(100);
                    continue;
                }
                Task manageConnectionTask=new Task(ManagingConnections);
                manageConnectionTask.Start();
            }
        }
 
 
 
 
        /// <summary>
        /// Создаёт сокет
        /// </summary>
        /// <returns>Возвращает созданный сокет</returns>
        public static TcpListener Initializate()
        {
            Console.WriteLine("Вычисляю IP...");
            string hostIp = GetIpAddres();
            if (hostIp == "Error")
            {
                Console.WriteLine("Ошибка вычисления IP-адреса\n" +
                                  "Введите вручную (Пример: 192.168.0.1):");
                hostIp = Console.ReadLine();
            }
            try
            {
                IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse(hostIp), 8000);
                TcpListener hostListener = new TcpListener(endPoint);
                Console.WriteLine("Подключаться на "+endPoint.Address+":"+endPoint.Port);
                return hostListener;
            }
            catch (SocketException socketException)
            {
                Console.WriteLine("Не удалось создать сокет (Error: {0}): {1}", socketException.ErrorCode, socketException.Message);
                TcpListener hostListener=new TcpListener(IPAddress.Any,8000);
                Console.WriteLine("Буду слушать все сетевые интерфейсы на 8000 порту");
                return hostListener;
            }   
        }
 
        /// <summary>
        /// Получает IP-адрес с [url]http://checkip.dyndns.org/[/url]
        /// </summary>
        /// <returns>IP-адрес</returns>
        private static string GetIpAddres()
        {
            try
            {
                string ip = null;
                WebRequest requesToMyIp = WebRequest.Create("http://checkip.dyndns.org/");
                WebResponse responseMyIp = requesToMyIp.GetResponse();
                Stream amFromMyIp = responseMyIp.GetResponseStream();
                if (amFromMyIp != null)
                {
                    StreamReader streamFromMyIp = new StreamReader(amFromMyIp);
                    ip = new Regex(@"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})").Match(streamFromMyIp.ReadToEnd()).ToString();
                }
                return ip;
            }
            catch (Exception)
            {
                return "Error";
            }
        }
 
 
        /// <summary>
        /// Управляет получеными клиентами
        /// </summary>
        /// <param name="client">Клиент, с которым необходимо взаимодействие</param>
        public static void ManagingConnections()
        {
            if(ClientQueue.Count==0) return;
            TcpClient client = ClientQueue.Dequeue();
            if(client==null) return;
            Stream writerStream = client.GetStream();
            StreamReader readerStream=new StreamReader(client.GetStream());
            //тут потом будет код обработки
        }
 
 
        /// <summary>
        /// Асинхронно принимает клиентов и добавляет в List и Queue
        /// </summary>
        public static void AcceptTcpClient()
        {
            while (true)
            {
                Console.WriteLine("Ожидание новых подключений");
                TcpClient client = _bossHostListener.AcceptTcpClient();
                ClientList.Add(client);  
                ClientQueue.Enqueue(client);
                Console.WriteLine("//Новый клиент подключён");
            }
        }
    }
}
0

Помощь в написании контрольных, курсовых и дипломных работ здесь.

Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
12.06.2012, 14:52
Ответы с готовыми решениями:

Ошибка после конвертации метода на С++ к С#: "Неявное преобразование типа "int" в "bool" невозможно"
Ошибка после преобразования метода на С++ к С#: &quot;Неявное преобразование типа &quot;int&quot; в &quot;bool&quot;...

Игра "Трубопровод". Как сделать проверку трубопровода на связность
Всем привет. Пишу игру &quot;Трубопровод (Ветка)&quot;. Игра будет консольная. Имеется два вопроса. ...

Ошибка CS0019: Оператор "*" не может применяться к операндам типа "decimal" и "float"
Здравствуйте! Писал приложение и наткнулся на интересную ошибку (честно говоря, я не совсем понимаю...

Игра "Трубопровод": как сделать разъединение труб
Добрый день. Пишу игру Трубопровод. http://home.earthlink.net/~tdglenn/unicorn/pipegame.htm. Не...

5
152 / 152 / 30
Регистрация: 19.10.2009
Сообщений: 319
12.06.2012, 16:28 2
Первое, на что хочется обратить внимание (даже не совсем оптимизация) - ни разу не вызывается метод Dispose, т. е. явно создаётся утечка памяти и прочие неосвобождённые ресурсы. Для этого есть оператор using, вот его пример:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try
            {
                string ip = null;
                WebRequest requesToMyIp = WebRequest.Create("http://checkip.dyndns.org/");
                using (WebResponse responseMyIp = requesToMyIp.GetResponse())
                using (Stream amFromMyIp = responseMyIp.GetResponseStream())
          if (amFromMyIp != null)
          {
                    using (StreamReader streamFromMyIp = new StreamReader(amFromMyIp))
              ip = new Regex(@"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})").Match(streamFromMyIp.ReadToEnd()).ToString();
          }
                return ip;
            }
            catch (Exception)
            {
                return "Error";
            }
Рекомендую просмотреть все методы, и где есть интерфейс IDisposable, не забывать его ставить.

Непосрественно по оптимизации. Если цель строк выше - просто узнать IP, то в классе DNS такой метод есть. Ожидание через Thread.Sleep - не лучший метод взаимодействия потоков. Лучше использовать EventWaitHandle, создать его можно с параметром ResetMode.Auto, в методе AcceptTcpClient делать Set, а в безымянном методе внутри Main вместо Thread.Sleep поставить его метод WaitOne. То что список клиентов только пополняется, но из него ничего не удаляется, полагаю, что временно, но важно не забыть где-то его и очищать, иначе оперативная память переполнится.
1
28 / 29 / 3
Регистрация: 26.07.2010
Сообщений: 297
12.06.2012, 17:05  [ТС] 3
Цитата Сообщение от Ilya81 Посмотреть сообщение
Если цель строк выше - просто узнать IP, то в классе DNS такой метод есть.
Знаю, но он возвращает 6 адресов (у меня), 4 из которых IPv6 и 2 обычных - один локальный, другой глобальный

Цитата Сообщение от Ilya81 Посмотреть сообщение
Ожидание через Thread.Sleep - не лучший метод взаимодействия потоков.
Просто без этого сервер отъедает от процессора 1/4 (Core i5 2430m)

Цитата Сообщение от Ilya81 Посмотреть сообщение
Лучше использовать EventWaitHandle, создать его можно с параметром ResetMode.Auto, в методе AcceptTcpClient делать Set, а в безымянном методе внутри Main вместо Thread.Sleep поставить его метод WaitOne.
А не можете показать на примере, а то я не очень понимаю, что это значит
Цитата Сообщение от Ilya81 Посмотреть сообщение
То что список клиентов только пополняется, но из него ничего не удаляется
В процессе
0
152 / 152 / 30
Регистрация: 19.10.2009
Сообщений: 319
12.06.2012, 17:26 4
Собственно EventWaitHandle прямо здесь (с ним, думаю, сервер будет отъедать даже меньше процессора, чем с Thread.Sleep). Объявляем:
C#
1
private static EventWaitHandle _wait = new EventWaitHandle(ResetMode.Auto, false);
Ждём таким образом (за счёт этого и нагрузка на процессор сократится, что не будет выхода без необходимости):
C#
1
2
3
4
5
6
7
8
9
10
11
            while(true)
            {
                _wait.WaitOne();
                if(ClientQueue.Count==0)
                {
                    //Thread.Sleep(100); - это больше не нужно
                    continue;
                }
                Task manageConnectionTask=new Task(ManagingConnections);
                manageConnectionTask.Start();
            }
А отмашку даём так:
C#
1
2
3
4
5
6
7
8
9
10
11
12
        public static void AcceptTcpClient()
        {
            while (true)
            {
                Console.WriteLine("Ожидание новых подключений");
                TcpClient client = _bossHostListener.AcceptTcpClient();
                ClientList.Add(client);  
                ClientQueue.Enqueue(client);
        _wait.Set();
                Console.WriteLine("//Новый клиент подключён");
            }
        }
1
28 / 29 / 3
Регистрация: 26.07.2010
Сообщений: 297
12.06.2012, 19:32  [ТС] 5
Ilya81, а позволь спросить, в чём отличие между WaitHandle и EventWaitHandle?
0
152 / 152 / 30
Регистрация: 19.10.2009
Сообщений: 319
12.06.2012, 20:04 6
Вообще, WaitHandle, если посмотреть по документации - абстрактный класс, т. е. его экземпляр создать нельзя. EventWaitHandle наследуется от него, заодно с Mutex и Semaphore. Так что разницы меньше между Mutex и EventWaitHandle (если учесть, что класс Semaphore позволяет реализовывать количество объектов одновременного доступа больше единицы), по большому счёту у них только принципы использования разные. Но в самом WaitHandle есть ряд методов, скажем, WaitAll (это если б, например, нужно было б, чтоб пришли запросы с двух адресов/портов для обработки данных), для которых, соотвественно, годятся все наследуемые от него классы.
1
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
12.06.2012, 20:04

Оператор ">" невозможно применить к операнду типа "IContainer" и "<NULL>".
// Оператор &quot;&gt;&quot; невозможно применить к операнду типа &quot;IContainer&quot; и &quot;&lt;NULL&gt;&quot;. if...

В программе должен быть создан всего лишь один объект "Игра" на все 10 одновременно ведущихся игр
Доброго времени суток. На екзамен очень нужна прога. Задание такое: Модифицировать...

Мониторинг состояния сервера "по взрослому"
Всем доброго времени суток! :) Сразу к делу. Хочу написать программу на C# которая умеет: ...

Переопределить операции "+" "=" "-" для экземпляров моего класса
Добрый день. Мне нужно переопределить операции &quot;+&quot; &quot;=&quot; &quot;-&quot; для экземпляров моего класса. Я вижу это...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.