Java(1.8)高级特性-网络

网络编程涉及到了最基础的Socket编程,以及基于次的网络服务。下面将介绍在Java中如何实现Socket以及一些简单的网络客户端和服务端。

Socket

  1. 连接
    Socket类是Java中实现的基本的网络编程类,可以通过地址和端口来进行初始化,连接到该服务器的端口上,也可以使用无参构造函数,再调用connect()方法连接上服务器。两者的区别是当直接使用带参构造函数去初始化Socket时,进程会一直阻塞直到连接上服务器,而如果是在使用无参构造函数创建Socket后调用connect()方法,可以设置连接的时间限制,当超过时间后就会抛出IOException
Socket s1=new  Socket(String host,int port);
Socket s2=new Socket();
s2.connect(host,port,1000);//时限为1秒钟
  1. 通信
    Socket对象连接上服务器后,就可以通过socket.getInputStream()socket.getOutputStream()与服务器进行数据传输。这两个方法返回的是(In|Out)putStream对象,可以使用输入输出流的处理方法来进行读写。最后通过socket.close()来关闭。
  2. 其余方法
    此外,Socket类还实现了一些有助于平常使用的方法。
public InetAddress getInetAddress();//获取socket连接的服务器地址
public int getPort();//获取socket连接的服务器端口
public InetAddress getLocalAddress();//获取socket连接的本地的地址
public int getLocalPort();
public boolean isClosed();
...

ServerSocket

  1. 创建
    服务器程序会在某个端口等待用户程序的连接,在创建ServerSocket的时候,可以进行端口指定。
    创建完ServerSocket对象后,通过调用s.accept()方法来等待用户程序连接上服务器。该方法阻塞进程直到用户连接,并返回一个Socket对象。获取到Socket对象后就可以通过输入输出流向用户程序进行读写。
ServerSocket ss=new ServerSocket(port);
Socket s=ss.accept();
InputStream in=s.getInputStream();
OutputStream out=s.getOutputStream();
  1. 并发处理
    当要同时处理多个用户程序连接服务器的时候,可以在获得Socket对象后创建线程来处理该Socket的读写。
while(ture){
  Socket s=ss.accept();
  Thread t=new Thread(
    public void run(){
      //input and output
    }
  );
  t.start();
}
  1. 半关闭
    Socket对象提供了只关闭输入/输出流其中之一而不断开连接的方法,即shutdown(In|Out)put(),在断开后,任何输入或输出都将会被抛弃。断开后没有办法再重新连接上,因此这种方法只适用于一站式的服务。

因特网地址

Java中提供了InetAddressInetSocketAddress类来表示因特网地址。其中InetSocketAddress类单纯地用来表示一个地址,即ip:portInetAddress用来表示一个ip,并提供了用于获得域名对应的ip等功能。

public boolean isReachable(int timeout) throws IOException;
public String getHostName();
public static InetAddress getByName(String host);
//获取一个域名所有的ip地址
public static InetAddress[] getAllByName(String host);
//获取本地的ipv4地址
public static InetAddress getLocalHost() throws UnknownHostException;
... 

获取Web服务

