一、基本思路:

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. [译]async/await中阻塞死锁

    这篇博文主要是讲解在async/await中使用阻塞式代码导致死锁的问题,以及如何避免出现这种死锁.内容主要是从作者Stephen Cleary的两篇博文中翻译过来. 原文1:Don'tBlock o ...

  2. 【RL-TCPnet网络教程】第22章 RL-TCPnet之网络协议IP

    第22章      RL-TCPnet之网络协议IP 本章节为大家讲解IP(Internet Protocol,网络协议),通过前面章节对TCP和UDP的学习,需要大家对IP也有个基础的认识. (本章 ...

  3. 【安富莱二代示波器教程】第16章 附件A---电阻屏触摸校准

    第16章      附件A---电阻屏触摸校准 二代示波器的触摸校准比较简单,随时随地都可以做触摸校准,按下K1按键即可校准.有时候我们做触摸校准界面,需要在特定的界面才可以进入触摸校准状态,非常繁琐 ...

  4. 浅谈Java的主要学习要点_上海尚学堂java培训课程思维导图

    Java是一种可以撰写跨平台应用程序的面向对象的程序设计语言.Java 技术具有卓越的通用性.高效性.平台移植性和安全性,广泛应用于PC.数据中心.游戏控制台.科学超级计算机.移动电话和互联网,同时拥 ...

  5. 理解Golang哈希表Map的元素

    目录 概述 哈希函数 冲突解决 初始化 结构体 字面量 运行时 操作 访问 写入 扩容 删除 总结 在上一节中我们介绍了 数组和切片的实现原理,这一节会介绍 Golang 中的另一个集合元素 - 哈希 ...

  6. [Swift]LeetCode78. 子集 | Subsets

    Given a set of distinct integers, nums, return all possible subsets (the power set). Note: The solut ...

  7. [Swift]LeetCode170.两数之和III - 数据结构设计 $ Two Sum III - Data structure design

    Design and implement a TwoSum class. It should support the following operations:add and find. add - ...

  8. vue项目安装vux

    本文章默认基于“vue init webpack myproject”已经搭好基本的项目, 而且本文是从我有道笔记拷贝稍加修改过来的 本来我私人笔记写给自己看的所以有些地方可能描述不够清晰 需要修改的 ...

  9. 【Redis篇】初始Redis与Redis安装

    一.前述 Redis是当前比较热门的NOSQL系统之一,它是一个key-value存储系统.和Memcache类似,但很大程度补偿了Memcache的不足,它支持存储的value类型相对更多,包括st ...

  10. 『素数 Prime判定和线性欧拉筛法 The sieve of Euler』

    素数(Prime)及判定 定义 素数又称质数,一个大于1的自然数,除了1和它自身外,不能整除其他自然数的数叫做质数,否则称为合数. 1既不是素数也不是合数. 判定 如何判定一个数是否是素数呢?显然,我 ...