在日常的开发中,我们用过很多开源的web服务器,例如tomcat、apache等等。现在我们自己实现一个简单的web服务器,基本的功能就是用户点击要访问的资源,服务器将资源发送到客户端的浏览器。为了简化操作,这里不考虑资源不存在等异常情况。web服务基于的是HTTP协议,用户在浏览器的地址栏输入要访问的地址,服务器如何得到该地址是个关键。先看下一般的HTTP请求和响应报文的一般格式:

HTTP 请求报文

HTTP 响应报文

web服务器获取一个用户的连接时,会初始化一个线程和用户通信,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.net.Socket;
 
 
//每有一个连接建立时,服务器分出一个通信的线程
public class CommunicateThread extends Thread{
    //与客户端通信的套接字
    Socket client;
     
    public CommunicateThread(Socket s) {
        client = s;
    }
     
    //获取浏览器请求资源的路径
    public String getResourcePath(String s){
        // 一般的HTTP请求报文的第一行是“GET /index.html HTTP/1.1”
        // 我们要获取的就是中间的"/indext.apsx"
         
        //获取资源的位置
        String s1 = s.substring(s.indexOf(' ')+1);
        s1 = s1.substring(1,s1.indexOf(' '));
         
        //默认资源为index.html
        if(s1.equals(""))
            s1 = "index.html";
         
        return s1;
    }
 
    public void sendFile(PrintStream out,File file){
        try{
            DataInputStream in  = new DataInputStream(new FileInputStream(file));
            int len = (int)file.length();
            byte buf[] = new byte[len];
            in.readFully(buf);//读取文内容到buf数组中
            out.write(buf,0,len);
            out.flush();
            in.close();
        }
        catch(Exception e){
            System.out.println(e.getMessage());
            System.exit(1);
            }
    }
     
    public void run(){
        try{
            //获取用户的IP地址和端口号
            String clientIP = client.getInetAddress().toString();
            int clientPort = client.getPort();
            //创建输出流对象
            PrintStream out = new PrintStream(client.getOutputStream());
            //创建输入流对象
            DataInputStream in = new DataInputStream(client.getInputStream());
            //读取浏览器提交的请求
            String msg = in.readLine();
             
             
            //获取文件路径
            String fileName = getResourcePath(msg);
            System.out.println("The user asked for resource: "+fileName);
            File file = new File(fileName);
             
            if(file.exists()){
                //根据响应报文格式设置
                System.out.println(fileName+" start send");
                 
                out.println("HTTP/1.0 200 OK");
                out.println("MIME_version:1.0");
                out.println("Content_Type:text/html");
                int len = (int) file.length();
                out.println("Content_Length:"+len);
                out.println("");//报文头和信息之间要空一行
                 
                //发送文件
                sendFile(out,file);
                 
                out.flush();
            }  
            client.close();    
        }
        catch(Exception e){
            System.out.println(e.getMessage());
        }      
    }
     
 
 
}

服务器主要负责初始化套接字和线程,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.net.ServerSocket;
import java.net.Socket;
 
 
public class WebServer {
 
 
    public static void main(String[] args) {
        int Port = 12345;//端口号,由于这里是测试,所以不要使用常用端口
        //创建两个套接字
        ServerSocket server = null;
        Socket client = null;
        try{
            server = new ServerSocket(Port);
            //服务器开始监听
            System.out.println("The WebServer is listening on port "+server.getLocalPort());
            while(true){
                client = server.accept();
                //多线程运行
                new CommunicateThread(client).start();
            }
        }catch(Exception e){
            System.out.println(e.getMessage());
        }
    }
 
}

运行测试:

编写一个index.html文件

1
<h1>This is the index of my WebServer</h1><hr>

放到项目文件的根目录,然后在浏览器地址栏输入:“localhost:12345/index.html”,就可以看到位于服务器端的html文件了。注意由于服务器是死循环,重启服务器会发现指定的端口已被绑定,只需要进入任务管理器,关闭"Java(TM) Platfrom SE binary"进程即可。最后结果如下所示:

这个服务器程序很简陋,还有很大的改进余地。大家可以自己尝试改进。这里可以尝试一下访问其他的文件,发现时成功的,说明这服务器很不安全呀。

