серверный движок

Сеть в Unity3D

серверный движок

Сообщение -Шум- 31 май 2017, 06:04

привет у меня такой вопрос, делаю игру и пишу собственный серверный движок. подскажите в правильном ли я направлении двигаюсь? подойдет ли данный подход для написания своих серверов (чат, авторизация, игровой сервер)?
вот пример кода сервера авторизации который я набросал
Синтаксис:
Используется csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace autorization
{
    class Program
    {
        static string log = null;
        static string pas = null;

        static void Main(string[] args)
        {
            start_server();
        }

        static void start_server()
        {
            // Устанавливаем для сокета локальную конечную точку
            IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8005);

            // Создаем сокет Tcp/Ip
            Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // Назначаем сокет локальной конечной точке и слушаем входящие сокеты
            try
            {
                server.Bind(ipPoint);
                server.Listen(10);
                Console.WriteLine("Сервер запущен.");
                // Начинаем слушать соединения
                while (true)
                {
                    Console.WriteLine("Ожидаем соединение через порт {0}", ipPoint);
                    // Программа приостанавливается, ожидая входящее соединение
                    Socket client = server.Accept();
                    // Мы дождались клиента, пытающегося с нами соединиться
                    byte[] receive = new byte[1024];
                    for (int i = 0; i < receive.Length; i++) { receive[i] = 0; }
                    client.Receive(receive);

                    string message = Encoding.UTF8.GetString(receive);
                    //Указываем на конец строки с нужными данными
                    int count = message.IndexOf(";;;5");
                    if (count == -1) { continue; }
                    //Создаем переменную, в которой будет храниться очищенное сообщение
                    string clear_message = "";
                    for (int i = 0; i < count; i++) { clear_message += message[i]; }
                    //Начинаем делить очищенное сообщение на отдельные части
                    string[] split = clear_message.Split(':');

                    log = split[0];
                    pas = split[1];

                    Console.WriteLine("Подключение клиента: " + "Логин: " + log + " Пароль: " + pas);

                    if (log == "admin" && pas == "1234")
                    {
                        Console.WriteLine("Данные успешно подтверждены.");
                        // Отправляем ответ клиенту
                        string msg = "yes" + ";;;5";
                        byte[] send = new byte[1024];
                        send = Encoding.UTF8.GetBytes(msg);
                        client.Send(send);
                    }
                    else
                    {
                        Console.WriteLine("Указанные Логин или Пароль не найдены в Базе Данных.");
                        // Отправляем ответ клиенту
                        string msg = "no" + ";;;5";
                        byte[] send = new byte[1024];
                        send = Encoding.UTF8.GetBytes(msg);
                        client.Send(send);
                    }
 
                    Console.WriteLine("Сервер завершил соединение с клиентом.");
                    client.Shutdown(SocketShutdown.Both);
                    client.Close();
                }
            }
            catch (Exception ex) { Console.WriteLine(ex.ToString()); }
        }
    }
}

 
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение Ert Donuell 31 май 2017, 06:38

Не очень грамотный подход. Много ошибок новичка. Попробуйте использовать существующее решение - сэкономите годы, разберётесь быстрее. Поэкспериментируйте с сеткой юнити, например.
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

Re: серверный движок

Сообщение -Шум- 31 май 2017, 10:38

Ert Donuell писал(а):Не очень грамотный подход. Много ошибок новичка. Попробуйте использовать существующее решение - сэкономите годы, разберётесь быстрее. Поэкспериментируйте с сеткой юнити, например.


я нехочу использовать юнет, фотон + хотелось бы писать код на C#
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение Woolf 31 май 2017, 13:34

фотон на сишарпе. Если не хочется его использовать, учитесь пару лет писать сервера. В помощь вам многопоточность, неблокируемые сокеты, очереди обработки, и многое, многое другое. С сервером, как с юнити, не выйдет, написал метод и готово. Серверная механика весьма требовательна как к качеству кода, так и к его чистоте. Это задача совсем не для новичков, так что, вы взяли ношу не по себе, как мне кажется.

Это я вам как профессионал говорю )) Я писал промышленные сервера 8 лет, мои "изделия" до сих пор работают в медицине Германии, беларуском КГБ и на валютно фондовой бирже, но я все равно использую фотон. Просто потому, что это дешевле и удобнее, чем изобретать очередной велосипед.
Разработчик theFisherOnline - там, где клюёт
Разработчик Atom Fishing II - Первая 3D MMO про рыбалку
Разработчик Atom Fishing - Рыбалка на поплавок, донку, нахлыст, блесну в постъядерный период.
Аватара пользователя
Woolf
Адепт
 
