Socket编程之Tomcat模拟_采坑汇总
用java.net.Socket来模拟实现Tomcat,碰到了一些坑,大部分是没有想到的,记录下来自查。
直接上代码,
public class TomcatDemo {
    private static ExecutorService executorService = Executors.newCachedThreadPool();
    public static void main(String[] args) throws IOException {
        //监听9000端口
        @SuppressWarnings("resource")
        ServerSocket serverSocket = new ServerSocket(9000);
        System.out.println("Tomcat服务启动成功!");
        while (!serverSocket.isClosed()) {
            //阻塞式
            Socket request = serverSocket.accept();
            System.out.println(request.getInetAddress());
            executorService.execute(() -> {
                try {
                    InputStream inputStream = request.getInputStream();
                    System.out.println("收到请求...");
                    BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
                    StringBuffer sb = new StringBuffer();
                    String line;
                    while((line = br.readLine()) != null) {
                        sb.append(line).append("\r\n");
                    }
                    System.out.println(sb.toString());
                    //由servlet处理业务逻辑
                    System.out.println("-----------------end");
                    //请求结束...
                    OutputStream outputStream = request.getOutputStream();
                    outputStream.write("HTTP/1.1 200 OK\r\n".getBytes());
                    outputStream.write(("Content-Length: " + "Hello World!".getBytes().length + "\r\n\r\n").getBytes());
                    outputStream.write("Hello World!".getBytes());
                    outputStream.flush();
                    System.out.println("请求结束...");
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        request.close();
                    } catch (Exception e2) {
                        e2.printStackTrace();
                    }
                }
            });
        }
    }
}
运行程序,使用Chrome访问localhost:9000

问题有两个,
(1) 竟然发起两次GET请求
(2) 出现socket write error
起初开始解决socket write error,大多数说是因为socket提前close或者超时导致的,但是发起的请求还没有结束。后来一步步调试,发现代码在 line = br.readLine()) != null 处阻塞等待了!
原来是br.readLine()的机制同自己想的并不一样,它是阻塞式的,叉掉http://localhost:9000/的请求后,后续代码才继续被执行。

增加如下判断代码解决,
while((line = br.readLine()) != null) {
    if (line.length() == 0){
        break;
    }
    sb.append(line).append("\r\n");
}
但是socket write error的问题还在,这个应该就和重复请求有关系了。
改用Firefox访问http://localhost:9000/,发现请求正常,

看来是Chrome的问题,遂查了下,应该是插件造成的请求重复发送,这也导致了如上socket write error的问题。
用Chrome访问还会出现请求/favicon.ico,这个是Chrome后台默默做的,用来显示和网站相关的信息。这也正是平时大家说的Chrome一次GET请求,出现两次的根源。

Socket编程之Tomcat模拟_采坑汇总的更多相关文章
- PHP Socket 编程之9个主要函数的使用之测试案例
		
php的socket编程算是比较难以理解的东西吧,不过,我们只要理解socket几个函数之间的关系,以及它们所扮演的角色,那么理解起来应该不是很难了,在笔者看来,socket编程,其实就是建立一个网络 ...
 - [深入浅出WP8.1(Runtime)]Socket编程之UDP协议
		
13.3 Socket编程之UDP协议 UDP协议和TCP协议都是Socket编程的协议,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议.UDP适用于一次只 ...
 - iPhone socket 编程之BSD Socket篇
		
iPhone socket 编程之BSD Socket篇 收藏在进行iPhone网络通讯程序的开发中,不可避免的要利用Socket套接字.iPhone提供了Socket网络编程的接口CFSocket, ...
 - 老雷socket编程之websocket实现
		
老雷socket编程之websocket实现 我们主要实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocket.websocket是一种可以双向通讯的 ...
 - 老雷socket编程之PHP利用socket扩展实现聊天服务
		
老雷socket编程之PHP利用socket扩展实现聊天服务 socket聊天服务原理 PHP有两个socket的扩展 sockets和streamssockets socket_create(AF_ ...
 - C#编程 socket编程之tcp服务器端和客户端
		
基于Tcp协议的Socket通讯类似于B/S架构,面向连接,但不同的是服务器端可以向客户端主动推送消息. 使用Tcp协议通讯需要具备以下几个条件: (1).建立一个套接字(Socket) (2).绑定 ...
 - C#编程 socket编程之udp服务器端和客户端
		
基于Udp协议是无连接模式通讯,占用资源少,响应速度快,延时低.至于可靠性,可通过应用层的控制来满足.(不可靠连接) 使用Udp协议通讯需要具备以下几个条件: (1).建立一个套接字(Socket) ...
 - Python socket编程之二:【struct.pack】&【struct.unpack】
		
import struct """通过 socket 的 send 和 recv 只能传输 str 格式的数据""" "" ...
 - Linux系统编程(37)—— socket编程之UDP服务器与客户端
		
典型的UDP客户端/服务器通讯过程: 编写UDP Client程序的步骤 1.初始化sockaddr_in结构的变量,并赋值.这里使用"8888"作为连接的服务程序的端口,从命令行 ...
 
随机推荐
- poj2976(01分数规划)
			
poj2976 题意 给出 a b 数组,一共 n 对数,其中最多可以去掉 k 对,问怎样使剩下比率(原始比率是 $ \frac{\sum_{i=1}^{n} a}{\sum_{i=1}^{n} b} ...
 - 反汇编引擎Capstone
			
反汇编引擎Capstone Capstone是Kali Linux自带的一款轻量级反汇编引擎.它可以支持多种硬件构架,如ARM.ARM64.MIPS.X86.该框架使用C语言实现,但支持C++.P ...
 - [xsy2724]Tree
			
题意:给一棵树,找出$k$个点$A_{1\cdots k}$以最小化$\begin{align*}\sum\limits_{i=1}^{k-1}dis_{A_i,A_{i+1}}\end{align* ...
 - protostuff序列化使用
			
背景 最近在做项目的时候需要使用持久化功能,1.0版本中使用的akka自带的持久化功能,使用的是akka persist支持的redis插件,在使用的过程中踩了一些坑.因此,在而2.0版本中考虑自己往 ...
 - Linux下进行Web服务器压力(并发)测试工具http_load、webbench、ab、Siege、autobench简单使用教程(转)
			
一.http_load 程序非常小,解压后也不到100K http_load以并行复用的方式运行,用以测试web服务器的吞吐量与负载.但是它不同于大多数压力测试工 具,它可以以一个单一的进程运行,一般 ...
 - NSOperationQueue 和 NSOperation
			
The NSOperationQueue class regulates the execution of a set of NSOperation objects. After being adde ...
 - jar文件的Eclipse插件安装
			
以[zigen.plugin.db_1.2.2.v20101009.jar]为例. (1)在[\eclipse\dropins]目录下新建一个目录,例如[myplugin] (2)上面新建的n目录下建 ...
 - 【Hadoop】Hadoop MR 性能优化 Combiner机制
			
1.概念 2.参考资料 提高hadoop的mapreduce job效率笔记之二(尽量的用Combiner) :http://sishuo(k).com/forum/blogPost/list/582 ...
 - Docker以及registry的入门学习安装
			
一.前言 如果你是数据中心或云计算IT圈子的人,我想你一定听过Docker,关于它们的新闻从未间断过.Docker的发展历程虽然算不上太长,但是自2014年6月Docker 1.0 正式发布,但是Do ...
 - SQLiteDatabase中query、insert、update、delete方法参数说明
			
1.SQLiteDataBase对象的query()接口: public Cursor query (String table, String[] columns, String selection, ...