客户端请求服务器端通信, Web 编程发展基础|乐字节

282 阅读7分钟
乐字节的小伙伴们,好久不见,甚是想念啊!
前面我发布的文章算是把Java初级基础阶段讲完了,接下来小乐将会给大家接着讲Java中级阶段——Javaweb。

首先,我们要看看Javaweb阶段主要重点掌握的知识:

  • 了解C/S和B/S两种结构模式
  • 理解Web应用程序的工作原理
  • 实现第一个Servlet程序
  • 理解程序的内部工作流程
  • 掌握web.xml的基本配置

这篇文章我们先学习web发展基础。

1、 简单通信

回顾 Socket 编程给我们最大的感受,是可以在多台电脑之间进行数据的传输,这就是网络编程的开端和基础,通过客户端请求服务器端通信,直观了解 Web 编程。
Server
/**
 * 服务器端,接收客户端请求并给出简单的响应
 * @author Administrator
 */
public class Server {
	public static void main(String[] args) throws IOException {
		//1、创建服务器,指定端口ServerSocket(int port)
		ServerSocket socket=new ServerSocket(8888);
		//2、接收客户端连接
		Socket client=socket.accept();
		System.out.println("******************");
		//获取数据的输入流
		InputStream is=client.getInputStream();
		//使用字符缓存流
		BufferedReader br=new BufferedReader(new InputStreamReader(is));
		String msg="";
		while((msg=br.readLine())!=null){
			System.out.println(msg);
		}
		br.close();
	}
}
乐字节原创
Client
/**
 * 客户端:向服务器发送请求,并发送简单的消息
 * @author Administrator
 */
public class Client {
	public static void main(String[] args) throws UnknownHostException, IOException {
		//创建客户端 	必须指定服务器+端口	
		Socket client=new Socket("localhost",8888);
		//发送消息	请求资源
		//获取发送流
		OutputStream os=client.getOutputStream();
		BufferedWriter br=new BufferedWriter(new OutputStreamWriter(os));
		//写出消息,发送内容
		String msg="hello I need some source";
		br.write(msg);
		br.close();
	}
}
从上面的例子总结通信条件如下:
1)、需要有服务器端(server) :等待被请求,需要暴露ip 和 port
2)、需要有客户端(client):主动发起请求 ,知晓服务端的ip 和 port
3)、通信规则(协议):TCP/IP协议

ip用于定位计算机;端口号(定位程序),用于标识进程的逻辑地址,不同进程的标志;有效端口:0~65535,其中0~1024由系统使用或者保留端口,开发中建议使用1024以上的端口。


2. 不同请求

Client
package com.shsxt.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
/**
 * 
 * @author Lj
 *
 * 客户端
 */
public class Client {
	public static void main(String[] args) throws IOException {
		//  通过系统默认类型的 SocketImpl 创建未连接套接字
		Socket socket = new Socket();
		//此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名
		SocketAddress address = new InetSocketAddress("localhost",8898);
		// 将此套接字连接到服务器,并指定一个超时值。  或者不指定超时时间   
		socket.connect(address, 1000);
		OutputStream os = socket.getOutputStream();
		os.write("time".getBytes());
		os.flush();
		socket.close();
	}
}
Server
package com.shsxt.socket;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 * @author Lj
 * 服务端
 * public class ServerSocketextends Object:此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。 
 */
public class Server {
	public static void main(String[] args) throws IOException {
		//创建绑定到特定端口的服务器套接字。
		ServerSocket server = new ServerSocket(8898);
		
		// Socket accept()   侦听并接受到此套接字的连接。 
		Socket client = server.accept();	
		System.out.println("接收到连接");
		
		InputStream is = client.getInputStream();
		BufferedInputStream bis = new BufferedInputStream(is);
		byte[] req = new byte[1024];
		// 接收客户端请求
		int len = bis.read(req);
		String reqStr = new String(req,0,len);
		System.out.println(reqStr);
		if(reqStr.equals("money")){
			System.out.println("here's the money");
		}else if(reqStr.equals("time")){
			System.out.println("you have so much time");
		}	
		client.close();
		server.close();
	}
}

3. 复杂请求

Client
package com.shsxt.socket;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
/**
 * @author Lj
 * 客户端
 */