Сообщения: 7179
Зарегистрирован: 02 мар 2009, 16:59

Re: серверный движок

Сообщение -Шум- 31 май 2017, 13:44

Woolf писал(а):фотон на сишарпе. Если не хочется его использовать, учитесь пару лет писать сервера. В помощь вам многопоточность, неблокируемые сокеты, очереди обработки, и многое, многое другое. С сервером, как с юнити, не выйдет, написал метод и готово. Серверная механика весьма требовательна как к качеству кода, так и к его чистоте. Это задача совсем не для новичков, так что, вы взяли ношу не по себе, как мне кажется.

Это я вам как профессионал говорю )) Я писал промышленные сервера 8 лет, мои "изделия" до сих пор работают в медицине Германии, беларуском КГБ и на валютно фондовой бирже, но я все равно использую фотон. Просто потому, что это дешевле и удобнее, чем изобретать очередной велосипед.


избегая проблем ничему не научишься, я просто сейчас немогу в голове представить как это реализовывается, правильно ли то что я устанавливаю свзять через сокеты таким путем? стоит ли мне исспользовать методы Send \ Recieve для отправки \ приема сообшений или же нужно писать собственные?
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение Tolking 31 май 2017, 14:21

Не ищи легких путей! Пиши свое на брейнфаке!!!
Ковчег построил любитель, профессионалы построили Титаник.
Аватара пользователя
Tolking
Адепт
 
Сообщения: 2715
Зарегистрирован: 08 июн 2009, 18:22
Откуда: Тула

Re: серверный движок

Сообщение -Шум- 31 май 2017, 14:38

Tolking писал(а):Не ищи легких путей! Пиши свое на брейнфаке!!!

никто не ищет лёгких путей, хочу обойтись с#. крайний случай java
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение Ert Donuell 01 июн 2017, 01:57

Вы каждый раз открываете новое соединение для получения данных. Вы каждый раз парсите строку. Вы используете кастомный набор символов для определения конца строки. У Вас полно хардкода. Вместо булевых переменных Вы используете строки. При исключении SocketError: ConnectionReset Ваш сервер загнётся. Каждый раз Вы создаёте массив receive. Каждый раз Вы его зачем-то обнуляете его. Мало того - вместо Array.Clear(receive, 0, receive.Length), Вы делаете это вручную. Зачем-то по букве копруете message в clear_message.

Реально - посмотрите те же примеры фотона, UNet. И фиг, что не будете их юзать - так хоть логику углядите. Как это обычно делают. Покопайтесь в исходниках Lidgren, наконец! Хотя в там тоже, кхм..
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

Re: серверный движок

Сообщение -Шум- 01 июн 2017, 11:04

Ert Donuell писал(а):Вы каждый раз открываете новое соединение для получения данных. Вы каждый раз парсите строку. Вы используете кастомный набор символов для определения конца строки. У Вас полно хардкода. Вместо булевых переменных Вы используете строки. При исключении SocketError: ConnectionReset Ваш сервер загнётся. Каждый раз Вы создаёте массив receive. Каждый раз Вы его зачем-то обнуляете его. Мало того - вместо Array.Clear(receive, 0, receive.Length), Вы делаете это вручную. Зачем-то по букве копруете message в clear_message.

Реально - посмотрите те же примеры фотона, UNet. И фиг, что не будете их юзать - так хоть логику углядите. Как это обычно делают. Покопайтесь в исходниках Lidgren, наконец! Хотя в там тоже, кхм..

спасибо, буду думать
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение maksimov 01 июн 2017, 14:02

Woolf писал(а):фотон на сишарпе. ...
Это я вам как профессионал говорю )) Я писал промышленные сервера 8 лет, мои "изделия" до сих пор работают в медицине Германии, беларуском КГБ и на валютно фондовой бирже, но я все равно использую фотон.


Photon написан на С++. На C# написан фреймворк приложений работающих на Photon.

Как-то это всё грустно...


А парень молодец (если конечно это он сам написал, а не скопипастил откуда-нибудь). Правильно делает. Жаль будет, если вы тут "научите его плохому", и он пополнит ряды инфантильных "пользователей технологий, без понимания как они работают". =(
Красота — не прихоть полубога, а хищный глазомер простого столяра.
Аватара пользователя
maksimov
UNITрон
 
Сообщения: 154
Зарегистрирован: 19 фев 2013, 11:48
  • Сайт

Re: серверный движок

Сообщение -Шум- 01 июн 2017, 15:12

maksimov писал(а):
Woolf писал(а):фотон на сишарпе. ...
Это я вам как профессионал говорю )) Я писал промышленные сервера 8 лет, мои "изделия" до сих пор работают в медицине Германии, беларуском КГБ и на валютно фондовой бирже, но я все равно использую фотон.


