用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. 【bzoj2393】【Cirno的完美算数教室】容斥原理的剪枝应用

    (上不了p站我要死了,侵权度娘背锅) 在用容斥定理时,常常会用到dfs的形式,如果枚举完所有的情况可能会超时,其剪枝的优化很是重要. Description ~Cirno发现了一种baka数,这种数呢 ...

  2. Orchard EventBus 事件总线及 IEventHandler作用

    事件总线接口定义: public interface IEventBus : IDependency { IEnumerable Notify(string messageName, IDiction ...

  3. 解决413 Request Entity Too Large

    修改nginx配置    这是最简单的一个做法,着报错原因是nginx不允许上传配置过大的文件,那么件把nginx的上传大小配置调高就好. 1.打开nginx主配置文件nginx.conf,一般在/u ...

  4. [置顶] kubernetes--应用程序健康检查

    K8S的应用程序健康检查分为livenessProbe和readinessProbe,两者相似,但两者存在着一些区别. livenessProbe在服务运行过程中检查应用程序是否运行正常,不正常将杀掉 ...

  5. 【Spark】SparkContext源代码解读

    SparkContext的初始化 SparkContext是应用启动时创建的Spark上下文对象,是进行Spark应用开发的主要接口,是Spark上层应用与底层实现的中转站(SparkContext负 ...

  6. JavaScript入门:006—JS函数的定义

    JS函数的声明. 声明函数的格式例如以下: function 函数名(參数列表){ //函数语句: return 返回值; } 来看详细的函数声明.1.普通函数 <script type=&qu ...

  7. linux /etc/hosts 配置问题

    在java code中获取本机IP的程序如下: import java.net.InetAddress; public class Test { public static void main(Str ...

  8. .Net程序测试使用阿里云OCS开放缓存服务

     首先需要有一个阿里的OCS实例和ECS云服务器 请确认这两个是在同一个可用区的,这个很重要! 这两个可以在阿里云官网申请得到 拿到OCS之后 进入OCS控制台,点击下面的客户端下载选择.Net客 ...

  9. 质量平台建设之Mock平台

    转载:http://blog.csdn.net/spark2008/article/details/51372913 基于目前系统越来越多,在项目开发过程中,减少各模块之间的开发依赖,另保证各个系统模 ...

  10. java学习笔记——Collection集合接口

    NO 方法名称 描述 1 public boolean add(E e) 向集合中保存数据 2 public void clear() 清空集合 3 public boolean contains(O ...