Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > Котяра

Оценить эту запись

Тестовый сокет-сервер для Windows

Запись от Котяра размещена 05.12.2010 в 19:14
Обновил(-а) Котяра 06.12.2010 в 02:54

Не секрет, что для разработки суперприкольных и невероятно-многопользовательских реалтайм игр с гениальной механикой, разработчикам клиентской части не хватает умений реализовать и оттестировать сервер.

Мне этого тоже не хватало.
Представляю вашему вниманию тестовый сервер, а вернее целых 2!!!
Использование:
1. Скачайте архив.k0.zip
2. Распакуйте (желательно в c:\)
3. Если хотите тестить в локалке, то подправьте 2 конфиг файла для сервера и 1 для клиента


что вообще тут:

первый сервер - сервер отдачи кроссдомена.
запуск: \server\bin\crossdomain\start.bat
конфиги: \server\bin\crossdomain\kaon.ini

вообще там желательно менять только hostaddr=127.0.0.1 на ip компа в локалке, если будете тестить в локальной сети, если нет, то менять не надо.

второй сервер - сервер-ресивер данных
что делает: создаёт коннекты и каждое сообщение от клиентов передаёт всем подписавшимся клиентам.
Никакого парсинга не делает, поэтому данные могут быть в любом формате, кроме содержащих /0
запуск: \server\bin\server\start.bat
конфиги: \server\bin\server\server.ini

сервера специально разделил, ибо просто отдача кроссдомена - тоже нужная штука.

