Многопользовательский чат C#

104
21 ноября 2021, 05:40

По уроку https://www.youtube.com/watch?reload=9&v=OdCPzknLX6Y написан чат, где есть сервер и клиент. При запуске сервера и клиента на локальной машине все замечательно работает, но если запустить сервер на одном пк, а клиента на другом одной локальной сети, то чат не работает. Как исправить данную проблему?

Клиент:

public partial class chatForm : Form
{
    private delegate void printer(string data);
    private delegate void cleaner();
    printer Printer;
    cleaner Cleaner;
    private Socket _serverSocket;
    private Thread _clientThread;
    private const string _serverHost = "192.168.1.35";
    private const int _serverPort = 9933;
    public chatForm()
    {
        InitializeComponent();
        Printer = new printer(print);
        Cleaner = new cleaner(clearChat);
        connect();
        _clientThread = new Thread(listner);
        _clientThread.IsBackground = true;
        _clientThread.Start();
    }
    private void listner()
    {
        while (_serverSocket.Connected)
        {
            byte[] buffer = new byte[8196];
            int bytesRec = _serverSocket.Receive(buffer);
            string data = Encoding.UTF8.GetString(buffer, 0, bytesRec);
            if (data.Contains("#updatechat"))
            {
                UpdateChat(data);
                continue;
            }
        }
    }
    private void connect()
    {
        try
        {
            IPHostEntry ipHost = Dns.GetHostEntry(_serverHost);
            IPAddress ipAddress = ipHost.AddressList[0];
            IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, _serverPort);
            _serverSocket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
            _serverSocket.Connect(ipEndPoint);
        }
        catch { print("Сервер недоступен!"); }
    }
    private void clearChat()
    {
        if (this.InvokeRequired)
        {
            this.Invoke(Cleaner);
            return;
        }
        chatBox.Clear();
    }
    private void UpdateChat(string data)
    {
        //#updatechat&userName~data|username~data
        clearChat();
        string[] messages = data.Split('&')[1].Split('|');
        int countMessages = messages.Length;
        if (countMessages <= 0) return;
        for (int i = 0; i < countMessages; i++)
        {
            try
            {
                if (string.IsNullOrEmpty(messages[i])) continue;
                print(String.Format("[{0}]:{1}.", messages[i].Split('~')[0], messages[i].Split('~')[1]));
            }
            catch { continue; }
        }
    }
    private void send(string data)
    {
        try
        {
            byte[] buffer = Encoding.UTF8.GetBytes(data);
            int bytesSent = _serverSocket.Send(buffer);
        }
        catch { print("Связь с сервером прервалась...");}
    }
    private void print(string msg)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(Printer, msg);
            return;
        }
        if (chatBox.Text.Length == 0)
            chatBox.AppendText(msg);
        else
            chatBox.AppendText(Environment.NewLine + msg);
    }
    private void enterChat_Click(object sender, EventArgs e)
    {
        string Name = userName.Text;
        if (string.IsNullOrEmpty(Name)) return;
        send("#setname&" + Name);
        chatBox.Enabled = true;
        chat_msg.Enabled = true;
        chat_send.Enabled = true;
        userName.Enabled = false;
        enterChat.Enabled = false;
    }
    private void chat_send_Click(object sender, EventArgs e)
    {
        sendMessage();
    }
    private void sendMessage()
    {
        try
        {
            string data = chat_msg.Text;
            if (string.IsNullOrEmpty(data)) return;
            send("#newmsg&" + data);
            chat_msg.Text = string.Empty;
        }
        catch { MessageBox.Show("Ошибка при отправке сообщения!"); }
    }
    private void chatBox_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyData == Keys.Enter)
            sendMessage();
    }
    private void chat_msg_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.KeyData == Keys.Enter)
            sendMessage();
    }
}

Сервер:

class Program
{
    private const string _serverHost = "192.168.1.35";
    private const int _serverPort = 9933;
    private static Thread _serverThread;
    static void Main(string[] args)
    {
        _serverThread = new Thread(startServer);
        _serverThread.IsBackground = true;
        _serverThread.Start();
        while (true)
            handlerCommands(Console.ReadLine());
    }
    private static void handlerCommands(string cmd)
    {
        cmd = cmd.ToLower();
        if (cmd.Contains("/getusers"))
        {
            int countUsers = Server.Clients.Count;
            for (int i = 0; i < countUsers; i++)
            {
                Console.WriteLine("[{0}]: {1}",i,Server.Clients[i].UserName);
            }
        }
    }
    private static void startServer()
    {
        IPHostEntry ipHost = Dns.GetHostEntry(_serverHost);
        IPAddress ipAddress = ipHost.AddressList[0];
        IPEndPoint ipEndPoint = new IPEndPoint(ipAddress, _serverPort);
        Socket socket = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
        socket.Bind(ipEndPoint);
        socket.Listen(1000);
        Console.WriteLine("Server has been started on IP: {0}.",ipEndPoint);
        while(true)
        {
            try
            {
                Socket user = socket.Accept();
                Server.NewClient(user);
            }
            catch (Exception exp) { Console.WriteLine("Error: {0}",exp.Message); }
        }
    }
}
Answer 1

Дело не в сервере, а в межсетевом экране. Блокировать общение по локальной сети может так же и роутер, но в большинстве случаев это происходит из-за Брандмауэра Windows на стороне сервера.

Благо, его достаточно просто отключить как для определенного порта в настройках, так и глобально. Используя программу Windows Updates Disabler это можно сделать в два клика.

Если это не помогает, универсальным способом будет применение ngrok - утилиты для проброса вещания с специфичного порта через интернет. Ее так же применяют для расшаривания ресурсов при отсутствие статичного ip.

Answer 2

Вопрос решен! Спасибо Bulson, за то что натолкнул меня на Exception, что я действительно забыл прописать, чтобы увидеть ошибку!

Проблема была в нескольких сетевых адаптерах на ПК (сервер), ipHost.AddressList[0] на удаленном ПК был равен iPv6, а ipHost.AddressList[1] и был тот нужный локальный iPv4.

READ ALSO
Подключение C++ dll к WPF проекту C# [дубликат]

Подключение C++ dll к WPF проекту C# [дубликат]

Есть WPF проект на C# и С++ dll реализующая некоторые сложные вычисления, возможно ли как то подключить эту библиотеку к С# проекту для создания...

85
Angular - как правильно подписаться на ng-model

Angular - как правильно подписаться на ng-model

Почему я не могу так сделать? У меня два селектаПервый солект должен создать вложенный объект у объекта Album

199
Вопрос по методу Instantiate() в Unity

Вопрос по методу Instantiate() в Unity

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

129
Загрузка System.Runtime.InteropServices.RuntimeInformation

Загрузка System.Runtime.InteropServices.RuntimeInformation

После ошибки "Пакет Shared Web Component не был правильно загружен" удалил Visual Studio Community 17 и установил Visual Studio Community 19

117