第一次尝试(V1.0)
1.理论支持
这里主要要说的关于Socket方面的。主要是一个例子,关于Socket如何建立服务端程序的简单的代码。

static void Main(string[] args) { //创建一个新的Socket,这里我们使用最常用的基于TCP的Stream Socket(流式套接字) var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //将该socket绑定到主机上面的某个端口 socket.Bind(new IPEndPoint(IPAddress.Any, 4530)); //启动监听,并且设置一个最大的队列长度 socket.Listen(4); //到这里我们的Socket已经运行起来了,但仅仅是运行起来,什么都不会做的! Console.WriteLine("Server is ready!"); Console.Read(); }

打开调试一口,因为要监听某个端口,windows会有这样的一个提示。点允许就好了。
从上面例子看,socket的职责仅仅是监听4530端口,什么都不会做的!
就像一个人的耳朵。他会聆听,但是不会倾诉。职责所限,我们需要一个监听4530端口的耳朵。
但是从交流的角度看,web服务器仅仅能聆听是不够的。
请求来了以后(监听到请求以后),我还需要一个既能聆听,又能诉说的Socket。去和请求交流。
刚刚那个socket为啥不能直接交流呢? 不不不,他得继续去聆听新的请求。
2.说说思路
这次实验的主要思路是这样的。
1)监听4530端口
2)当请求来了以后,我们使用Socket socket = serverSocket.Accept();建立一个新的socket。
3)新的socket返回一个字符串给请求方!
也就是说,我们v1.0版本的web服务器,不管你如何请求,他都会返回你同一个字符串!(任性吧?其实我挺喜欢就这样的。)
3.代码

static void Main(string[] args) { //我仅负责聆听,因为你来了,我就得接着等待下一个。 Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); //绑定监听的端口 serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8070)); //开始聆听你的请求 serverSocket.Listen(10); while (true) { Console.WriteLine("等着请求"); //没有请求的状态下,程序就在这里停留。 //你来了,serverSocket就会把你的心愿告诉给一个新的socket。程序就继续执行了! Socket socket = serverSocket.Accept(); Console.WriteLine("来了请求"); using (NetworkStream stream = new NetworkStream(socket)) using (StreamReader reader = new StreamReader(stream)) { string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); if (line.Length <= 0) { break;//遇到空行了,请求结束了不用再等了 //如果不break,就一直卡在ReadLine()等着浏览器发后续的数据 } } } using (NetworkStream stream = new NetworkStream(socket)) using (StreamWriter writer = new StreamWriter(stream)) { writer.WriteLine("HTTP/1.1 200 OK"); writer.WriteLine(); writer.WriteLine("哎呀,你好,你好!"); } socket.Disconnect(false); } }

4.调试
我们就这样任性的、如qq自动回互般的,高冷的一直回答说:“哎呀,你好,你好!”。
改进(V2.0)
1.改进需求
新的web服务器改进需求如下。
1.能够获取请求 路径
2.能够根据请求路径对应的文件,返回响应的静态页面!
2.实现

static void Main(string[] args) { Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(new IPEndPoint(IPAddress.Any, 8080)); serverSocket.Listen(10); while (true) { Console.WriteLine("等着请求"); Socket socket = serverSocket.Accept(); Console.WriteLine("来了请求"); string firstLine; using (NetworkStream stream = new NetworkStream(socket)) using (StreamReader reader = new StreamReader(stream)) { //比1.0版本里多出了这么一句。 //想想http请求报文格式吧,第一行有文件路径的喏! firstLine = reader.ReadLine(); string line; while ((line = reader.ReadLine()) != null) { Console.WriteLine(line); if (line.Length <= 0) { break;//遇到空行了,请求结束了不用再等了 //如果不break,就一直卡在ReadLine()等着浏览器发后续的数据 } } } //获取请求路径 string[] strs = firstLine.Split(' '); //url就获取到了 类似index.html的这样的串。 string url = strs[1]; Console.WriteLine("url=" + url); using (NetworkStream stream = new NetworkStream(socket)) using (StreamWriter writer = new StreamWriter(stream)) { //为什么要指定绝对路径呢?想想正常web服务器里的【物理路径】是啥意思。应该就懂了。 string filePath = @"C:\Users\WinterT\Desktop\消息框、JBar" + url; Console.WriteLine("filePath=" + filePath); if (File.Exists(filePath)) { writer.WriteLine("HTTP/1.1 200 OK"); writer.WriteLine(); string html = File.ReadAllText(filePath); Console.WriteLine(html); writer.Write(html); } else { writer.WriteLine("HTTP/1.1 404 NOT FOUND"); writer.WriteLine(); writer.Write("404,没有找到"); } } socket.Disconnect(false); } }

3.调试
请求的是我电脑里已有的一个html页面。成功的显示出来了!
PS:刚刚发现,现在补充进来。
不知道诸位注意到没有。
我的web服务器,每次我从浏览器输入url发出一个请求后,服务器的控制台上都会显示两个请求。
那么多出来的那个请求是干啥的呢?我们再仔细看一下图!
对,没错。浏览器在请求网站图标!
也就是说,我们想做网站图标的话,直接在网站根目录下放一个做好的
favicon.ico文件就好了!!