клиент - простой чат.
исходники клиента выложу позже (нет под рукой), а сервера не обещаю что выложу вообще, т.к. там используютя некие секретные сторонние разработки)))
UPD исходники клиента даю здесь текстом. Лень вытаскивать из проекта:
главный класс:
Код AS3:
package chat 
{
 
	/**
	 * ...
	 * @author k0t0vich
	 */
	public class Chat extends Sprite
	{
		private var urlLoader:URLLoader;
		private var configManager:ConfigManager;
		private var socketConnector:XMLSocketConnector = new XMLSocketConnector();
                // форматы сокета
		//private var socketConnector:SocketConnector = new SocketConnector();
		//private var socketConnector:ProtoBufConnector = new ProtoBufConnector();
                // гуй чата
		private var chatInput:ChatInput;
 
		public function Chat() 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
 
		private function init(e:Event=null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// поле чата и сообщений.
			addChild(new Output());
			chatInput = new ChatInput();
			addChild(chatInput);
			chatInput.addEventListener(DataEvent.DATA, sendToChat);
 
			loadConfig();
		}
 
		private function sendToChat(e:DataEvent):void 
		{
			socketConnector.send(e.data);
		}
 
		public function loadConfig():void
		{
			urlLoader = new URLLoader(new URLRequest("config.xml"));
			urlLoader.addEventListener(Event.COMPLETE, onLoadConfig);
		}
 
		private function onLoadConfig(e:Event):void 
		{
			configManager = new ConfigManager(XML(urlLoader.data));
			socketConnector.init(configManager);
			socketConnector.addEventListener(DataEvent.DATA, onSocketData);
			socketConnector.connect();
		}
 
		private function onSocketData(e:DataEvent):void 
		{
			Output.trace("message > " + e.data);
		}
 
	}
 
}
XMLSocketСonnector (чистый сокет и protobuf практически аналогичны)
Код AS3:
package server
 
	/**
	 * ...
	 * @author k0t0vich
	 */
	[Event(name="data", type="flash.events.DataEvent")]
	public class XMLSocketConnector extends EventDispatcher
	{
		private var configManager:ConfigManager;
		private var serverHost:String;
		private var serverPort:int;
		private var socket:XMLSocket;
		private var socketPolicyPort:int = 843;
		private var timer:Timer;
		private var session:String=null;
 
		public function XMLSocketConnector() 
		{
			super();
		}
 
		/**
		 * 
		 * @param	configManager
		 */
		public function init(configManager:ConfigManager):void	{
			this.configManager = configManager;
			serverHost = configManager.serverHost;
			serverPort = int(configManager.serverPort);
			socketPolicyPort = serverPort;
		}
 
		public function connect():void	{
			Output.trace("ServerConnector.connect");
			System.useCodePage = true;
			//Security.loadPolicyFile("xmlsocket://"+serverHost + ":" + socketPolicyPort);
			timer = new Timer(10, 1);
			timer.addEventListener(TimerEvent.TIMER, tryConnect);
			timer.start();
		}
 
 
		//--------------------------tryConnect---------------------------------------
		private function tryConnect(e:TimerEvent=null):void 
		{
			Output.trace("ServerConnector.tryConnect > e : " + e);
			timer.removeEventListener(TimerEvent.TIMER, tryConnect);
 
			socket = new XMLSocket();
			socket.addEventListener(Event.CONNECT, onTryConnect);
			socket.addEventListener(DataEvent.DATA, onTryData);
			socket.addEventListener(Event.CLOSE, onTryClose);
 
                        if (serverHost && serverPort) {
                           socket.connect(serverHost, socketPolicyPort);
                        }
		}
 
 
		private function onTryConnect(e:Event):void 
		{
			socket.removeEventListener(Event.CONNECT, onTryConnect);
			// посылаем первый пинг
			send("ping");
		}
 
		/**
		 * Хэндлер политики безопасности
		 * Запускаем основной коннект
		 * @param	e
		 */
		private function onTryClose(e:Event=null):void 
		{
			Output.trace("ServerConnector.onTryClose > e : " + e);
			socket.removeEventListener(Event.CLOSE, onTryClose);
			socket.removeEventListener(DataEvent.DATA, onTryData);
			socket.removeEventListener(Event.CONNECT, onTryConnect);
 
			baseConnect();
		}
 
		private function onTryData(e:DataEvent):void 
		{
			Output.trace("ServerConnector.onTryData > e : " + e);
			socket.close();
			onTryClose();
		}
 
 
		//--------------------------baseConnect---------------------------------------
 
		private function baseConnect():void
		{
			Output.trace("ServerConnector.baseConnect"); 
			configureListeners(socket);
                        socket.connect(serverHost, serverPort);
		}
 
 
 
 
		/**
		 * Посылка данных
		 * @param	data
		 */
		public function send(data:*):void {
                      socket.send(data);
                 }
 
 
		//----------------socket handlers---------------------------------------
		private function configureListeners(dispatcher:IEventDispatcher):void {
            dispatcher.addEventListener(Event.CLOSE, closeHandler);
            dispatcher.addEventListener(Event.CONNECT, connectHandler);
            dispatcher.addEventListener(DataEvent.DATA, dataHandler);
            dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
            dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
            dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
        }
 
 
        private function closeHandler(event:Event):void {
            Output.trace("closeHandler: " + event);
			// пробуем коннект после прихода политик
        }
 
        private function connectHandler(event:Event):void {
            Output.trace("connectHandler: " + event);
        }
 
        private function ioErrorHandler(event:IOErrorEvent):void {
            Output.trace("ioErrorHandler: " + event);
        }
 
        private function progressHandler(event:ProgressEvent):void {
            Output.trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
        }
 
        private function securityErrorHandler(event:SecurityErrorEvent):void {
            Output.trace("securityErrorHandler: " + event);
        }
 
		/**
		 *  Хэндлер сообщений
		 * @param	event
		 */
        private function dataHandler(event:DataEvent):void {
            //Output.trace("dataHandler: " + event);	
			dispatchEvent(new DataEvent(DataEvent.DATA, false, false, event.data));
        }
		//----------------socket handlers---------------------------------------
 
	}
 
}
Всякие служебные классы, вроде Output, ChatInput и ConfigManager пропускаю.. За чистоту кода тоже извините. Могут быть ошибки (например кроссдомен тут должен быть всегда на 843 и таймер не нужен для первого коннекта). Накидывал на скорую руку методом копипастинга

Пример "прослойки" скоро будет, если у меня не будет авралов. Пожелайте мне удачи)
Размещено в игродел
Комментарии 11 Отправить другу ссылку на эту запись
Всего комментариев 11

Комментарии

