2015-11-26 3 views
0

Я пытаюсь сделать 2 программы (в консольном приложении) в .NET, которые общаются вместе через Интернет (код из видео, которое вы можете найти ниже, я просто пытаюсь прежде чем приступать к настройке кода). Простите меня, я не опытный программист.Программирование сокетов C#/Связь клиент-сервер

У меня есть сервер и клиент, они отлично работают, когда я запускаю их обоих на своем компьютере (локально). Я могу подключить несколько клиентов к серверу, отправлять запросы и получать ответ. Я столкнулся с проблемой, когда я запускаю сервер на компьютере и клиент на другом, и я пытаюсь подключиться через Интернет.

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

Вот код сервера:

class Program 
{ 
    private static Socket _serverSocket; 
    private static readonly List<Socket> _clientSockets = new List<Socket>(); 
    private const int _BUFFER_SIZE = 2048; 
    private const int _PORT = 50114; 
    private static readonly byte[] _buffer = new byte[_BUFFER_SIZE]; 

    static void Main() 
    { 
     Console.Title = "Server"; 
     SetupServer(); 
     Console.ReadLine(); // When we press enter close everything 
     CloseAllSockets(); 
    } 



    private static void SetupServer() 
    { 
     // IPAddress addip = GetBroadcastAddress(); 
     Console.WriteLine("Setting up server..."); 
     _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 
     _serverSocket.Bind(new IPEndPoint(IPAddress.Any , _PORT)); 
     _serverSocket.Listen(5); 
     _serverSocket.BeginAccept(AcceptCallback, null); 
     Console.WriteLine("Server setup complete"); 
    } 

    /// <summary> 
    /// Close all connected client (we do not need to shutdown the server socket as its connections 
    /// are already closed with the clients) 
    /// </summary> 
    private static void CloseAllSockets() 
    { 
     foreach (Socket socket in _clientSockets) 
     { 
      socket.Shutdown(SocketShutdown.Both); 
      socket.Close(); 
     } 

     _serverSocket.Close(); 
    } 

    private static void AcceptCallback(IAsyncResult AR) 
    { 
     Socket socket; 

     try 
     { 
      socket = _serverSocket.EndAccept(AR); 
     } 
     catch (ObjectDisposedException) // I cannot seem to avoid this (on exit when properly closing sockets) 
     { 
      return; 
     } 

     _clientSockets.Add(socket); 
     socket.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, socket); 
     Console.WriteLine("Client connected, waiting for request..."); 
     _serverSocket.BeginAccept(AcceptCallback, null); 
    } 

    private static void ReceiveCallback(IAsyncResult AR) 
    { 
     Socket current = (Socket)AR.AsyncState; 
     int received; 

     try 
     { 
      received = current.EndReceive(AR); 
     } 
     catch (SocketException) 
     { 
      Console.WriteLine("Client forcefully disconnected"); 
      current.Close(); // Dont shutdown because the socket may be disposed and its disconnected anyway 
      _clientSockets.Remove(current); 
      return; 
     } 

     byte[] recBuf = new byte[received]; 
     Array.Copy(_buffer, recBuf, received); 
     string text = Encoding.ASCII.GetString(recBuf); 
     Console.WriteLine("Received Text: " + text); 

     if (text.ToLower() == "get time") // Client requested time 
     { 
      Console.WriteLine("Text is a get time request"); 
      byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString()); 
      current.Send(data); 
      Console.WriteLine("Time sent to client"); 
     } 
     else if (text.ToLower() == "exit") // Client wants to exit gracefully 
     { 
      // Always Shutdown before closing 
      current.Shutdown(SocketShutdown.Both); 
      current.Close(); 
      _clientSockets.Remove(current); 
      Console.WriteLine("Client disconnected"); 
      return; 
     } 
     else 
     { 
      Console.WriteLine("Text is an invalid request"); 
      byte[] data = Encoding.ASCII.GetBytes("Invalid request"); 
      current.Send(data); 
      Console.WriteLine("Warning Sent"); 
     } 

     current.BeginReceive(_buffer, 0, _BUFFER_SIZE, SocketFlags.None, ReceiveCallback, current); 
    } 
} 

А вот код клиента:

class Program 
{ 
    private static readonly Socket _clientSocket = new Socket 
     (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); 

    private const int _PORT = 50114; 

    static void Main() 
    { 
     Console.Title = "Client"; 
     ConnectToServer(); 
     RequestLoop(); 
     Exit(); 
    } 

    private static void ConnectToServer() 
    { 
     int attempts = 0; 

     while (!_clientSocket.Connected) 
     { 
      try 
      { 
       attempts++; 
       Console.WriteLine("Connection attempt " + attempts); 
       _clientSocket.Connect("IpAddr", _PORT); 
      } 
      catch (SocketException) 
      { 
       Console.Clear(); 
      } 
     } 

     Console.Clear(); 
     Console.WriteLine("Connected"); 
    } 

    private static void RequestLoop() 
    { 
     Console.WriteLine(@"<Type ""exit"" to properly disconnect client>"); 

     while (true) 
     { 
      SendRequest(); 
      ReceiveResponse(); 
     } 
    } 

    /// <summary> 
    /// Close socket and exit app 
    /// </summary> 
    private static void Exit() 
    { 
     SendString("exit"); // Tell the server we re exiting 
     _clientSocket.Shutdown(SocketShutdown.Both); 
     _clientSocket.Close(); 
     Environment.Exit(0); 
    } 

