简易的自定义Web服务器

基于浏览器向服务端发起请求

两台主机各自的进程之间相互通信,需要协议、IP地址和端口号,IP表示了主机的网络地址,而端口号则表示了主机上的某个进程的地址,IP加Port统称为端点(EndPoint),在网络编程的世界里,.NET提供了Socket(套接字)类,此类处于传输层之中,Socket使开发人员可以以编程的方式侦听远程主机向本机发送的数据,并对到达传输层的数据包做出处理,同时它还可以向远程发送数据包。也即,Socket用于处理传输的数据。

 );
             );];, , len );,  };

clientSocket.Send( HttpDataLineByte );
                clientSocket.Send( HttpHeaderByte );
                clientSocket.Send( HttpNullLineByte );
                clientSocket.Send( HttpBodyByte );

//断开连接
                clientSocket.Close( );              
            }
        }
    }
}

在浏览器输入端点进行访问,因为浏览器实已经实现了Http协议,浏览器处于应用层,封装好请求后会往下传递给传输层,封装TCP端口再传递给网络层直到请求发送至服务端,所以可以直接看到服务端返回的结果:

TcpListener封装了Socket,所以也可以使用TcpListener来监听请求

  , HttpBodyByte.Length );
                }
                //断开连接
                clientTcp.Close( );              
            }
        }
    }
}

基于windows窗体实现双方发送即时通信

分别创建两个windows窗体项目,命名为TCPServer和TCPClient。两个项目的窗体控件的名称是一样的,如下:

服务端通过TcpListener开启监听,然后通过开启新的线程并使用TcpListener的AcceptTcpClient方法去监听客户端的请求,而客户端则开启新线程并通过TcpClient发起远程连接请求。这样双方就可以建立一个连接。接着,服务端的AcceptTcpClient方法会阻塞线程直到接受到一个请求为止,此时它会返回一个NetworkStream实例,此类提供了读取远程数据、发送数据的方法,此后,双方的互动都是通过这个唯一的NetworkStream实例的方法(Read、Write)来完成,发送数据和接收数据时都使用新线程来处理,并且应将发送数据和接收数据的逻辑都放入try块,这样一旦互动过程出现异常则可以关闭当前的Tcp连接、清空NetworkStream资源,然后服务端重新开启新线程继续监听客户端的连接请求,而客户端则重新发送远程连接的请求即可。

服务端源码

 
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
;
         );
            
             ); //模拟发送延时
                    writer.Flush( );
                    statusStrip.Invoke( showStatusMessage, "消息发送成功……" );
                    ShowMessageBox.Invoke( showGetOrSendMessage, senMsg );//在创建"公共消息框控件"的线程上调用showGetOrSendMessage委托来显示消息
                }
                catch 
                {
                    //如果出现异常则需要关闭现有连接,清除所有资源后重新开始
                    statusStrip.Invoke( showStatusMessage, "消息发送失败……" );
                    if (client != null) client.Close( );
                    if (reader != null) reader.Close( );
                    if (writer != null) writer.Close( );
                    //重新开启新线程来接收请求
                    Thread thread = new Thread( Request );
                    thread.Start( );
                }
            } );

proxyThread.Start( );
        }

//关闭监听
        private void CloseTcpListen_Click( object sender, EventArgs e )
        {
            if (client != null) client.Close( );
            if (reader != null) reader.Close( );
            if (writer != null) writer.Close( );
            lister.Stop( );
            statusStrip.Invoke( showStatusMessage, "监听已经关闭……" );
        }

//断开连接
        private void NoConnect_Click( object sender, EventArgs e )
        {
            if (client != null) client.Close( );
            if (reader != null) reader.Close( );
            if (writer != null) writer.Close( );
            statusStrip.Invoke( showStatusMessage, "连接已断开……" );
        }

//清空消息
        private void ClearMessage_Click( object sender, EventArgs e )
        {
            ShowMessageBox.Clear( );
        }

//点击关闭窗口按钮时,关闭TCP侦听,否则它会一直开启
        private void Server_FormClosing( object sender, FormClosingEventArgs e )
        {
            lister.Stop( );
        }
    }
}

客户端源码

 );  );
                    ShowMessageBox.Invoke( showGetOrSendMessage, sendMsg );
                    statusStrip.Invoke( showStatusMessage, "消息发送成功……" );
                }
                catch
                {
                    //如果出现异常则关闭现有连接,清除所有资源
                    statusStrip.Invoke( showStatusMessage, "消息发送失败……" );
                    if (server != null) server.Close( );
                    if (reader != null) reader.Close( );
                    if (writer != null) writer.Close( );
                    statusStrip.Invoke( showStatusMessage, "连接已经断开,请重新点击'连接服务器'按钮……" );
                }
            } );
            proxyThread.Start( );
        }

//断开连接
        private void NoConnect_Click( object sender, EventArgs e )
        {
            if (server != null) server.Close( );
            if (reader != null) reader.Close( );
            if (writer != null) writer.Close( );
            statusStrip.Invoke( showStatusMessage, "连接已断开……" );
        }

//清空消息
        private void ClearMessage_Click( object sender, EventArgs e )
        {
            ShowMessageBox.Clear( );
        }

//关闭窗口
        private void CloseWin_Click( object sender, EventArgs e )
        {
            this.Close( );
        }
    }
}

参考资料

msdn:基于TCP协议的简单通信程序

网络知识 - 学习总目录

