ArticleDirectory
- Enable Service
- Analyze packets and process requests
- Summary
With the following knowledge:
What is unknown about ASP. NET (1)
What is unknown about ASP. NET (2)
I think it is no longer a problem to develop a small server. The function is complicated and can respond to client browser requests and return response information based on the type of request file, such as processing static pages, images, styles, scripts, and dynamic pages. Review
The communication between the client and the server is through socket, and the "language" of the communication is based on http1.1 protocol. Based on this clue, we can develop our own server software and call it melodies server for the time being. Of course this is a very simple example. There is still a gap with the real server, first, we need to understand the following knowledge points:
- The client communicates with the server through a socket. The server must have a socket for listening requests. It is bound to a port number. If a request is sent, the socket. accept () generates a socket to communicate with the client.
- The requests (packets) sent by the client are sent to the server software for analysis to determine whether they are static pages, images, or dynamic aspx files. If they are static files, they can be directly returned.
- It is a little difficult to process dynamic pages and requires reflection to create page classes (For details, refer to the unknown ASP. NET (2 ))
Enable Service
Public partial class webserverform: FORM {public webserverform () {initializecomponent (); textbox. checkforillegalcrossthreadcils = false;} private socket socketwatch; // listens to the socket private thread threadwatch of the browser connection request; // calls the socket cyclically. accept listening thread private void btnstartserver_click (Object sender, eventargs e) {socketwatch = new socket (addressfamily. interNetwork, sockettype. stream, protocoltype. TCP); IPaddress address = IPaddress. parse (txtipaddress. text. trim (); ipendpoint endpoint = new ipendpoint (address, Int. parse (txtport. text. trim (); socketwatch. BIND (endpoint); socketwatch. listen (10); threadwatch = new thread (watchconnect); threadwatch. isbackground = true; threadwatch. start ();} private bool iswatch = true; // dictionary <> void watchconnect () {While (iswatch) {socket socketconnection = socketwatch. accept (); showmsg ("browser:" + socketconnection. remoteendpoint. tostring () + ", connection successful ********************"); connectionclient = new connectionclient (socketconnection, showmsg) ;}} void showmsg (string MSG) {txtlog. appendtext (MSG + "\ r \ n ");}}
Analyze packets and process requests
- The socket created in the asynchronous thread to communicate with the client, its main responsibility is to analyze the letter:
/// <Summary> /// communication class for connecting to the client (including a socket and communication thread that communicates with the client) /// </Summary> public class connectionclient {private socket socketmsg; // communication socket private thread threadmsg; // communication thread private dgshowmsg; // delegate public connectionclient (Socket socket, dgshowmsg) that displays messages to the main form text box {This. socketmsg = socket; this. dgshowmsg = dgshowmsg; // starts a thread that accepts client browser request packets. threadmsg = new thread (receivemsg); threadmsg. isbac Kground = true; threadmsg. start ();} private bool isrec = true; void receivemsg () {While (isrec) {byte [] arrmsg = new byte [1024*1024*3]; // accept the request message int length = socketmsg sent from the client. receive (arrmsg); string strmsg = system. text. encoding. utf8.getstring (arrmsg, 0, length); dgshowmsg (strmsg); // process the message string [] arrstr = strmsg. replace ("\ r \ n", "success "). split ('failed'); string [] firstrow = arrstr [0]. split (''); string R Equestfile = firstrow [1]; excuterequest (requestfile); // todo: duration of persistent connections} private void excuterequest (string requestfile) {// obtain the suffix string fileextension = system of the requested page. io. path. getextension (requestfile); If (! String. isnullorempty (fileextension) {Switch (fileextension. tolower () {Case ". html ": Case ". htm ": Case ". CSS ": Case ". JS ": excutestaticpage (requestfile, fileextension); break; case ". jpg ": excuteimg (requestfile, fileextension); break; case ". aspx ": excutedympage (requestfile, fileextension); break ;}}}
- perform different operations on different requests. Static pages, CSS, JS, and image processing are all static attribute files, and the byte stream is directly returned:
/// <Summary> /// process static pages and output them directly /// </Summary> private void excutestaticpage (string requestpath, string fileextension) {stringbuilder sb = new stringbuilder (); // obtain the physical path of the folder in the request file string datadir = appdomain. currentdomain. basedirectory; If (datadir. endswith (@ "\ bin \ debug \") | datadir. endswith (@ "\ bin \ release \") {datadir = system. io. directory. getparent (datadir ). parent. parent. fullname;} string phypath = datadir + requestpath; // read static page content string filecontent = system. io. file. readalltext (phypath); // get the response body byte array byte [] filearr = system. text. encoding. utf8.getbytes (filecontent); // get the response header: String responseheader = getResponseHeader (filearr. length, fileextension); byte [] arrhead = system. text. encoding. utf8.getbytes (responseheader); // send the Response Header back to the browser socketmsg. send (arrhead); // send the response to the style and return it to the browser. // todo: what will happen to socketmsg in 1 minute during sleep. send (filearr );} /// <summary> /// process the image /// </Summary> /// <Param name = "requestpath"> </param> /// <Param name = "extentionname"> </param> private void excuteimg (string requestpath, string extentionname) {// the physical path of the folder for obtaining the request file string datadir = appdomain. currentdomain. basedirectory; If (datadir. endswith (@ "\ bin \ debug \") | datadir. endswith (@ "\ bin \ release") {datadir = system. io. directory. getparent (datadir ). parent. parent. fullname;} // obtain the physical path (absolute path) of the request file string phypath = datadir + requestpath; int imglength; byte [] filearr; // read the image content using (filestream FS = new filestream (phypath, filemode. open) {filearr = new byte [FS. length]; imglength = FS. read (filearr, 0, filearr. length); // obtain the response header string responseheader = getResponseHeader (imglength, extentionname); byte [] arrheader = system. text. encoding. utf8.getbytes (responseheader); socketmsg. send (arrheader); socketmsg. send (filearr, imglength, socketflags. none );}} /// <summary> /// get the response header information /// </Summary> /// <Param name = "contentlength"> </param> /// <Param name = "fileextentionname"> </param> // <returns> </returns> private string getResponseHeader (INT contentlength, string fileextentionname) {stringbuilder sbheader = new stringbuilder (); sbheader. append ("HTTP/1.1 200 OK \ r \ n"); sbheader. append ("Content-Length:" + contentlength + "\ r \ n"); sbheader. append ("Content-Type:" + getresponseheadcontenttype (fileextentionname) + "; charset = UTF-8 \ r \ n"); Return sbheader. tostring ();} /// <summary> /// obtain the content type in the Response Letter according to the suffix. /// </Summary> /// <Param name = "fileextentionname"> </param>/ // <returns> </returns> private string getresponseheadcontenttype (string fileextentionname) {Switch (fileextentionname. tolower () {Case ". html ": Case ". htm ": Case ". aspx ": Return" text/html "; break; case ". CSS ": Return" text/plain "; break; case ". JS ": Return" text/JavaScript "; break; case ". jpg ": Return" image/JPEG "; case ". GIF ": Return" image/GIF "; break; default: Return" text/html "; break ;}}
- Similarly, create a page class for dynamic page reflection. Remember to implement the ihttphandler interface.
- Create a page view
Public Class View: ihttphandler {Public String processrequest () {string datadir = appdomain. currentdomain. basedirectory; // obtain the template physical path if (datadir. endswith (@ "\ bin \ debug \") | datadir. endswith (@ "\ bin \ release") {datadir = system. io. directory. getparent (datadir ). parent. parent. fullname;} string phypath = datadir + "/model.htm"; string modelcontent = system. io. file. readalltext (phypath); modelcontent = modelcontent. replace ("@ title", "dynamic page "). replace ("@ content", "Reflection page class"); Return modelcontent ;}}
- Reflection view, call its processrequest method to execute the serverCode
/// <Summary> /// reflection creates a dynamic page object /// </Summary> /// <Param name = "requestfile"> </param> // <param name = "extentionname"> </param> private void excutedympage (string requestfile, string extentionname) {string pageclassname = system. io. path. getfilenamewithoutextension (requestfile); string assemblyname = assembly. getexecutingassembly (). getname (). name; // obtain the full name of the page class. pageclassname = assemblyname + ". "+ pageclas Sname; // create a page Class Object object pageobj = Assembly through reflection. getexecutingassembly (). createinstance (pageclassname); ihttphandler page = pageobj as ihttphandler; byte [] filearr = NULL; If (page! = NULL) {string strhtml = page. processrequest (); filearr = system. text. encoding. utf8.getbytes (strhtml);} // obtain the response header string responseheader = getResponseHeader (filearr. length, extentionname); byte [] arrheader = system. text. encoding. utf8.getbytes (responseheader); socketmsg. send (arrheader); socketmsg. send (filearr );}
Summary
So far, a small server software has been built and tested.