java的服务端与客户端通信(2)

一、Socket连接与HTTP连接

  1.1Socket套接字

  • 套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
  • 应用层通过传输层进行数据通信时,TCP会遇到同时为多个应用程序进程提供并发服务的问题。多个TCP连接或多个应用程序进程可能需要通过同一个 TCP协议端口传输数据。为了区别不同的应用程序进程和连接,许多计算机操作系统为应用程序与TCP/IP协议交互提供了套接字(Socket)接口。应用层可以和传输层通过Socket接口,区分来自不同应用程序进程或网络连接的通信,实现数据传输的并发服务。

  1.2Socket与TCP连接

  • 创建Socket连接时,可以指定使用的传输层协议,Socket可以支持不同的传输层协议(TCP或UDP),当使用TCP协议进行连接时,该Socket连接就是一个TCP连接。

  1.3Socket连接与HTTP连接

  • 由于通常情况下Socket连接就是TCP连接,因此Socket连接一旦建立,通信双方即可开始相互发送数据内容,直到双方连接断开。但在实际网络应用中,客户端到服务器之间的通信往往需要穿越多个中间节点,例如路由器、网关、防火墙等,大部分防火墙默认会关闭长时间处于非活跃状态的连接而导致 Socket 连接断连,因此需要通过轮询告诉网络,该连接处于活跃状态。
  • HTTP连接使用的是“请求—响应”的方式,不仅在请求时需要先建立连接,而且需要客户端向服务器发出请求后,服务器端才能回复数据。
  • 很多情况下,需要服务器端主动向客户端推送数据,保持客户端与服务器数据的实时与同步。此时若双方建立的是Socket连接,服务器就可以直接将数据传送给客户端;若双方建立的是HTTP连接,则服务器需要等到客户端发送一次请求后才能将数据传回给客户端,因此,客户端定时向服务器端发送连接请求,不仅可以保持在线,同时也是在“询问”服务器是否有新的数据,如果有就将数据传给客户端。

  1.4TCP和UDP的区别

  • TCP是面向链接的,虽然说网络的不安全不稳定特性决定了多少次握手都不能保证连接的可靠性,但TCP的三次握手在最低限度上(实际上也很大程度上保证了)保证了连接的可靠性;而UDP不是面向连接的,UDP传送数据前并不与对方建立连接,对接收到的数据也不发送确认信号,发送端不知道数据是否会正确接收,当然也不用重发,所以说UDP是无连接的、不可靠的一种数据传输协议。
  • 也正由于1所说的特点,使得UDP的开销更小数据传输速率更高,因为不必进行收发数据的确认,所以UDP的实时性更好。

知道了TCP和UDP的区别,就不难理解为何采用TCP传输协议的MSN比采用UDP的QQ传输文件慢了,但并不能说QQ的通信是不安全的,因为程序员可以手动对UDP的数据收发进行验证,比如发送方对每个数据包进行编号然后由接收方进行验证啊什么的,即使是这样,UDP因为在底层协议的封装上没有采用类似TCP的“三次握手”而实现了TCP所无法达到的传输效率。

  1.5传输层与应用层协议

  • 我们在B/S或C/S架构下传输数据时,可以使用传输层协议(TCP/IP),也可以使用应用层协议(HTTP,FTP)。但如果我们只是用传输层协议,没有应用层,便无法识别数据内容,要使我们传输的数据有意义,必须用到一个应用层协议,我们也可以自己定义应用层协议。WEB应用程序使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP作为传输层协议将它发到网络上。
  • Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口。而HTTP连接时建立在传输层基础之上的。

 总而言之,HTTP是轿车,提供了封装或者显示数据的具体形式;Socket是发动机,提供了网络通信的能力。

二、用Socket模拟客户端向真实服务端发送请求

  2.1HTTP请求格式

    <request-line>
    <headers>
    <blank line>
    [<request-body>]

   (1)GET请求

