一、基本思路:

1、服务器端通过socket(), 监听在TCP 8080端口,等待客户端来连接。

2、服务器端解析客户端的HTTP请求中的URI值,把本地的目录下指定文件通过java的读取文件的方式getResourceAsStream()发送给客户端。

3、客户端把应用程序的第一个参数作为目标文件,传到HTTP请求中。

二、总结:

1、服务器端终究是通过解析HTTP请求中的内容,取到目标文件,并且服务器端的字节码文件,必须和root目录放一起。

2、java有现成的类的方法,获得socket中的内容,服务器端的成功返回,也是服务器自行构造的。

三、源码

1、服务器端代码:

 package server;
import java.io.*;
import java.net.*; public class HTTPServer{
public static void main(String args[]) {
int port;
ServerSocket serverSocket; try {
port = Integer.parseInt(args[0]);
}catch (Exception e) {
System.out.println("port = 8080 (默认)");
port = 8080; //默认端口为8080
} try{
serverSocket = new ServerSocket(port);
System.out.println("服务器正在监听端口:" + serverSocket.getLocalPort()); while(true) { //服务器在一个无限循环中不断接收来自客户的TCP连接请求
try{
//等待客户的TCP连接请求
final Socket socket = serverSocket.accept();
System.out.println("建立了与客户的一个新的TCP连接,该客户的地址为:"+
socket.getInetAddress()+":" + socket.getPort()); service(socket); //响应客户请求
}catch(Exception e){e.printStackTrace();}
} //#while
}catch (Exception e) {e.printStackTrace();}
} /** 响应客户的HTTP请求 */
public static void service(Socket socket)throws Exception{ /*读取HTTP请求信息*/
InputStream socketIn=socket.getInputStream(); //获得输入流
Thread.sleep(500); //睡眠500毫秒,等待HTTP请求
int size=socketIn.available();
byte[] requestBuffer=new byte[size];
socketIn.read(requestBuffer);
String request=new String(requestBuffer);
System.out.println(request); //打印HTTP请求数据 /*解析HTTP请求*/
//获得HTTP请求的第一行
String firstLineOfRequest=request.substring(0,request.indexOf("\r\n"));
//解析HTTP请求的第一行
String[] parts=firstLineOfRequest.split(" ");
String getMethod = "GET";
if(true != parts[0].equals("GET"))
{
System.out.println("client Bad request:" + parts[0] + " method length=" + parts[0].length() ); //打印错误的请求
System.out.println("correct request is:" + getMethod );
} String uri=parts[1]; //获得HTTP请求中的uri /*决定HTTP响应正文的类型*/
String contentType;
if(uri.indexOf("html")!=-1 || uri.indexOf("htm")!=-1)
contentType="text/html";
else if(uri.indexOf("jpg")!=-1 || uri.indexOf("jpeg")!=-1)
contentType="image/jpeg";
else if(uri.indexOf("gif")!=-1)
contentType="image/gif";
else
contentType="application/octet-stream"; /*创建HTTP响应结果 */
//HTTP响应的第一行
String responseFirstLine="HTTP/1.1 200 OK\r\n";
//HTTP响应头
String responseHeader="Content-Type:"+contentType+"\r\n\r\n";
//获得读取响应正文数据的输入流
InputStream in=HTTPServer.class.getResourceAsStream("root/"+uri); /*发送HTTP响应结果 */
OutputStream socketOut=socket.getOutputStream(); //获得输出流
//发送HTTP响应的第一行
socketOut.write(responseFirstLine.getBytes());
//发送HTTP响应的头
socketOut.write(responseHeader.getBytes());
//发送HTTP响应的正文
int len=0;
byte[] buffer=new byte[128];
while((len=in.read(buffer))!=-1)
socketOut.write(buffer,0,len); Thread.sleep(1000); //睡眠1秒,等待客户接收HTTP响应结果
socket.close(); //关闭TCP连接 }
} /****************************************************
* 作者:孙卫琴 *
* 来源:<<Tomcat与Java Web开发技术详解>> *
* 技术支持网址:www.javathinker.org *
***************************************************/

客户端代码:

 package client;
import java.net.*;
import java.io.*;
import java.util.*; public class HTTPClient {
public static void main(String args[]){
//确定HTTP请求的uri
String uri="index.htm";
if(args.length !=0)uri=args[0]; doGet("localhost",8080,uri); //按照GET请求方式访问HTTPServer
} /** 按照GET请求方式访问HTTPServer */
public static void doGet(String host,int port,String uri){
Socket socket=null; try{
socket=new Socket(host,port); //与HTTPServer建立FTP连接
}catch(Exception e){e.printStackTrace();} try{
/*创建HTTP请求 */
StringBuffer sb=new StringBuffer("GET1 "+uri+" HTTP/1.1\r\n");
sb.append("Accept: */*\r\n");
sb.append("Accept-Language: zh-cn\r\n");
sb.append("Accept-Encoding: gzip, deflate\r\n");
sb.append("User-Agent: HTTPClient\r\n");
sb.append("Host: localhost:8080\r\n");
sb.append("Connection: Keep-Alive\r\n\r\n"); /*发送HTTP请求*/
OutputStream socketOut=socket.getOutputStream(); //获得输出流
socketOut.write(sb.toString().getBytes()); Thread.sleep(2000); //睡眠2秒,等待响应结果 /*接收响应结果*/
InputStream socketIn=socket.getInputStream(); //获得输入流
int size=socketIn.available();
byte[] buffer=new byte[size];
socketIn.read(buffer);
System.out.println(new String(buffer)); //打印响应结果 }catch(Exception e){
e.printStackTrace();
}finally{
try{
socket.close();
}catch(Exception e){e.printStackTrace();}
}
} //#doGet()
} /****************************************************
* 作者:孙卫琴 *
* 来源:<<Tomcat与Java Web开发技术详解>> *
* 技术支持网址:www.javathinker.org *
***************************************************/

四、运行方法:

1、先运行服务器端,以便等待客户端的连接:

2、再启动客户端,发送http 请求:

3、观察服务器端的输出:

特别说明,在本程序中,已经判断出客户端写错了GET请求,写成了GET1,但是,这里判断不严格,只是捕获出来了,但是不影响程序继续运行。

Java实践:一个简易的http server和client的java源码学习和总结。的更多相关文章

  1. Java集合专题总结(1):HashMap 和 HashTable 源码学习和面试总结

    2017年的秋招彻底结束了,感觉Java上面的最常见的集合相关的问题就是hash--系列和一些常用并发集合和队列,堆等结合算法一起考察,不完全统计,本人经历:先后百度.唯品会.58同城.新浪微博.趣分 ...

  2. Seata Server 1.5.2 源码学习

    Seata 包括 Server端和Client端.Seata中有三种角色:TC.TM.RM,其中,Server端就是TC,TM和RM属Client端.Client端的源码学习上一篇已讲过,详见 < ...

  3. 使用Python创建一个简易的Web Server

    Python 2.x中自带了SimpleHTTPServer模块,到Python3.x中,该模块被合并到了http.server模块中.使用该模块,可以快速创建一个简易的Web服务器. 我们在C:\U ...

  4. Java并发包源码学习之AQS框架(四)AbstractQueuedSynchronizer源码分析

    经过前面几篇文章的铺垫,今天我们终于要看看AQS的庐山真面目了,建议第一次看AbstractQueuedSynchronizer 类源码的朋友可以先看下我前面几篇文章: <Java并发包源码学习 ...

  5. Java并发包源码学习之AQS框架(三)LockSupport和interrupt

    接着上一篇文章今天我们来介绍下LockSupport和Java中线程的中断(interrupt). 其实除了LockSupport,Java之初就有Object对象的wait和notify方法可以实现 ...

  6. Java并发包源码学习之AQS框架(一)概述

    AQS其实就是java.util.concurrent.locks.AbstractQueuedSynchronizer这个类. 阅读Java的并发包源码你会发现这个类是整个java.util.con ...

  7. java Integer 源码学习

    转载自http://www.hollischuang.com/archives/1058 Integer 类在对象中包装了一个基本类型 int 的值.Integer 类型的对象包含一个 int 类型的 ...

  8. Java开源生鲜电商平台-系统架构与技术选型(源码可下载)

    Java开源生鲜电商平台-系统架构与技术选型(源码可下载) 1.  硬件环境 公司服务器 2.   软件环境 2.1  操作系统 Linux CentOS 6.8系列 2.2 反向代理/web服务器 ...

  9. java io系列12之 BufferedInputStream(缓冲输入流)的认知、源码和示例

    本章内容包括3个部分:BufferedInputStream介绍,BufferedInputStream源码,以及BufferedInputStream使用示例. 转载请注明出处:http://www ...

随机推荐

  1. proxy_pass根据path路径转发时的"/"问题记录

    在nginx中配置proxy_pass时,如果是按照^~匹配路径时,要注意proxy_pass后的url最后的/.当加上了/,相当于是绝对根路径,则nginx不会把location中匹配的路径部分代理 ...

  2. Oracle SQL性能优化的40条军规

    1. SQL语句执行步骤 语法分析> 语义分析> 视图转换 >表达式转换> 选择优化器 >选择连接方式 >选择连接顺序 >选择数据的搜索路径 >运行“执 ...

  3. [Swift]LeetCode788. 旋转数字 | Rotated Digits

    X is a good number if after rotating each digit individually by 180 degrees, we get a valid number t ...

  4. [Swift]LeetCode789. 逃脱阻碍者 | Escape The Ghosts

    You are playing a simplified Pacman game. You start at the point (0, 0), and your destination is (ta ...

  5. [Swift]LeetCode904. 水果成篮 | Fruit Into Baskets

    In a row of trees, the i-th tree produces fruit with type tree[i]. You start at any tree of your cho ...

  6. MySql综合知识汇总

    本文实验的测试环境:Windows 10+cmd+MySQL5.6.36+InnoDB Mysql驱动:com.mysql.jdbc.Driver MysqlURL:jdbc:mysql://loca ...

  7. kubernetes系列之ConfigMap使用方式

    作用理解 核心用途就是容器和配置的分离解耦. 如启用一个mysql容器,mysql容器重要的文件有两部分,一部分为存储数据文件,一部分为配置文件my.cnf,存储数据可以用持久存储实现和容器的分离解耦 ...

  8. 使用reflector对.NET反编译

    reflector的下载地址:https://www.cr173.com/soft/355285.html 反编译后的结果:

  9. asp.net core系列 31 EF管理数据库架构--必备知识 反向工程

    一.   反向工程 反向工程是基于数据库架构,生成的实体类和DbContext类代码的过程,对于Visual Studio开发,建议使用PMC.对于其他开发环境,请选择.NET Core CLI工具( ...

  10. Python爬虫入门教程 6-100 蜂鸟网图片爬取之一

    1. 蜂鸟网图片--简介 国庆假日结束了,新的工作又开始了,今天我们继续爬取一个网站,这个网站为 http://image.fengniao.com/ ,蜂鸟一个摄影大牛聚集的地方,本教程请用来学习, ...