java实现简单web服务器(分析+源代码)的更多相关文章

  1. Java 18 新特性:简单Web服务器 jwebserver

    在今年3月下旬的时候,Java版本已经更新到了18.接下来DD计划持续做一个系列,主要更新从Java 9开始的各种更新内容,但我不全部都介绍,主要挑一些有意思的内容,以文章和视频的方式来给大家介绍和学 ...

  2. C#中使用Socket实现简单Web服务器

    上一篇博客中介绍了怎样使用socket访问web服务器.关键有两个: 熟悉Socket编程: 熟悉HTTP协议. 上一篇主要是通过socket来模拟浏览器向(任何)Web服务器发送(HTTP)请求,重 ...

  3. tomcat解析之简单web服务器(图)

    链接地址:http://gogole.iteye.com/blog/587163 之前有javaeyer推荐了一本书<how tomcat works>,今天晚上看了看,确实不错,第一眼就 ...

  4. Socket网络编程--简单Web服务器(1)

    这一次的Socket系列准备讲Web服务器.就是编写一个简单的Web服务器,具体怎么做呢?我也不是很清楚流程,所以我找来了一个开源的小的Web服务器--tinyhttpd.这个服务器才500多行的代码 ...

  5. Socket网络编程--简单Web服务器(6)

    本来是想实现ssl连接的,但是弄了好久都不成功,就索性不做了,等以后有能力再做了.所以这一小节就是本次的最后一节了.就简单的说几个注意点. 1.加个配置文件 使用单例模式,使用一个类,该类保存一些信息 ...

  6. 理解与模拟一个简单web服务器

    先简单说下几个概念,根据自己的理解,不正确请见谅. web服务器 首先要知道什么是web服务器,简单说web服务器就是可以使用HTTP传输协议与客户端进行通信的服务器.最初的web服务器只能用来处理静 ...

  7. 用java写一个web服务器

    一.超文本传输协议 Web服务器和浏览器通过HTTP协议在Internet上发送和接收消息.HTTP协议是一种请求-应答式的协议——客户端发送一个请求,服务器返回该请求的应答.HTTP协议使用可靠的T ...

  8. Socket网络编程--简单Web服务器(3)

    上一小节已经实现了浏览器发送请求,然后服务器给出应答信息,然后浏览器显示出服务器发送过来的网页.一切看起来都是那么的美好.这一小节就准备实现可以根据地址栏url的不同来返回指定的网页.目前还不考虑带参 ...

  9. Socket网络编程--简单Web服务器(4)

    上一小节已经实现了对图片的传输,接下来就是判断文件是否为js,css,png等格式.我们增加一个函数用于判断格式 int WebServer::get_filetype(char *type,char ...

随机推荐

  1. 挑战一下吧!C#测试开发工程师英语面试题

    1. Given a rectangular (cuboidal for the puritans) cake with a rectangular piece removed (any size o ...

  2. ice cave

    Description You play a computer game. Your character stands on some level of a multilevel ice cave. ...

  3. 如何使用Gmail的别名功能?

    Gmail真的是一个很好的邮箱,一直是我的最爱!它有一个很独特的功能-别名,用这个功能,我们就可以把一个 邮箱当成很多个邮箱来使用了! 1.Gmail 不提供传统别名 ,但是你可以收到发送到 your ...

  4. 快速排序算法之我见(附上C代码)

    因为<The C Programming Language>一书中有一个练习,需要用到快速排序,所以又复习了一下,感觉收获颇多,故而分享之. 快速排序的核心是一种 divide and c ...

  5. MFC程序的消息处理顺序

    MFC应用程序中处理消息的顺序 1.AfxWndProc()      该函数负责接收消息,找到消息所属的CWnd对象,然后调用AfxCallWndProc 2.AfxCallWndProc()  该 ...

  6. 基于MMSeg算法的中文分词类库

    原文:基于MMSeg算法的中文分词类库 最近在实现基于lucene.net的搜索方案,涉及中文分词,找了很多,最终选择了MMSeg4j,但MMSeg4j只有Java版,在博客园上找到了*王员外*(ht ...

  7. 手把手教你_android自己主动化实践方案选型

    接到一个android自己主动化的任务,看了看手中的家伙:ranorex,appium,uiautomator 当然先捡商用的试试,简单呀,能够录制回放,只是不是抱特别大的期望,这个爷比較娇气,要是a ...

  8. 如何去掉List中的重复内容

    1.通过循环进行删除 public static void removeDuplicate(List list) { ; i < list.size() - ; i ++ ) { ; j > ...

  9. C++ 多源码文件简单组织

    C++ 多源码文件简单组织 基本上和C的是一样的,只不过C++的方法要在类中声明.看一个简单实例.ainimal.h  类里面对外公开的信息. 点击(此处)折叠或打开 #ifndef _ANIMAL_ ...

  10. php 上传文件 $_FILES['']['type']的值

    php 上传文件 $_FILES['']['type']的值 一个函数 function upload_file($fname,$ftype,$fsize,$ferror,$ftmp_name,$fp ...