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判断接收数据完毕,然后我们就可以退出拼接数据包的循环。

 

你可能感兴趣的:(Scoket)