使用Socket只能与指定的ip:port进行通信,而无法获得服务器特定目录下的资源,即无法通过URL获得资源(?)。URI是统一资源标识符,其中能够定位到数据的称为URL(统一资源定位符),不能定位到数据的称为URN(统一资源名称)。
Java提供了URL类对URL进行访问,提供了URI类对标识符进行解析。

  1. URI
    一个URI具有这样的格式,[scheme:]schemeSpecificPart[#fragment],其中[...]表示可选的部分,并且:#可以被包含在标识符内。包含[scheme:]部分的为绝对URI,否则为相对URI,其中schemeSpecificPart/开头的绝对URI为不透明的,例如mailto:cay@test.com。所有透明的绝对URI和所有相对URI都是分层的,如https://test.com/index../../java/net/Socket.html#Socket()。一个分层的URI的schemeSpecificPart具有这样的格式,[//authority][path][?query],基于服务器的URI的authority部分具有这样的格式[user-info@]host[:port]
    URI类提供了解析标识符和处理相对(绝对)标识符的功能。其中resolve()方法提供了解析相对URI,将其生成绝对URI的方法,relativize()方法提供了相对化方法,将绝对URI生成相对URI。比如,b/chttps://a.com/b为参数调用resolve()将得到https://a.com/b/chttps://a.com/b/chttps://a.com/b为参数调用relativize()将得到c
public String getSchemeSpecificPart();
public String getAuthority();
public String getUserInfo();
public String getHost();
public int getPort();
...
  1. URL
    URL类提供了从给定url获得资源的方法。URL提供了与URI类似的解析标识符的方法,此外还可以通过调用openStream()获得InputStream对象来获取资源内容。不过URL类没有提供输出的方法,想要和服务器进一步交互,可以调用openConnection()方法来获得URLConnection对象来进一步操作。
URL url = new URL(urlString);
InputStream in = url.openStream();
  1. URLConnection
    该类提供了向服务器输出和接收服务器输入的功能。操作URLConnection需要遵循一下几个步骤:
    ⑴ 调用URLopenConnection()来获得 URLConnection对象。
    ⑵ 设置参数和请求的属性。
    ⑶ 调用connect()连接远程资源。
    ⑷ 建立连接后就可以查询头信息和访问资源数据。
  • 参数和请求头属性
    该类提供了一下方法设置参数和请求头属性(比如http header),setter都有对应的getter。默认情况下,建立的连接只允许从服务器接收输入流,如果想要向服务器发送数据,需要先设置setDoOutput(true)。修改请求头属性使用了键值对来进行修改,如果一个键可以有多个对应的值,则将值用list包装即可。
public void setAllowUserInteraction();
public void setDoInput();
public void setDoOutput();
public void setIfModifiedSince();//连接只对某个特定日期以来修改过的数据感兴趣
public void setUseCaches();
//修改请求头属性
public void addRequestProperty(String key, String value);
  • 建立连接后的查询访问
    建立连接后,该类还提供了如下方法进行头部的信息查询。
public Object getContent();
public String getHeaderField();
public InputStream getInputStream();
public  OutputStream getOutputStream();
public String getContentEncoding();
public int getContentLength();
public String getContentType();
public long getDate();
public long getExpiration();
public long getLastModifed();
  1. 提交表单
    想服务器提交表单有Get和Post两种方法。
  • Get
    对于Get方法来说,只需要遵循下面的规则将参数附在URL结尾处。
    ⑴ 保留字符A-Z、a-z、0-9、.、-、~、_。
    ⑵ 用+字符替换所有空格。
    ⑶ 将其他所有字符编码为UTF-8,并将每个字节都编码为%后面紧跟一个两位的十六进制数字。
    例如San Francisco,CA,可以使用San+Francisco%2+CA
  • Post
    Post方法将参数写入到输出流中,不在URL上显示长串的参数键值对。
URL url=new URL(urlString);
URLConnection connection=url.openConnection();
connection.setDoOutput(true);
PrintWriter out=new PrintWriter(connection.getOutputStream(),"utf-8");
out.print(name1+"="+URLEncoder.encode(value1,"utf-8")+"&");
out.print(name2+"="+URLEncoder.encode(value2,"utf-8"));
out.close();
  • 重定向
    服务器程序相应可能会产生重定向,重定向一般都是自动处理的,但是有些情况下,比如http与https之间的重定向因为安全原因不被支持,所以需要自己手动进行重定向。下面是手动处理重定向的步骤。
//在连接前关闭自动重定向
connection.setInstanceFollowRedirects(false);
//在发送请求之后获取相应码
int responseCode=connection.getResponseCode();
//如果是HttpURLConnection.HTTP_MOVED_PERM
//或HttpURLConnection.HTTP_MOVED_TEMP
//或HttpURLConnection.HTTP_SEE_OTHER
//就获取Location响应头,获得重定向URL,断开连接,创建到新的URL连接
String location=connection.getHeaderField("Location");
if(location!=null){
  URL base=connection.getURL();
  connection.disconnect();
  connection=(HttpURLConnection) new URL(base,location).openConnection();
}
HTTP

HTTP有0.9、1.0、1.1、2.0这几个版本。

  1. HTTP 0.9
    HTTP 0.9是第一个HTTP协议的版本,只支持GET请求,不支持请求头且没有协议头,只支持纯文本内容。该版本的协议就已经支持了无状态特性,事务结束就关闭请求,访问地址不存在也不会返回错误信息。
  2. HTTP 1.0
    HTTP 1.0在0.9的版本上支持了请求和响应头部、响应以一个响应状态行开始、响应信息不仅限于超文本、支持了POST请求。该版本默认使用了短连接,每次请求建立一个TCP连接。
  3. HTTP 1.1
    新增了keep alive、chunked编码传输、字节范围请求、请求流水线等特性。还支持了HOST域(即一个IP下可能有多个服务器,通过主机名指定)、增加了connect/trace/delete/put/options的请求方法。
  • keep alive
    该版本的HTTP协议默认使用长连接,即事务完成后不断开连接,除非客户端或服务器主动断开。
  • chunked编码传输
    该特性使得传输对象可以分块传输并标明长度,当长度表明为0时说明传输结束。
  • 字节范围请求
    当客户端已有请求对象的一部分内容时,可以向服务器请求其余部分的内容,而不用重新传输整个对象。
  1. HTTP 2.0
    该协议是下一代HTTP协议,以下是其特性。
  • 多路复用,将HTTP 1.1的包分为两帧,头部放在header帧,数据放在data帧,以实现加大带宽,降低延迟的目的。
  • 所有通信在一个连接上完成,该连接可以承载任意数量的双向传输,每个消息被分成多帧传输,到达后根据头部的信息进行重新组装。
  • 头部压缩,当一个客户端向同一服务器请求时,数据包的头部是相似的,HTTP 2.0提供了压缩的方法。
  • 随时复位,HTTP 2.0可以随时停止一个TCP连接的传输,在不中断的情况下传输新的内容。
  • 服务器端推流,客户端向服务器请求一个资源,服务器判断该客户端可能用到的其他资源,一并发送给客户端,客户端进行缓存。
  • 优先权和依赖,可以指明哪些资源优先级更高,可以更快得到处理。
HTTP包结构

一个HTTP包由一下部分构成:起始行、一个或多个头域、一个空行表示头域的结束、实体消息。

GET http://download.microtool.de:80/somedata.exe
Host: download.microtool.de
Accept:*/*
Pragma: no-cache
Cache-Control: no-cache
Referer: http://download.microtool.de/
User-Agent:Mozilla/4.04[en](Win95;I;Nav)
Range:bytes=554554-

HTTP包的第一行为起始行,请求包的起始行包含请求方法、URL、HTTP版本;响应包的起始行包含HTTP-Version Status-Code Reason-PhraseHTTP-Version表示支持的HTTP版本、Status-Code表示三位数字的结果代码、Reason-Phrase对结果代码的文本描述等。
上述请求包中HostAcceptPragma就为头域,通过<key>:<value>的形式表示。
头域可以分为通用头域、请求头域、响应头域和实体头域。

  • 通用头域:Date表示消息发送的时间、Pragma实现特定的指令比如Pragma:no-cacheConnection表示连接状态等。
  • 请求头域:Host表示请求资源的URL、Accept表示自己接收什么文件、Accept-Charset表示接收文件的编码格式、Authorization用来将身份验证信息发给服务器等。
  • 响应头域:AgeLocationProxy-AuthenticatePublic等。
  • 实体头域:请求消息和响应消息都可以包含实体信息,实体信息一般由实体头域和实体组成,Content-Type实体的介质类型、Content-Length表示实际传送的实体长度等。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,084评论 1 32
  • 计算机网络概述 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。 按照计算机网络的定义,通过一定...
    蛋炒饭_By阅读 1,210评论 0 10
  • 概要 64学时 3.5学分 章节安排 电子商务网站概况 HTML5+CSS3 JavaScript Node 电子...
    阿啊阿吖丁阅读 9,095评论 0 3
  • 转自http://blog.csdn.net/xugangwen/article/details/44811783...
    扎Zn了老Fe阅读 12,686评论 1 142
  • 炙热燥焖的青春 在夜里续着伏邪的妖媚 嚣张跋扈 打着白天的嗝 一丝未挂 扑向黑色的肌肉 缠着夜的心脏 月朦胧,星朦...
    挑夫阅读 279评论 11 27