一、基本思路:

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. [WEB]绕过安全狗与360PHP一句话的编写

    00x01安全狗的确是让人很头痛,尤其是在上传一句话或者写入一句话的时候,会被安全狗拦截从而拿不下shell.当然,安全狗是最简单的一款waf,很容易就进行一个绕过.00x02对于绕过安全狗跟360, ...

  2. [Swift]LeetCode90. 子集 II | Subsets II

    Given a collection of integers that might contain duplicates, nums, return all possible subsets (the ...

  3. [Swift]LeetCode741. 摘樱桃 | Cherry Pickup

    In a N x N grid representing a field of cherries, each cell is one of three possible integers. 0 mea ...

  4. [Swift]LeetCode1020. 飞地的数量 | Number of Enclaves

    Given a 2D array A, each cell is 0 (representing sea) or 1 (representing land) A move consists of wa ...

  5. mysql 主主+ Keepalived 高可用

    这是在mysql互为主从的基础上做的 yum -y install keepalived    #两台机器上都装 配置Keepalived主从, vrrp_instance VI_1 { state ...

  6. SpringBoot环境搭建

    创建 maven 项目 , 选择的打包类型为 jar 类型 自己构建 SpringBoot 项目时 , 要继承 SpringBoot 的父项目 , 这里用的版本是 2.1.4 点击 Finish , ...

  7. GoJS学习笔记

    GoJS 和 GO 语言没有关系,它是一个用来创建交互式图表的 JavaScript 库. 基础概念 GraphObject 是所有图形是抽象基类,基本上 GoJS 中,万物皆 GraphObject ...

  8. Python内置函数(40)——map

    英文文档: map(function, iterable, ...) Return an iterator that applies function to every item of iterabl ...

  9. Python内置函数(66)——vars

    英文文档: vars([object]) Return the __dict__ attribute for a module, class, instance, or any other objec ...

  10. 使用ML.NET和Azure Function进行机器学习 - 第1部分

    介绍 一提到机器学习,总是让人望而生畏.幸运的是,Azure正在想方设法让开发人员更容易进入机器学习.ML.NET是Microsoft Research专为.NET开发人员开发的机器学习框架,因此您可 ...