Вопрос

Я пытаюсь создать простой веб-сервер на C #, к которому на этом этапе вы можете получить доступ через браузер и просто выполните "Hello World".

У меня проблема в том, что сервер может нормально получать данные - я получаю информацию заголовка браузера - но браузер не получает ничего, что я отправляю. Кроме того, я могу подключиться к серверу, только перейдя на localhost (или 127.0.0.1). Я не могу добраться до него, перейдя на свой IP, и это не сетевые настройки, потому что Apache работает нормально, если я запускаю это вместо этого. Кроме того, я использую программу мониторинга портов, и после попытки подключения из браузера порт процесса застревает в состоянии TIME_WAIT, даже если я сказал, чтобы соединение закрылось, и оно должно вернуться к LISTEN.

Вот соответствующий код. Пара вызовов может не иметь смысла, но это часть большой программы.

class ConnectionHandler
{
    private Server server;

    private TcpListener tcp;

    private ArrayList connections;

    private bool listening;

    private Thread listeningThread;

    public Server getServer()
    {
        return server;
    }

    private void log(String s, bool e)
    {
        server.log("Connection Manager: " + s, e);
    }

    private void threadedListen()
    {
        while (listening)
        {
            try
            {
                TcpClient t = tcp.AcceptTcpClient();
                Connection conn = new Connection(this, t);
            }
            catch (NullReferenceException)
            {
                log("unable to accept connections!", true);
            }
        }
        log("Stopped listening", false);
    }

    public void listen()
    {
        log("Listening for new connections", false);
        tcp.Start();
        listening = true;
        if (listeningThread != null && listeningThread.IsAlive)
        {
            listeningThread.Abort();
        }
        listeningThread = new Thread(new ThreadStart(
            this.threadedListen));
        listeningThread.Start();
    }

    public void stop()
    {
        listening = false;
        if (listeningThread != null)
        {
            listeningThread.Abort();
            log("Forced stop", false);
        }
        log("Stopped listening", false);
    }

    public ConnectionHandler(Server server)
    {
        this.server = server;
        tcp = new TcpListener(new IPEndPoint(
            IPAddress.Parse("127.0.0.1"), 80));
        connections = new ArrayList();
    }
}

class Connection
{
    private Socket socket;
    private TcpClient tcp;

    private ConnectionHandler ch;

    public Connection(ConnectionHandler ch, TcpClient t)
    {
        try
        {
            this.ch = ch;
            this.tcp = t;
            ch.getServer().log("new tcp connection to " 
                + this.tcp.Client.RemoteEndPoint.ToString(), false);
            NetworkStream ns = t.GetStream();

            String responseString;
            Byte[] response;
            Int32 bytes;
            responseString = String.Empty;
            response = new Byte[512];
            bytes = ns.Read(response, 0, response.Length);
            responseString = 
                System.Text.Encoding.ASCII.GetString(response, 0, bytes);
            ch.getServer().log("Received: " + responseString);

            String msg = "<html>Hello World</html>";
            String fullMsg = "HTTP/1.x 200 OK\r\n"
                    + "Server: Test Server\r\n"
                    + "Content-Type: text/html; "
                        + "charset=UTF-8\r\n"
                    + "Content-Length: " + msg.Length + "\r\n"
                    + "Date: Sun, 10 Aug 2008 22:59:59 GMT"
                        + "\r\n";
            nsSend(fullMsg, ns);
            nsSend(msg, ns);

            ns.Close();
            tcp.Close();
        }
        catch (ArgumentNullException e)
        {
            ch.getServer().log("connection error: argument null exception: " + e);
        }
        catch (SocketException e)
        {
            ch.getServer().log("connection error: socket exception: " + e);
        }
    }

    private void nsSend(String s, NetworkStream ns)
    {
        Byte[] data = System.Text.Encoding.ASCII.GetBytes(s);
        ns.Write(data, 0, data.Length);
        ns.Flush();
        ch.getServer().log("Sent: " + s);
    }
}

У кого-нибудь есть идеи? Такое ощущение, что это должно быть что-то глупое с моей стороны, но я просто не знаю, что. Буду очень признателен за понимание

Это было полезно?

Решение

Возможно, вы захотите узнать, что вы можете использовать HttpListener для написания простого веб-сервера очень легко - это касается большинства болезненных моментов, позволяя вам сосредоточиться на написании реального кода. На странице MSDN приведен пример.

Обратите внимание, что здесь используется HTTP.SYS, что хорошо, но означает, что не-администраторам должен быть явно предоставлен доступ к открытым портам; на XP вы можете сделать это с помощью httpcfg ; на Vista вы можете использовать netsh . См. здесь , чтобы узнать больше.

Другие советы

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

В конструкторе Connection также происходит довольно много вещей - вещи, которые на самом деле не принадлежат конструктору, IMO. Это также не закрывает вещи, если происходят исключения.

Вы смотрели на то, что происходит в сетевом трассере, таком как WireShark? Это был бы самый простой способ узнать, отправляются ли какие-либо данные обратно клиенту.

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

Возможно, я просто что-то упускаю, но причина, по которой вы можете подключиться только к localhost, заключается в том, что прослушиваемый IP-адрес 127.0.0.1, поэтому TCPListener прослушивает только этот IP-адрес. И я нигде не вижу, чтобы вы вызывали какое-либо клиентское отключение, TCPListener является блокирующим вызовом, поэтому он остается там до тех пор, пока не будет установлено соединение. В моем прошлом опыте работы с TCP / IP и TCPListener, классы TCPClient не представляли особого способа заставить слушателя разорвать соединение до тех пор, пока вы не разорвете соединение клиента. Вызов TCPListener.Abort () не сбрасывает соединение с клиентом, из-за чего порт блокируется.

Для тех, кто находится в аналогичной ситуации, когда вы хотите получить доступ к вашему серверу C # с IP-адреса локальной сети, вам нужно будет прослушать адрес 0.0.0.0, то есть прослушивать все IP-адреса, а не конкретный, такой как 127.0.0.1 и т. д.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top