public class Client {
	public static void main(String[] args) throws IOException {
		//  通过系统默认类型的 SocketImpl 创建未连接套接字
		Socket socket = new Socket();
		//此类实现 IP 套接字地址(IP 地址 + 端口号)。它还可以是一个对(主机名 + 端口号),在此情况下,将尝试解析主机名
		SocketAddress address = new InetSocketAddress("localhost",8898);
		// 将此套接字连接到服务器,并指定一个超时值。  或者不指定超时时间   
		socket.connect(address, 1000);
		
		OutputStream os = socket.getOutputStream();
		os.write("money".getBytes());
		os.flush();		
		// 接收响应, 显示结果
		InputStream is = socket.getInputStream();
		byte[] result = new byte[1024];
		int len = is.read(result);
		String resultStr  = new String(result,0,len);
		System.out.println(resultStr);
		socket.close();
	}
}
Server
package com.shsxt.socket;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * 
 * @author Lj 服务端 public class ServerSocketextends
 *         Object:此类实现服务器套接字。服务器套接字等待请求通过网络传入。它基于该请求执行某些操作,然后可能向请求者返回结果。
 */
public class Server {
	public static void main(String[] args) throws IOException {
		// 创建绑定到特定端口的服务器套接字。
		ServerSocket server = new ServerSocket(8898);

		// Socket accept() 侦听并接受到此套接字的连接。
		Socket client = server.accept();
		System.out.println("接收到连接");
		InputStream is = client.getInputStream();
		BufferedInputStream bis = new BufferedInputStream(is);
		byte[] req = new byte[1024];
		// 接收客户端请求
		int len = bis.read(req);
		String reqStr = new String(req, 0, len);
		System.out.println(reqStr);
		// 将接收到的请求封装成对象, 传送给请求的类
		MyRequest request = new MyRequest();
		MyResponse response = new MyResponse();

		OutputStream os = client.getOutputStream();
		if (reqStr.equals("money")) {
			// 根据请求的信息, 构造处理的类
			MyServlet s1 = new ServletMoney();
			s1.service(request, response);
			// 通过client的响应, 将结果响应回客户端
			os.write("here's the money".getBytes());
			os.flush();
		} else if (reqStr.equals("time")) {
			// 根据请求的信息, 构造处理的类
			MyServlet s2 = new ServletTime();
			s2.service(request, response);
			// 通过client的响应, 将结果响应回客户端
			os.write("you have somuch time".getBytes());
			os.flush();
		}
		client.close();
		server.close();
	}
}
/*
 * 我是一个有要求的人, 你请求的这个资源必须是满足我要求格式的类 作用:防止混乱,方便调用
 * 这是我的标准
 */
interface MyServlet {
	void service(MyRequest req, MyResponse resp);
}
class ServletMoney implements MyServlet {
	/*
	 * @see com.shsxt.socket.MyServlet#service(com.shsxt.socket.MyRequest)
	 */
	@Override
	public void service(MyRequest req, MyResponse resp) {
		// 做出力所能及的处理
	}
}
class ServletTime implements MyServlet {
	/*
	 * @see com.shsxt.socket.MyServlet#service(com.shsxt.socket.MyRequest)
	 */
	@Override
	public void service(MyRequest req, MyResponse resp) {
		// 做出力所能及的处理
	}
}
/*
 * 请求信息都按规律封装在该对象
 */
class MyRequest {
}
class MyResponse {
}
随着客户需求越来越复杂,需要的功能越来越多,我们的服务器端需要处理的请求越来越多,需要区分不同的请求,还需要按照不同请求进行请求数据的提取以及资源的分配和运算还有逻辑的处理,最后还需要响应给客户端,这就使得服务器端代码越来越复杂,实现越来越困难。
根据以往的经验,双方进行通信只需要遵循一定的规则就可以很明确地知道各部分数据的含义,于是出现了网络更上层的应用协议(后面讲的 HTTP 协议),规定服务器端和客户端通信的规则。

客户端请求服务器端和服务器端响应客户端,都按照固定的规则,那么接收请求和相应数据这部分操作就可以固定下来,交给特定的一段代码来执行,从而减少服务器端的代码量,于是出现了接下来说的服务器。

4. 服务器的出现

当客户端请求的资源越来越丰富,需求越来越复杂,程序的核心就应该放在解决业务和 计算响应数据上,于是出现了服务器统一接收客户端处理并进行分发到不同的资源,由各个资源进行处理,最后结果交由服务器响应。

从上面的描述可以发现,现在所说的服务器只是负责接收请求,对请求进行分发,以及最后将获取的数据进行相应的固定框架,至于数据怎么计算得出还得根据具体的业务需求编 写(填充)代码。在没有业务需求的情况下就能将服务器准备出来,现在市面上的服务器有 很多,比较常用的有:Tomcat、JBOOS、IBM 的 WebSphere、BEA 的 WebLogic 以及 Apache 等。


好了,web发展基础就讲到这里了,下一文章将会给大家Javaweb的介绍和C/S、B/S体系结构,敬请关注乐字节哦~~~~