GET/ sample.jsp HTTP/1.1                               请求方法  URI  协议/版本
Accept: image/gif.image/jpeg,*/*               浏览器可接受的MIME类型
Accept-Language: zh-cn                     浏览器所希望的语言种类,当服务器能够提供一种以上的语言版本时要用到(发送参数时有个参数q,表明用户的喜好程度)
Connection: Keep-Alive                     Connection:表示是否需要持久连接。
Host: localhost                        初始URL中的主机和端口
User-Agent: Mozila/4.0(compatible;MSIE5.01;Window NT5.0)浏览器类型(如果Servlet返回的内容与浏览器类型有关则该值非常有用)
Accept-Encoding: gzip,deflate                浏览器能够进行解码的数据编码方式(Servlet能够向支持gzip的浏览器返回经gzip编码的HTML页面。许多情形下这可以减少5到10倍的下载时间。)

username=jinqiao&password=1234              

 (2)POST请求

POST / HTTP/1.1
Host: www.baidu.com
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.6)Gecko/20050225 Firefox/1.0.1
Content-Type: application/x-www-form-urlencoded     说明了请求主体的内容是如何编码的,这是针对简单URL编码的MIME类型。
Content-Length: 40                      表示请求消息正文的长度。
Connection: Keep-Alive
name=Professional%20Ajax&publisher=Wiley

   2.2HTTP响应格式

如下所示,HTTP响应的格式与请求的格式十分类似:

<status-line>
<headers>
<blank line>
[<response-body>]

正如你所见,在响应中唯一真正的区别在于第一行中用状态信息代替了请求信息。状态行(status line)通过提供一个状态码来说明所请求的资源情况。以下就是一个HTTP响应的例子:

HTTP/1.1 200 OK                                        状态行给出的HTTP状态代码是200,以及消息OK。状态行始终包含的是状态码和相应的简短消息,以避免混乱
Date: Sat, 31 Dec 2005 23:59:59 GMT            用来说明响应生成的日期和时间(服务器通常还会返回一些关于其自身的信息,尽管并非是必需的)。
Content-Type: text/html;charset=ISO-8859-1        指定了MIME类型HTML(text/html),其编码类型是ISO-8859-1(这是针对美国英语资源的编码标准)
Content-Length: 122
<html>
<head>
<title>Wrox Homepage</title>
</head>
<body>
<!-- body goes here -->
</body>
</html>
常用的状态码有:
◆200 (OK): 找到了该资源,并且一切正常。 ◆304 (NOT MODIFIED): 该资源在上次请求之后没有任何修改。这通常用于浏览器的缓存机制。 ◆401 (UNAUTHORIZED): 客户端无权访问该资源。这通常会使得浏览器要求用户输入用户名和密码,以登录到服务器。 ◆403 (FORBIDDEN): 客户端未能获得授权。这通常是在401之后输入了不正确的用户名或密码。 ◆404 (NOT FOUND): 在指定的位置不存在所申请的资源。
* 1XX 保留 
* 2XX 表示成功 
* 3XX 表示URL已经被移走 
* 4XX 表示客户错误 
* 5XX 表示服务器错误 

  2.3模拟客户端向真实服务端发送请求(Socket版)

    客户端代码:

 1 package socketPractiseList;
 2 
 3 import java.io.*;
 4 import java.net.*;
 5 public class HttpClient {
 6 
 7     public static void main(String args[])throws Exception{
 8         InetAddress inet=InetAddress.getByName("www.baidu.com");
 9         System.out.println(inet.getHostAddress());
10         Socket socket=new Socket(inet.getHostAddress(),80);
11         InputStream in=socket.getInputStream();
12         OutputStream out=socket.getOutputStream();
13         BufferedReader reader=new BufferedReader(new InputStreamReader(in));
14         PrintWriter writer=new PrintWriter(out,true);
15         writer.println("GET /home.html HTTP/1.1");//home.html是关于百度的页面
16         writer.println("Accept:  image/gif,  image/x-xbitmap,  image/jpeg,  image/pjeg,  application/xaml+xml,"
17                 +"application/vnd.ms-xpdocument,  application/x-ms-xbap,application/x-ms-application,"
18                 +"application/msword,  application/vnd.ms-excel,  application/vnd.ms-powerpoint,*/*");
19         writer.println("Accept-Language:en-us,zh-cn;q=0.5;");
20         writer.println("Content-Type:text/html;");
21         writer.println("Accept-Encoding:gzip,deflate;");
22         writer.println("Host:www.baidu.com");
23         writer.println("User-Agent:Mozilla/4.0(compatible;MSIE6.0;windows NT5.1;SV1;.NET CLR 1.1.4322;.NET CLR 2.0.50727;"
24                 + ".NET CLR 3.0.04506.30;.NET CLR 3.0.4506.30;.NET CLR 3.0.4506.30;.NET CLR 3.0.4506.2152;.NET CLR 3.5.30729)");
25            writer.println("Connection:Keep-Alive");
26            writer.println();
27            writer.flush();
28            String result=reader.readLine();
29            while(result!=null){
30             System.out.println(result);
31             result=reader.readLine();
32            }
33         reader.close();
34         writer.close();
35         socket.close();
36     }
37 }

     服务端的响应信息:

  乱码问题估计有两种解决方式:(1)指定字符集编码方式;(2)不用BufferedReader,改用DataInputStream;(3)使用缓冲字节流;

2.4模拟客户端向真实服务端发送请求(HTTPClient版)

原文地址:https://www.cnblogs.com/MenAngel/p/5317087.html