Photon написан на С++. На C# написан фреймворк приложений работающих на Photon.

Как-то это всё грустно...


А парень молодец (если конечно это он сам написал, а не скопипастил откуда-нибудь). Правильно делает. Жаль будет, если вы тут "научите его плохому", и он пополнит ряды инфантильных "пользователей технологий, без понимания как они работают". =(

пока работаю по примерам, пытаюсь понять суть что да как, переделывая код под себя, вот кстати я тут переделал код посмотрите стал ли он лучше?вот сервер:
Синтаксис:
Используется csharp
[syntax=csharp]using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
 
namespace LoginServer
{
    class Program
    {
        const int PORT = 5006;       // порт для прослушивания подключений
        static TcpListener listener; // создаем переменную класа TcpListener
 
        static void Main(string[] args)
        {
            try
            {
                listener = new TcpListener(IPAddress.Parse("127.0.0.1"), PORT); //прослушиваем входящие подключения по порту "PORT"
                listener.Start();
                Console.WriteLine("Ожидание подключений...");
 
                while (true)
                {
                    TcpClient client = listener.AcceptTcpClient();
                    ClientObject clientObject = new ClientObject(client);
 
                    // создаем новый поток для обслуживания нового клиента
                    Task clientTask = new Task(clientObject.Working);
                    clientTask.Start();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
            finally
            {
                if (listener != null)
                    listener.Stop();
            }
        }
    }
    class Account
    {
        public Account(string login, string password)
        {
            this.log = login;
            this.pas = password;
            this.msg = "server ok".ToString();
        }
        public string log { get; private set; } //логин
        public string pas { get; private set; } //пароль
        public string msg { get; private set; } //сообщение
    }
    class ClientObject
    {
        public TcpClient client;
        public ClientObject(TcpClient tcpClient)
        {
            client = tcpClient;
        }
        public void Working()
        {
            NetworkStream stream = null;
            try
            {
                stream = client.GetStream();
                BinaryReader reader = new BinaryReader(stream);
                //считываем данные их потока
                string lg = reader.ReadString();
                string ps = reader.ReadString();
                //создаем по полученным данным объект аккаунт
                Account account = new Account(lg, ps);
 
                Console.WriteLine("подключение клиента: {0}, пароль: {1}", account.log, account.pas);
 
                //отправляем ответ клиенту
                BinaryWriter writer = new BinaryWriter(stream);
                writer.Write(account.msg);
                writer.Flush();
 
                writer.Close();
                reader.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
 
            finally
            {
                if (stream != null)
                    stream.Close();
                if (client != null)
                    client.Close();
            }
        }
    }
}[/syntax]

вот клиент:
Синтаксис:
Используется csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Net;
using System.Net.Sockets;
using System.Text;
using UnityEngine.SceneManagement;
using System;
using System.IO;
public class ScriptLoad01 : MonoBehaviour
{
    public InputField InputBox1;
    public InputField InputBox2;
    public GameObject ErrorPanel;
    const int PORT = 5006;
    const string ADDRESS = "127.0.0.1";
 
    public void OnClick()
    {
        string log = InputBox1.text;
        string pas = InputBox2.text;
 
        TcpClient client = null;
 
        try
        {
            string login = log;
            string password = pas;
 
            client = new TcpClient(ADDRESS, PORT);
            NetworkStream stream = client.GetStream();
 
            BinaryWriter writer = new BinaryWriter(stream);
            writer.Write(login);
            writer.Write(password);
            writer.Flush();
 
            BinaryReader reader = new BinaryReader(stream);
            string msg = reader.ReadString();
 
            if (msg == "server ok")
            {
                SceneManager.LoadScene(1);
            }
            else
            {
                ErrorPanel.SetActive(true);
                Debug.Log("Неправильный логин или пароль");
            }
 
            reader.Close();
            writer.Close();
        }
        catch(Exception ex)
        {
            Debug.Log(ex.Message);
        }
        finally
        {
            client.Close();
        }
    }
}
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение Ert Donuell 02 июн 2017, 02:24

Уже лучше.

Вместо IPAddress.Parse("127.0.0.1") используй IPAddress.Loopback
ClientObject - зачем таки именовать класс? Почему не Client? То, что все экземпляры классов - объекты, и так понятно.
msg = "server ok".ToString(); - а зачем приводить стрингу к стринге?
Почему Account содержит msg? Какое это сообщение имеет отношение к аккаунту?
Вместо объявления типа для каждой переменной, которая прямо в здесь и сейчас инициализируется, можно использовать var - это может повысить читабельность кода.
while (true) - будет крутиться вечно?
finally - сработает только при исключении, ведь из цикла нет выхода. Как я знаю, при закрытии приложения код в там не выполнится
InputBox1, InputBox2 - ужасное именование переменных
log, pas - излишнее сокращение. login и password куда понятнее. Особенно если код разрастётся
BinaryWriter writer = new BinaryWriter(stream); ... writer.Close(); - стоит использовать using (var writer = new BinaryWriter(stream)) { ... }. Кстати, тогда и Close явно вызывать не нужно. Касается также NetworkStream, BinaryReader, а также всех прочих классов, реализующих интерфейс IDisposable
msg == "server ok" - строка вместо булевой переменной, чтобы.. что? К слову, переменная должна быть true для верных логина и пароля и false - для неверных. Для деталей ошибки - да, можно вернуть строку. Типа "такой юзер не найден", "пароль неверен" или "юзернейм не может быть empty"
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

Re: серверный движок

Сообщение -Шум- 02 июн 2017, 06:45

Ert Donuell писал(а):Уже лучше.

Вместо IPAddress.Parse("127.0.0.1") используй IPAddress.Loopback
ClientObject - зачем таки именовать класс? Почему не Client? То, что все экземпляры классов - объекты, и так понятно.
msg = "server ok".ToString(); - а зачем приводить стрингу к стринге?
Почему Account содержит msg? Какое это сообщение имеет отношение к аккаунту?
Вместо объявления типа для каждой переменной, которая прямо в здесь и сейчас инициализируется, можно использовать var - это может повысить читабельность кода.
while (true) - будет крутиться вечно?
finally - сработает только при исключении, ведь из цикла нет выхода. Как я знаю, при закрытии приложения код в там не выполнится
InputBox1, InputBox2 - ужасное именование переменных
log, pas - излишнее сокращение. login и password куда понятнее. Особенно если код разрастётся
BinaryWriter writer = new BinaryWriter(stream); ... writer.Close(); - стоит использовать using (var writer = new BinaryWriter(stream)) { ... }. Кстати, тогда и Close явно вызывать не нужно. Касается также NetworkStream, BinaryReader, а также всех прочих классов, реализующих интерфейс IDisposable
msg == "server ok" - строка вместо булевой переменной, чтобы.. что? К слову, переменная должна быть true для верных логина и пароля и false - для неверных. Для деталей ошибки - да, можно вернуть строку. Типа "такой юзер не найден", "пароль неверен" или "юзернейм не может быть empty"

можете привести пример? не совсем понимаю как и в каких местах нужно написать код (объявление через var, стоит использовать using (var writer = new BinaryWriter(stream)) { ... }, как исправить ситуацию с бесконечным циклом и finally?)
-Шум-
UNец
 
Сообщения: 11
Зарегистрирован: 31 май 2017, 05:56

Re: серверный движок

Сообщение Ert Donuell 02 июн 2017, 19:55

var можно использовать там, в где тип переменной определяется значением, которое ей присваивается:
int i = 0;
эквивалентно
var i = 0;

Но вместо
int i;
i = 0;

нельзя написать
var i;
i = 0;

потому как в строке var i; переменной не присваивается значение

Так, в каждом месте (внутри методов, при объявлении переменных класса так нельзя) вместо
Синтаксис:
Используется csharp
IPEndPoint ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8005);
// Создаем сокет Tcp/Ip
Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);


можно писать

Синтаксис:
Используется csharp
var ipPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8005);
// Создаем сокет Tcp/Ip
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);



Синтаксис:
Используется csharp
using (var writer = new BinaryWriter(stream))
{
    ...
}
 


эквивалентно
Синтаксис:
Используется csharp
var writer = new BinaryWriter(stream);
try
{
    ...
}
finally
{
    writer.Close();
}
 
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

Re: серверный движок

Сообщение Ert Donuell 02 июн 2017, 19:57

Чтобы выйти из цикла, вместо true можно установить флаговую переменную, изменяемую из фонового потока по, например, нажатию Esc. Функционал сервера имеет смысл вынести в отдельный поток.
Добавить dmitrii.baranov.yumasoft в Skype
Аватара пользователя
Ert Donuell
Старожил
 
Сообщения: 781
Зарегистрирован: 05 июл 2010, 09:50
Откуда: Санкт-Петербург
  • ICQ

След.

Вернуться в Сеть

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1