网络知识 - 简易的自定义Web服务器的更多相关文章

  1. C# 编写简易 ASP.NET Web 服务器

    C# 编写简易 ASP.NET Web 服务器 你是否有过这样的需求——想运行 ASP.NET 程序,又不想安装 IIS 或者 Visual Studio?我想如果你经常编写 ASP.NET 程序的话 ...

  2. atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener

    atitit.跨架构 bs cs解决方案. 自定义web服务器的实现方案 java .net jetty  HttpListener 1. 自定义web服务器的实现方案,基于原始socket vs   ...

  3. 自定义web服务器(四)

    关于HTTP协议的具体内容,前面章节已经有所讲解,相信读者已有所了解,在此不在累述,本章节讲解自定义web服务器.  一,.net提供自定义Web服务器的类 以下只是写主要的类 1.HTTPListe ...

  4. [C# 网络编程系列]专题三:自定义Web服务器

    转自:http://www.cnblogs.com/zhili/archive/2012/08/23/2652460.html 前言: 经过前面的专题中对网络层协议和HTTP协议的简单介绍相信大家对网 ...

  5. 使用 C# 编写简易 ASP.NET Web 服务器

    原文 http://www.cnblogs.com/lcomplete/p/use-csharp-write-aspnet-web-server.html 如果你想获得更好的阅读体验,可以前往我在 g ...

  6. 转:【专题三】自定义Web服务器

    前言: 经过前面的专题中对网络层协议和HTTP协议的简单介绍相信大家对网络中的协议有了大致的了解的, 本专题将针对HTTP协议定义一个Web服务器,我们平常浏览网页通过在浏览器中输入一个网址就可以看到 ...

  7. 使用 C# 编写简易 ASP.NET Web 服务器 ---- 模拟IIS的处理过程

    如果你想获得更好的阅读体验,可以前往我在 github 上的博客进行阅读,http://lcomplete.github.io/blog/2013/07/16/use-csharp-write-asp ...

  8. Servlet学习笔记【1】--- 背景和基础知识(CGI、Web服务器发展史、Servlet简介、任务、继承结构)

    本文主要讲Servlet的基础知识和背景知识. 1 CGI简介 CGI(Common Gateway Interface 公共网关接口)是WWW技术中最重要的技术之一,有着不可替代的重要地位.CGI是 ...

  9. 专题三:自定义Web服务器

    前言: 经过前面的专题中对网络层协议和HTTP协议的简单介绍相信大家对网络中的协议有了大致的了解的, 本专题将针对HTTP协议定义一个Web服务器,我们平常浏览网页通过在浏览器中输入一个网址就可以看到 ...

随机推荐

  1. Dockerfile 规范

    https://time-track.cn/compile-docker-from-source.html 参考 https://time-track.cn/install-docker-on-ubu ...

  2. 数据类型:list列表[]、元祖tuple()、dict字典{}

    List 列表[] 可变的 lst = [1,2,3,4] #改 lst[(元素下标)] = '需要修改的' #通过下表修改 lst[下标:下标] = '需要修改的' #通过范围修改 #加 lst.a ...

  3. [详细实例]MicroPython拼插编程实战:DIY一台会思考的壁障车

    (转载请注明文章来源,更多教程可自助参考www.tpyboard.com,QQ技术交流群:157816561,公众号:MicroPython玩家汇) 在日常生活中,大家会经常见到各种各样的遥控车,它需 ...

  4. Linux笔记-ps -aux的结果解析

    参考: https://blog.csdn.net/flyingleo1981/article/details/7739490 ps 的参数说明ps 提供了很多的选项参数,常用的有以下几个: l 长格 ...

  5. HRBUST - 2069-萌萌哒十五酱的衣服~-multiset-lower_bound

    众所周知,十五酱有很多的衣服,而且十五酱东西收拾的非常糟糕. 所以十五酱经常找不到合适的衣服穿,于是她觉得收拾一下屋子,把衣服配成一套一套的~(即一件衬衫一件裤子. 十五酱一共有n件衣服,有衬衫有裤子 ...

  6. 通过Docker发布RestAPI遇到的种种问题

    目标:发布一个分词API 问题1:Docker外无法访问API 原因: Docker映射的地址是0.0.0.0:8888端口,而flask启动的时候默认地址是127.0.0.1:5000,需要手动配置 ...

  7. 一些有意思的Linux命令

    1.输出你最常用的十条命令 history|awk '{print $2}'|awk 'BEGIN {FS="|"} {print $1}'|sort|uniq -c|sort - ...

  8. 【C/C++】Dijkstra算法的简洁实现

    Dijkstra的实现有很多种,下面给出一种较为简洁和高效的实现,可以作为模板快速使用. 1. 使用邻接表存储图: 2. 使用标准STL的vector存储每个点的所有邻接边: 3. 使用pair记录当 ...

  9. 【数学建模】偏最小二乘回归分析(PLSR)

    PLSR的基本原理与推导,我在这篇博客中有讲过. 0.偏最小二乘回归集成了多元线性回归.主成分分析和典型相关分析的优点,在建模中是一个更好的选择,并且MATLAB提供了完整的实现,应用时主要的问题是: ...

  10. shell实战之日志脱敏

    本次实战目标为日志脱敏,将日志目录内的所有文件进行处理,凡是涉及到卡号和密码的信息,一律以“*”号替代,要替代的内容都从对应的标签内获取,本脚本执行目录 drwxr-xr-x 5 root root ...