用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模拟_采坑汇总的更多相关文章

  1. PHP Socket 编程之9个主要函数的使用之测试案例

    php的socket编程算是比较难以理解的东西吧,不过,我们只要理解socket几个函数之间的关系,以及它们所扮演的角色,那么理解起来应该不是很难了,在笔者看来,socket编程,其实就是建立一个网络 ...

  2. [深入浅出WP8.1(Runtime)]Socket编程之UDP协议

    13.3 Socket编程之UDP协议 UDP协议和TCP协议都是Socket编程的协议,但是与TCP协议不同,UDP协议并不提供超时重传,出错重传等功能,也就是说其是不可靠的协议.UDP适用于一次只 ...

  3. iPhone socket 编程之BSD Socket篇

    iPhone socket 编程之BSD Socket篇 收藏在进行iPhone网络通讯程序的开发中,不可避免的要利用Socket套接字.iPhone提供了Socket网络编程的接口CFSocket, ...

  4. 老雷socket编程之websocket实现

    老雷socket编程之websocket实现 我们主要实现私聊和群聊两个功能,要在web端实现想微信QQ那样的即时通讯的功能,我们需要了解一下websocket.websocket是一种可以双向通讯的 ...

  5. 老雷socket编程之PHP利用socket扩展实现聊天服务

    老雷socket编程之PHP利用socket扩展实现聊天服务 socket聊天服务原理 PHP有两个socket的扩展 sockets和streamssockets socket_create(AF_ ...

  6. C#编程 socket编程之tcp服务器端和客户端

    基于Tcp协议的Socket通讯类似于B/S架构,面向连接,但不同的是服务器端可以向客户端主动推送消息. 使用Tcp协议通讯需要具备以下几个条件: (1).建立一个套接字(Socket) (2).绑定 ...

  7. C#编程 socket编程之udp服务器端和客户端

    基于Udp协议是无连接模式通讯,占用资源少,响应速度快,延时低.至于可靠性,可通过应用层的控制来满足.(不可靠连接) 使用Udp协议通讯需要具备以下几个条件: (1).建立一个套接字(Socket) ...

  8. Python socket编程之二:【struct.pack】&【struct.unpack】

    import struct """通过 socket 的 send 和 recv 只能传输 str 格式的数据""" "" ...

  9. Linux系统编程(37)—— socket编程之UDP服务器与客户端

    典型的UDP客户端/服务器通讯过程: 编写UDP Client程序的步骤 1.初始化sockaddr_in结构的变量,并赋值.这里使用"8888"作为连接的服务程序的端口,从命令行 ...

随机推荐

  1. 新疆大学ACM-ICPC程序设计竞赛五月月赛(同步赛)- 勤奋的杨老师(最长递增子序列)

    链接:https://www.nowcoder.com/acm/contest/116/C来源:牛客网 题目描述 杨老师认为他的学习能力曲线是一个拱形.勤奋的他根据时间的先后顺序罗列了一个学习清单,共 ...

  2. Kruskal+LCA【p2245】 星际导航

    Description sideman做好了回到Gliese 星球的硬件准备,但是sideman的导航系统还没有完全设计好.为了方便起见,我们可以认为宇宙是一张有\(N\) 个顶点和\(M\) 条边的 ...

  3. Qt如何学习(参考官方文档)

    Designers who are familiar with web development can start with QML 一共有四种安装工具 You have following opti ...

  4. mac-command-line-doing

    创建文件夹 mkdir myDirectory 新建文件 touch a.html 编辑文件 vim a.html 删除文件 rm a.html 删除整个文件夹 rm -rf myDirectory ...

  5. HDOJ 3516 Tree Construction 四边形优化dp

    原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=3516 题意: 大概就是给你个下凸包的左侧,然后让你用平行于坐标轴的线段构造一棵树,并且这棵树的总曼哈顿 ...

  6. LA 3026 Period

    这只是蓝书上的一道KMP水题...然后对于最长前缀的循环证明我就不说了... #include<iostream> #include<cstring> #include< ...

  7. POJ 2109 Inner Vertices(扫描线+树状数组)

    [题目链接] http://poj.org/problem?id=3109 [题目大意] 在一个棋盘上放满白子,现在把一些白子变成黑子, 如果一个白子上下左右都有黑子,就会变成黑子,问最终黑子个数 [ ...

  8. java多线程设计模式(3)读写锁模式

    1 Read-Write Lock Pattern Read-Write Lock Pattern是一种将对于共享资源的访问与修改操作分离,称为读写分离.即访问是reader,修改是write,用单独 ...

  9. Linux性能监控工具收集(转)

    一.基于命令行的性能监控工具 1.dstat - 多类型资源统计工具 该命令整合了vmstat,iostat和ifstat三种命令.同时增加了新的特性和功能可以让你能及时看到各种的资源使用情况,从而能 ...

  10. web-51job(前程无忧)-账户、简历-数据库设计

    ylbtech-DatabaseDesgin:web-51job(前程无忧)-账户.简历-数据库设计   1.A,数据库关系图 1.B,数据库设计脚本 /App_Data/1,Account.sql ...