質問
この段階で、ブラウザを介してアクセスでき、「Hello World」を実行するだけの簡単なC#Webサーバーを作成しようとしています。
私が抱えている問題は、サーバーがデータを正常に受信できることです-ブラウザーのヘッダー情報を取得します-しかし、ブラウザーは送信したものを受信しません。さらに、localhost(または127.0.0.1)にアクセスすることでのみサーバーに接続できます。 IPにアクセスしてもアクセスできず、ネットワーク設定ではありません。代わりに実行するとApacheが正常に動作します。また、ポート監視プログラムを使用しており、ブラウザから接続を試みた後、接続を閉じてLISTENに戻るように指示したにもかかわらず、プロセスのポートがTIME_WAIT状態のままになります。
関連するコードは次のとおりです。いくつかの呼び出しは意味をなさないかもしれませんが、これは大きなプログラムの一部です。
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
を使用すると、基本的なWebサーバーを非常に簡単に記述できます。これにより、ほとんどの苦痛な部分が処理されるため、実際のコードの記述に専念できます。 MSDNページに例を示します。
これはHTTP.SYSを使用することに注意してください。これは優れていますが、開いているポートへのアクセス権を管理者以外に明示的に与える必要があることを意味します。 XPでは、 httpcfg
でこれを行うことができます。 Vistaでは、 netsh
を使用できます。 こちらをご覧ください。
他のヒント
現時点では問題ではありませんが、後で問題になる可能性があるのは、コンテンツの長さがバイナリではなく、メッセージ文字列の Unicode の長さに基づいていることですem>長さ。
また、Connectionコンストラクターではかなり多くのことが行われています。実際には、コンストラクターにまったく属さないもの、IMOです。また、例外が発生しても物事を閉じません。
WireSharkのようなネットワークトレーサーで何が起こっているのか見てきましたか?これは、任意のデータがクライアントに返送されているかどうかを確認する最も簡単な方法です。
別の方法として、短いが完全なバージョンのコードを投稿し、それをコンパイルして実行できます。
何かが足りないかもしれませんが、localhostでしか接続できない理由は、リッスンしているIPが127.0.0.1であるためです。これにより、TCPListenerはそのIPアドレスのみをリッスンします。また、クライアント切断を呼び出している場所は表示されません。TCPListenerはブロッキング呼び出しであるため、接続が確立されるまで永久に存在します。 TCP / IPおよびTCPListenerでの過去の経験では、TCPClientクラスは、クライアント接続をドロップするまでリスナーに接続を強制的にドロップさせる方法はあまりありません。 TCPListener.Abort()を呼び出しても、ポートがブロックされたままになるクライアント接続はドロップされません。
同様の状況で、ローカルネットワークIPアドレスからC#サーバーにアクセスする場合は、アドレス0.0.0.0をリッスンする必要があります。つまり、127.0.0.1などの特定のものではなく、すべてのIPアドレスでリッスンする必要があります。 / p>