• Scoket 处理HTTP请求响应


    套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。

         它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,

    本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。

    套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

    1HTTP请求格式:

    <request line>

    <headers>

    <blank line>

    [<request-body>]

    2.了解Socket,TCP,HTTP,直接的关系

        HTTP协议(Hypertext Transfer Protocol ),是Web联网的基础,也是手机联网常用的协议之一,HTTP协议是建立在TCP协议之上的一种应用。

    创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

    .NetFrameWork为Socket通讯提供了System.Net.Socket命名空间,在这个命名空间里面有以下几个常用的重要类分别是:

      ·Socket类这个低层的类用于管理连接,WebRequest,TcpClient和UdpClient在内部使用这个类。

      ·NetworkStream类这个类是从Stream派生出来的,它表示来自网络的数据流

      ·TcpClient类允许创建和使用TCP连接

      ·TcpListener类允许监听传入的TCP连接请求

      ·UdpClient类用于UDP客户创建连接(UDP是另外一种TCP协议,但没有得到广泛的使用,主要用于本地网络)

           IPAddress类 提供网际协议 (IP) 地址。

          IPEndPoint 继承 EndPoint  将网络端点表示为 IP 地址和端口号。


    简单的Http请求服务处理类 


    class MyWebServer
    {
    private readonly int port = Convert.ToInt32(ConfigurationManager.AppSettings["port"].ToString());
    private readonly string host = ConfigurationManager.AppSettings["host"];
    private readonly string sMyWebServerRoot = ConfigurationManager.AppSettings["dir"];
    private TcpListener tcplistener=null;
    public MyWebServer()
    {
    try
    {
    ///创建终结点(EndPoint)
    IPAddress ip = IPAddress.Parse(host);//把ip地址字符串转换为IPAddress类型的实例
    //TcpListener类对象,监听端口
    tcplistener = new TcpListener(ip, port);
    tcplistener.Start();
    Console.WriteLine(
    "Web Server Running... Press ^C to Stop...");
    //同时启动一个兼听进程 ''StartListen''
    Thread th = new Thread(new ThreadStart(StartListen));
    th.Start();

    }
    catch (Exception e)
    {
    Console.WriteLine(
    "监听端口时发生错误 :" + e.ToString());
    }
    }
    /// <summary>
    /// 设置请求的标头
    /// </summary>
    /// <param name="sHttpVersion"></param>
    /// <param name="sMIMEHeader"></param>
    /// <param name="iTotBytes"></param>
    /// <param name="sStatusCode"></param>
    /// <param name="mySocket"></param>
    public void SendHeader(string sHttpVersion, string sMIMEHeader, int iTotBytes, string sStatusCode, ref Socket mySocket)
    {

    String sBuffer
    = "";

    if (sMIMEHeader.Length == 0)
    {
    sMIMEHeader
    = "text/html"; // 默认 text/html
    }

    sBuffer
    = sBuffer + sHttpVersion + sStatusCode + "\r\n";
    sBuffer
    = sBuffer + "Server: cx1193719-b\r\n";
    sBuffer
    = sBuffer + "Content-Type: " + sMIMEHeader + "\r\n";
    sBuffer
    = sBuffer + "Accept-Ranges: bytes\r\n";
    sBuffer
    = sBuffer + "Content-Length: " + iTotBytes + "\r\n\r\n";

    Byte[] bSendData
    = Encoding.ASCII.GetBytes(sBuffer);

    SendToBrowser(bSendData,
    ref mySocket);

    Console.WriteLine(
    "Total Bytes : " + iTotBytes.ToString());

    }

    public void SendToBrowser(String sData, ref Socket mySocket)
    {
    SendToBrowser(Encoding.ASCII.GetBytes(sData),
    ref mySocket);
    }
    /// <summary>
    /// 负责向客户端发起数据
    /// </summary>
    /// <param name="bSendData">字节数组</param>
    /// <param name="mySocket">Soket对象!</param>
    public void SendToBrowser(Byte[] bSendData, ref Socket mySocket)
    {
    int numBytes = 0;

    try
    {
    if (mySocket.Connected)
    {
    if ((numBytes = mySocket.Send(bSendData, bSendData.Length, 0)) == -1)
    Console.WriteLine(
    "Socket Error cannot Send Packet");
    else
    {
    Console.WriteLine(
    "No. of bytes send {0}", numBytes);
    }
    }
    else
    Console.WriteLine(
    "连接失败....");
    }
    catch (Exception e)
    {
    Console.WriteLine(
    "发生错误 : {0} ", e);

    }
    }
    public static void Main()
    {
    MyWebServer MWS
    = new MyWebServer();
    }
    public void StartListen()
    {

    int iStartPos = 0;
    String sRequest;
    String sDirName;
    String sRequestedFile;
    String sErrorMessage;
    String sLocalDir;
    String sPhysicalFilePath
    = "";
    String sFormattedMessage
    = "";
    String sResponse
    = "";
    //进入监听循环
    while (true)
    {
    //接受新连接
    Socket mySocket = tcplistener.AcceptSocket();

    Console.WriteLine(
    "Socket Type " + mySocket.SocketType);
    if (mySocket.Connected)
    {
    Console.WriteLine(
    "\nClient Connected!!\n==================\nCLient IP {0}\n", mySocket.RemoteEndPoint);

    //将请求转化成字节数组!
    // 为读取数据而准备缓存
    Byte[] bReceive = new Byte[1024];
    int i = mySocket.Receive(bReceive, bReceive.Length, 0);

    //转换成字符串类型
    string sBuffer = Encoding.ASCII.GetString(bReceive);
    Console.WriteLine(sBuffer);
    //只处理"get"请求类型
    if (sBuffer.Substring(0, 3) != "GET")
    {
    Console.WriteLine(
    "只处理get请求类型..");
    mySocket.Close();
    return;
    }

    // 查找 "HTTP" 的位置
    iStartPos = sBuffer.IndexOf("HTTP", 1);


    string sHttpVersion = sBuffer.Substring(iStartPos, 8);


    // 得到请求类型和文件目录文件名
    sRequest = sBuffer.Substring(0, iStartPos - 1);

    sRequest.Replace(
    "\\", "/");


    //如果结尾不是文件名也不是以"/"结尾则加"/"
    if ((sRequest.IndexOf(".") < 1) && (!sRequest.EndsWith("/")))
    {
    sRequest
    = sRequest + "/";
    }


    //得带请求文件名
    iStartPos = sRequest.LastIndexOf("/") + 1;
    sRequestedFile
    = sRequest.Substring(iStartPos);


    //得到请求文件目录
    sDirName = sRequest.Substring(sRequest.IndexOf("/"), sRequest.LastIndexOf("/") - 3);


    //获取虚拟目录物理路径
    sLocalDir = sMyWebServerRoot;

    Console.WriteLine(
    "请求文件目录 : " + sLocalDir);

    if (sLocalDir.Length == 0)
    {
    sErrorMessage
    = "<H2>Error!! Requested Directory does not exists</H2><Br>";
    SendHeader(sHttpVersion,
    "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
    SendToBrowser(sErrorMessage,
    ref mySocket);
    mySocket.Close();
    continue;
    }


    if (sRequestedFile.Length == 0)
    {
    // 取得请求文件名
    sRequestedFile = "index.html";
    }


    /////////////////////////////////////////////////////////////////////
    // 取得请求文件类型(设定为text/html)
    /////////////////////////////////////////////////////////////////////

    String sMimeType
    = "text/html";

    sPhysicalFilePath
    = sLocalDir + sRequestedFile;
    Console.WriteLine(
    "请求文件: " + sPhysicalFilePath);


    if (File.Exists(sPhysicalFilePath) == false)
    {

    sErrorMessage
    = "<H2>404 Error! File Does Not Exists...</H2>";
    SendHeader(sHttpVersion,
    "", sErrorMessage.Length, " 404 Not Found", ref mySocket);
    SendToBrowser(sErrorMessage,
    ref mySocket);

    Console.WriteLine(sFormattedMessage);
    }

    else
    {
    int iTotBytes = 0;

    sResponse
    = "";

    FileStream fs
    = new FileStream(sPhysicalFilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
    BinaryReader reader
    = new BinaryReader(fs);
    byte[] bytes = new byte[fs.Length];
    int read;
    while ((read = reader.Read(bytes, 0, bytes.Length)) != 0)
    {
    sResponse
    = sResponse + Encoding.ASCII.GetString(bytes, 0, read);

    iTotBytes
    = iTotBytes + read;

    }
    reader.Close();
    fs.Close();

    SendHeader(sHttpVersion, sMimeType, iTotBytes,
    " 200 OK", ref mySocket);
    SendToBrowser(bytes,
    ref mySocket);
    //mySocket.Send(bytes, bytes.Length,0);

    }
    mySocket.Close();
    }
    }
    }

    }

    服务端配置文件

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
    <appSettings>
    <add key="port" value="1280"/>
    <!--IP地址-->
    <add key="host" value="127.0.0.1"/>
    <!--设定你自己的虚拟目录-->
    <add key="dir" value="E:\\MyWebServerRoot\\"/>
    </appSettings>
    </configuration>

    客户端请求类

    static void Main(string[] args)
    {
    int port = 1280;
    string host = "127.0.0.1";
    IPAddress ip
    = IPAddress.Parse(host);

    // string hotByname = "www.baidu.com";
    // IPHostEntry gist = Dns.GetHostByName(hotByname);
    //IPAddress ip = gist.AddressList[0];
    /**/
    ///创建终结点EndPoint

    //IPAddress ipp = new IPAddress("127.0.0.1");
    IPEndPoint ipe = new IPEndPoint(ip, port);//把ip和端口转化为IPEndpoint实例

    /**/
    ///创建socket并连接到服务器
    Socket c = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);//创建Socket
    Console.WriteLine("Conneting…");
    c.Connect(ipe);
    //连接到服务器

    ///向服务器发送信息
    //{GET /index.php HTTP/1.0Content-Type: application/x-www-form-urlencoded
    StringBuilder buf = new StringBuilder();
    buf.Append(
    "GET ").Append("/index.php").Append(" HTTP/1.0\r\n");
    buf.Append(
    "Content-Type: application/x-www-form-urlencoded\r\n");
    buf.Append(
    "\r\n");
    byte[] bs = Encoding.ASCII.GetBytes(buf.ToString());//把字符串编码为字节
    Console.WriteLine("Send Message");
    c.Send(bs);
    //发送信息

    /**/
    ///接受从服务器返回的信息
    string recvStr = "";
    byte[] recvBytes = new byte[1024];
    int bytes;
    do
    {
    bytes
    = c.Receive(recvBytes, recvBytes.Length, 0);//从服务器端接受返回信息
    recvStr += Encoding.Default.GetString(recvBytes, 0, bytes);
    Console.WriteLine(
    "client get message:{0}", recvStr);//显示服务器返回信息

    }
    while (bytes!=0);

    /**/
    ///一定记着用完socket后要关闭
    c.Close();
    Console.ReadLine();

    以上有一个问题注意:

     GET /xxx.xxx HTTP/1.1
    Host: xxx
    Connection: Close  //没有关闭请求!

    只有加入这最后一行,对方发送完数据才会关闭连接,只有对方关闭连接,我们这边才能recv到一个0,

    从而根据recv返回的0判断接收数据完毕,然后我们就可以退出拼接数据包的循环。

  • 相关阅读:
    SQL复制多表数据
    ie与firefox 关于js 的差别(转载)
    水晶报表函数大全【收藏】
    ArcGIS Engine对象库
    SQL Server死锁总结(转载)
    C#制作鹰眼全过程(带注释)
    大块鸭
    【经典】jQuery使用大全
    TreeView控件失效引发的思考
    根据数据集动态生成TREE
  • 原文地址:https://www.cnblogs.com/and/p/1739482.html
Copyright © 2020-2023  润新知