    private static void SendRequest() 
    { 
     Console.Write("Send a request: "); 
     string request = Console.ReadLine(); 
     SendString(request); 

     if (request.ToLower() == "exit") 
     { 
      Exit(); 
     } 
    } 

    /// <summary> 
    /// Sends a string to the server with ASCII encoding 
    /// </summary> 
    private static void SendString(string text) 
    { 
     byte[] buffer = Encoding.ASCII.GetBytes(text); 
     _clientSocket.Send(buffer, 0, buffer.Length, SocketFlags.None); 
    } 

    private static void ReceiveResponse() 
    { 
     var buffer = new byte[2048]; 
     int received = _clientSocket.Receive(buffer, SocketFlags.None); 
     if (received == 0) return; 
     var data = new byte[received]; 
     Array.Copy(buffer, data, received); 
     string text = Encoding.ASCII.GetString(data); 
     Console.WriteLine(text); 
    } 
} 
static void Main() 
    { 
     Console.Title = "Client"; 
     ConnectToServer(); 
     RequestLoop(); 
     Exit(); 
    } 

    private static void ConnectToServer() 
    { 
     int attempts = 0; 

     while (!_clientSocket.Connected) 
     { 
      try 
      { 
       attempts++; 
       Console.WriteLine("Connection attempt " + attempts); 
       _clientSocket.Connect("IpAddr", _PORT); 
      } 
      catch (SocketException) 
      { 
       Console.Clear(); 
      } 
     } 

     Console.Clear(); 
     Console.WriteLine("Connected"); 
    } 

"IPAddr" является заполнителем для публичного IP маршрутизатора.

Это видео мой текущий код основан на: https://www.youtube.com/watch?v=xgLRe7QV6QI

я взял код непосредственно из него (вы можете найти файлы с кодом 2 на сайте связаны в описании).

Я запустил сервер, он ждет подключения. Затем я запускаю клиентов, которые пытаются подключиться к серверу. Я подключаюсь, и на сервере он показывает успешное соединение. Затем клиент посылает запрос, как «получить время», а сервер должен поймать его и ответить:

byte[] data = Encoding.ASCII.GetBytes(DateTime.Now.ToLongTimeString()); 
current.Send(data); 

Вернуться к сетевой стороне:

Вот список всех вещей, которые я попробовал, что были обычные основные причины этой проблемы после того, как в поисках решения примерно на полный день:

  • у меня уже есть статический публичный IP-адрес маршрутизатора (поэтому общественность IP никогда не меняется). Несмотря на это, я создал динамический dns на noip.com.

  • Я дал статическую аренду компьютеру, на котором работает сервер, поэтому он всегда имеет тот же локальный ip.

  • Я создал правила в брандмауэре Windows, чтобы убедиться, что порт, который я использую, открыт. Я сделал это на обоих компьютерах, пытающихся связаться.

  • Я перенаправил порт на маршрутизатор, чтобы он указывал на локальный IP-адрес компьютера, на котором работает сервер. (Я пробовал с большим количеством различных портов, нет шансов)

  • Я попытался активировать «ДМЗ» на маршрутизаторе, но это, скорее всего, не является решением

  • Я пытался создать веб-сайт ASP.NET, который страница возвращает строку, публикует ее с помощью IIS 7.5 и настраивает ее. Работает на localhost, но использует общедоступный IP-адрес, например «xx.xxx.xxx.xx: PORT/default/index». Я получаю сообщение об ошибке. Тем не менее он показывает имя веб-сайта в ошибке.Кроме того, при использовании локального IP-компьютера он не работает (что-то вроде 192.168.1.180).

Спасибо вам за помощь.

+0

Не изучайте код с YouTube, покупайте книгу. Этот пример нарушен, это пустая трата времени. Он не реализует протокол, поэтому ваш сервер никогда не получает «получить время», он получает «get t» в одном пакете и «ime» в другом. Например. По крайней мере, это то, что я увидел, когда я быстро пропустил видео. Если вы хотите помочь отладить ваш код, включите в свой вопрос все ** соответствующие ** коды. :) Код подключения не имеет значения и работает, иначе вы получите исключение, с которым вы не могли соединиться. Ошибка в коде, который обрабатывает отправку и получение данных. – CodeCaster

+0

Он работает локально, мне не нужно отлаживать, в частности, я потратил много времени, чтобы найти решение в Интернете, поэтому я просто разместил здесь свою проблему ^^. –

+1

_ «Это работает на моей машине» _ является классическим оправданием для сломанного сетевого кода, но это не делает его менее сломанным. Если вы можете подключиться, но связь не работает должным образом, код не работает. Я, конечно, не пытаюсь вас раздражать, но такие учебные пособия порождают множество таких вопросов в день. Введите код в свой вопрос. – CodeCaster

ответ

1

Я узнал о создании сообщений, спасибо CodeCaster.

Для людей, которым интересно об этом, вот интересная ссылка я нашел об этом: http://blog.stephencleary.com/2009/04/message-framing.html

Но прежде чем пытаться изменить код, я побежал сервера в VPS АМС, и она работала мгновенно, проблема вероятно, поступал от моего ISP или моего маршрутизатора. Мне просто интересно, как он может работать без обработки сообщений.

Смежные вопросы