Старый 05.12.2010 19:17 iNils вне форума
iNils
 
Аватар для iNils
Я так понимаю, что ничего ставить не нужно, для того, чтобы это работало?
Старый 05.12.2010 19:18 Котяра вне форума
Котяра
 
Аватар для Котяра
Нет. Просто распаковать. Нужные dll лежат рядом.
Если возникут какие нибудь проблемы, просьба описать.
Обновил(-а) Котяра 05.12.2010 в 19:21
Старый 05.12.2010 19:19 iNils вне форума
iNils
 
Аватар для iNils
Супер!
Старый 05.12.2010 19:49 Котяра вне форума
Котяра
 
Аватар для Котяра
Вообще это обрезанная и адаптированная под винду часть сервера на плюсах. Нагрузочные тесты показали хорошие результаты.

Кроме того это часть глобальной идеи которая перевернёт мир серверов для игр и вытеснит SmartFox))))
Идея в том что между приёмом и отправкой можно отправлять данные другому серверу, который будет их парсить.
вместо клиент1- > сервер1- > клиент1... клиентN
будет клиент1- > сервер1- >логика-> сервер1-> клиент1... клиентN
прослойку логики подключаем на некий порт/адрес, который может быть вообще на другом сервере и написан на любом я зыке.
Кстати, аналогичный функционал на Эрланге проиграл по тестам(тесты конечно были узконаправленными на конкретную ситуацию). Си - быстрее. Но именно Эрланг сподвиг меня на такое архитектурное решение. Мне понравилась идея отказа от ссылок. События и сообщения - наше всё.

Даже сейчас можно прослойку логики реализовать на as.
Т.е. это будет некий серверный клиент.
Пример выложу, если дойдут руки.
По мне очень удобно; пример: Я описал логику, оттестировал и предоставил исходники серверному программисту. Он просто перевёл её на плюсы и завёл нужные данные в БД.

Изврат:
Я запускаю 2 сервера на локалке (кроссдомен, и сервер) затем запускаю псевдосервер.swf (слой логика)
затем подключаются клиенты.
Псевдосервер читает шареды(псевдо БД) и рассылает авторизованным клиентам их данные, потом он фильтрует данные от реального сервера и отсылает откорректированныесвои. Клиенты хотя и принимают все данные, парсят только с пометкой ("от псевдосервера")
На релизе, конечно это глупость, но для тестов офигенно.
В реале - настоящий сервер не будет посылать эхо всем клиентам, а только сообщения от логики.
Я мог бы и в тестовый сервер внести такую фичу, но это сразу подразумевает парсинг сообщений сервером, что мне совсем не подходит (вернее не подходит под условия задачи: сделать тестовый сервер для любых протоколов).
Обновил(-а) Котяра 06.12.2010 в 03:04
Старый 05.12.2010 20:02 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Здорово!
Старый 05.12.2010 22:15 iNils вне форума
iNils
 
Аватар для iNils
Неплохо бы сделать пример работы с прослойкой на as.
Старый 06.12.2010 08:19 alexcon314 вне форума
alexcon314
Ну, вот, бубен таки нашелся?
Старый 07.12.2010 17:11 Хемуль вне форума
Хемуль
 
Аватар для Хемуль
2 Котяра:
Неплохо. Полезно.
Старый 14.12.2010 18:49 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
Вот простите за нубский вопрос. Если у меня есть хост, на нём работает php, mysql и т.д. Возможно ли как то запустить на нём такой сокет сервер, и как это сделать? Или всё таки нужен выделенный сервер? Просто погуглив вариант 2 мне вышли цены в раёне тысяч $ в месяц((
Старый 14.12.2010 22:37 Котяра вне форума
Котяра
 
Аватар для Котяра
Ну вы можете запустить сервер у себя на машине если есть выделенный ip.
А так простой виртуальный сервер за 5 баксов в месяц вряд ли подойдёт.
можно и за 100$ взять, можно и дешевле.
Старый 13.07.2011 00:32 leo150 вне форума
leo150
а где взять ConfigManager? без него можно обойтись?
 

 


Часовой пояс GMT +4, время: 13:20.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.