Java 网络编程 —— 客户端协议处理框架_天天快消息
博客园 2023-06-03 06:36:23
概述

Java 对客户程序的通信过程进行了抽象,提供了通用的协议处理框架,该框架封装了 Socket,主要包括以下类:


(资料图片仅供参考)

URL 类:统一资源定位符,表示客户程序要访问的远程资源URLConnection 类:表示客户程序与远程服务器的连接,客户程序可以从 URLConnection 获得数据输入流和输出流URLStreamHandler 类:协议处理器,主要负责创建与协议相关的 URLConnection 对象ContentHandler 类:内容处理器,负责解析服务器发送的数据,把它转换为相应的 Java 对象

以上类都位于 java.net 包,除 URL 类为具体类,其余的都是抽象类,对于一种具体的协议,需要创建相应的具体子类。Oracle 公司为协议处理框架提供了基于 HTTP 的实现,它们都位于 JDK 类库的 sun.net.www 包或者其子包

URL 类的用法

下例的 HtpClient 类利用 URL 类创建了一个简单的 HTTP 客户程序,先创建了一个 URL 对象,然后通过它的 openStream()方法获得一个输入流,接下来就从这个输入流中读取服务器发送的响应结果

public class HttpClient {        public static void main(String args[]) throws IOException {        //http是协议符号        URI url = new URL("http://www.javathinker.net/hello.htm");        //接收响应结果        InputStream in = url.openStream();        ByteArrayOutputStream buffer = new ByteArrayOutputStream();        bytel] buff = new byte[1024];        int len = -l;                while((len = in.read(buff)) != -1) {            buffer.write(buff, 0, len);        }        //把字节数组转换为字符串        System.out.println(new String(buffer.toByteArray()));    }}

URL 类的构造方法创建 URLStreamHandler 实例的流程如下:

如果在 URL 缓存已经存在这样的 URLStreamHandler实例,则无须再创建,否则继续执行下一步

如果程序通过 URL 类的静态 setURLStreamHandlerFactory()方法设置了 URLStreamHandlerFactory接口的具体实现类,那么就通过这个工厂类的 createURLStreamHandler()方法来构造 URLStreamHandler实例,否则继续执行下一步

根据系统属性 java.prolocol.handler.pkgs来决定 URLStreamHandler具体子类的名字,然后对其实例化,假定运行 HttpClient 的命令为:

java -Djava.protocol.handler.pkgs=com.abc.net.www | net.javathinker.protocols HttpClient

以上命令中的 -D 选项设定系统属性,会先查找并试图实例化 com.abc.net.www.http.Handler类,如果失败,再试图实例化 net.javathinkerprotocols.http.Handler类,如果以上操作都失败,那么继续执行下一步

试图实例化位于 sun.net.www.prolocol包的 sun.netwww.protocol.协议名.Handler类,如果失败,URL 构造方法就会抛出 MalforedURLException。在本例协议名是 http,会试图实例化 sun.net.www.protocol.http.Handler

URL 类具有以下方法:

openConnection():创建并返回一个 URLConnection对象,这个 openConnection()方法实际上是通过调用 URLStreamHandler类的 openConnection()方法,来创建 URLConnection对象openStream():返回用于读取服务器发送数据的输入流,该方法实际上通过调用 URLConnection类的 getInputStream()方法来获得输入流getContent():返回包装了服务器发送数据的 Java 对象,该方法实际上调用 URLConnection类的 getContent)方法,而 URLConnection类的 getContent()方法又调用了 ContentHandler类的 getContent()方法URLConnection 类的用法

URLConnection 类表示客户程序与远程服务器的连接,URLConnection 有两个 boolean 类型的属性以及相应的 get 和 set 方法:

dolnput:如果取值为 true,表示允许获得输入流,读取远程服务器发送的数据该属性的默认值为 true。程序可通过 getDolnput() 和 setDolnput() 方法来读取和设置该属性doOutput:如果取值为 true,表示允许获得输出流,向远程服务器发送数据该属性的默认值为 false。程序可通过 getDoOutput() 和 setDoOutput() 方法来读取和设置该属性

URLConnection 类提供了读取远程服务器的响应数据的一系列方法:

getHeaderField(String name):返回响应头中参数 name 指定的属性的值getContentType():返回响应正文的类型,如果无法获取响应正文的类型就返回 nullgetContentLength():返回响应正文的长度,如果无法获取响应正文的长度,就返回 -1getContentEncoding():返回响应正文的编码类型,如果无法获取响应正文的编码类型,就返回 null

下例的 HtpClient 类利用 URLConnection 类来读取服务器的响应结果

public class HttpClient {        public static void main(String args[]) throws IOException {        URL url = new URL("http://www,javathinkernet/hello.htm");        URLConnection connection = url.openConnection();        //接收响应结果        System.out.printIn("正文类型:" + connection.getContentType());        System.out.printIn("正文长度:" + connection.getContentLength());        //读取响应正文        InputStream in = connection.getInputStream();                ByteArrayOutputStream buffer = new ByteArrayOutputStream();        byte[] buff = new byte[1024];        int len = -l;                while((len = in.read(buff)) != -1) {            buffer.write(buff, 0, len);        }                //把字节数组转换为字符串        System.out.println(new String(buffer.toByteArray()));    }}
实现协议处理框架

本节将为用户自定义的 ECHO 协议实现处理框架,共创建了以下类:

EchoURLConnection 类:继承自 URLConnection 类EchoURLStreamHandler 类:继承自 URLStreamHandler 类EchoURLStreamHandlerFactory 类:实现 URLStreamHandlerFactory 接口EchoContentHandler 类:继承自 ContentHandler 类EchoContentHandlerFactory 类:实现 ContentHandlerFactory 接口1. 创建 EchoURLConnection 类

EchoURLConnection 类封装了一个 Socket,在 connect() 方法中创建与远程服务器连接的 Socket 对象

public class EchoURLConnection extends URLConnection {        private Socket connection = null;    public final static int DEFAULT PORT = 8000;        public EchoURLConnection(URL url) {        super(url);    }        public synchronized InputStream getInputStream() throws IOException {        if(!connected) connect();        return connection.getInputStream();    }        public synchronized OutputStream getOutputStream() throws IOException {        if(!connected) connect();        return connection.getOutputStream();    }        public String getContentType() {        return "text/plain";    }        public synchronized void connect() throws IOException {        if(!connected) {            int port = url.getPort();            if(port < 0 || port > 65535) port = DEFAULT_PORT;            this.connection = new Socket(url.getHost(), port);            this.connected = true;        }    }        public synchronized void disconnect() throws IOException {        if(connected) {            //断开连接            this.connection.close();            this.connected = false;        }    }}
2. 创建 EchoURLStreamHandler 及工厂类

EchoURLStreamHandler 类的 openConnection()方法负责创建一个 EchoURLConnection 对象

public class EchoURLStreamHandler extends URLStreamHandler {        public int getDefaultPort() {        return 8000;    }        protected URLConnection openConnection(URL url) throws IOException {        return new EchoURLConnection(url);    }}

EchoURLStreamHandlerFactory 类的 createURLStreamHandle()方法负责构造 EchoURLStreamHandler 实例

public class EchoURLStreamHandlerFactory implements URLStreamhandlerFactory {        public URLStreamHandler createURLStreamHandler(String protocol) {        if(protocol.equals("echo"))            return new EchoURLStreamHandler();        else            return null;    }}

在客户程序中,可以通过以下方式设置 EchoURLStreamHandlerFactory

URL.setURLStreamHandlerFactory(new EchoURLStreamHandlerFactory());URL url=new URL("echo://localhost:8000");
3. 创建 EchoContentHandler 类及工厂类

URLConnection 类还提供了 getContent()方法,它有两种重载形式:

public Object getContent();public Object getContent(Class[] classes);

第二个 getContent() 方法把服务器发送的数据优先转换为 classes 数组第一个元素指定的类型,如果转换失败,再尝试转换第二个元素指定的类型,以此类推

下例 HttpClient 演示处理服务器发送的数据

public class HttpClient {        public static void main(String args[]) throws IOException {        URL url = new URL("http://www,javathinker.net/hello.htm");        URlConnection connection = url.openConnection();        //接收响应结果        InputStream in = connection.getInputStream();        Class[] types = {String.class, InputStream.class};        Object obj = connection.getContent(types);                if(obj instanceof String) {            System.out.println(obj);        } else if(obj instanceof InputStream) {            in = (InputStream) obj;            FileOutputStream file = new FileOutputStream("data");            byte[] buff = new byte[1024];            int len = -l;                        while((len = in.read(buff)) != -1) {                file.write(buff, 0 ,len);            }                        System.out.println("正文保存完毕");        } else {            System.out.println("未知的响应正文类型");        }    }}

EchoContentHandler 类负责处理 EchoServer 服务器发送的数据

public class EchoContentHandler extends ContentHandler {        /** 读取服务器发送的一行数据,把它转换为字符串对象 */    public Object getContent(URLConnection connection) throws IOException {    InputStream in = connection.getInputStream();        BufferedReader br = new BufferedReader(new InputStreamReader(in));        return br.readLine();    }        public Object getContent(URLConnection connection, Class[] classes) throws IOException {        InputStream in = connection.getInputStream();        for(int i = 0; i < classes.length; i++) {            if(classes[i] == InputStream.class) {                return in;            } else if(classes[i] == String.class) {                return getContent(connection);            }        }        return null;    }}

第二个 getContent() 方法依次遍历 classes 参数中的元素,判断元素是否为 InputSuream 类型或 String 类型,如果是,就返回相应类型的对象,它包含了服务器发送的数据。如果 classes 参数中的元素都不是 InputStream 类型或 String 类型,就返回 null

EchoContentHandlerFactory 类的 createContentHandler() 方法负责创建一个EchoContentHandler 对象

public class EchoContentHandlerFactory implements ContentHandlerFactory {        public ContentHandler createContentHandler(String mimetype) {        if(mimetype.equals("text/plain")) {            return new EchoContentHandler();        } else {            return null;        }    }}

在客户程序中,可以通过以下方式设置 EchoContentHandlerFactory

URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory());URL url = new URL("echo://localhost:8000");EchoURLConnection connection = (EchoURLConnection)url.openConnection();...//读取服务器返回的数据,它被包装为一个字符串对象String echoMsg = (String)connection.getContent();
4. 在 EchoClient 类运用 ECHO 协议处理框架
public class EchoClient {        public static void main(String args[]) throws IOException {        //设置URLStreamHandlerFactory        URL.setURLStreamHandlerFactory(new EchoURLStreamHandlerFactory());        //设置ContentHandlerFactory        URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory());                URL url = new URL("echo://localhost:8000");        EchoURLConnection connection = (EchoURlConnection) url.openConnection();        //允许获得输出流        connection.setDoOutput(true);        //获得输出流        PrintWriter pw = new PrintWriter(connection.getOutputStream(), true);        while(true) {            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));            String msg = br.readLine();            //向服务器发送消息            pw.println(msg);            //读取服务器返回的消息            String echoMsg = (String) connection.getContent();            System.out.println(echoMsg);            if(echoMsg.equals("echo:bye")) {                //断开连接                connection.disconnect();                break;            }        }    }}

Java 网络编程 —— 客户端协议处理框架_天天快消息

2023-06-03 06:36:23

逾期还不上可以和银行协商吗?催收打电话给家人朋友合法吗?_世界热点评

2023-06-03 06:27:16

纳思达(002180):6月2日北向资金减持125.91万股

2023-06-03 05:18:57

卫光生物:公司目前暂无脑科学技术储备 热推荐

2023-06-03 04:28:43

everybody是什么意思翻译_everybody是什么意思|全球即时看

2023-06-03 03:13:30

影视投资平台有哪些平台(影视投资平台有哪些) 今头条

2023-06-03 02:23:47

光遇火之灵位置在哪里(光遇火之灵)

2023-06-03 01:14:25

漯河召开第五次律师代表大会 九三社员当选副会长和理事

2023-06-03 00:43:42

世界简讯:我的女儿,我会教育她自立自强,不依赖别人,不管是和男性还是和女性相处都要平等

2023-06-03 00:28:36

苹果直播不带货,百万人看了个寂寞 动态

2023-06-02 23:40:27

视焦点讯!台风“玛娃”已造成日本多人受伤

2023-06-02 22:27:59

进击的小白,给大家安利四款入门级的入耳式耳机~|环球观察

2023-06-02 21:05:07

热头条丨神舟十五号 “圆梦乘组”将于6月4日返回东风着陆场

2023-06-02 20:29:30

温州市区将再添一体育公园,预计8月试运行-实时焦点

2023-06-02 20:03:59

supox磐正官网_SUPoX磐正AA75MC2Q7-环球今亮点

2023-06-02 19:58:04

自主品牌加快抢食合资品牌市场

2023-06-02 18:19:09

环球讯息:win11音量键失灵的解决方法

2023-06-02 17:28:26

李尚福重申中方在台湾问题上坚定立场|每日快讯

2023-06-02 17:09:59

环球微动态丨【原】春江花月夜,孤轮守夜明

2023-06-02 15:59:22

第19届杭州亚运会5克和30克银质纪念币多少钱(2023年06月02日)|新要闻

2023-06-02 15:54:30

中青旅举办“六一”研学游 助推古北水镇文旅融合_新要闻

2023-06-02 14:10:48

关节炎可以吃笋吗

2023-06-02 14:10:07

南昌公布“助考”违法行为举报电话 举报电话:0791-86220507_观点

2023-06-02 13:15:03

热消息:赛力斯:5月新能源汽车销量8562辆,环比增长23.78%

2023-06-02 11:59:34

环球观察:习主席复信的孟加拉国儿童,她的名字叫“中国”

2023-06-02 11:34:56

雾霾形成的原因是什么?(雾霾形成的原因是什么)

2023-06-02 10:49:34

热头条丨科创板首批退市公司诞生 *ST泽达、*ST紫晶触发重大违法强制退市

2023-06-02 10:05:51

焦点快报!表格斜线三分割怎么做_excel单元格斜线三分

2023-06-02 09:15:33

南京新百:融资净买入234.81万元,融资余额1.29亿元(06-01)|焦点速递

2023-06-02 08:42:53

这个周末,带你解锁夏日露营新玩法 环球资讯

2023-06-02 07:35:53

环球资讯:在数字经济新赛道上加速奔跑

2023-06-02 07:10:16

天天通讯!永寿县公益中行脱贫代理人协会_关于永寿县公益中行脱贫代理人协会简述

2023-06-02 05:55:58

加速深入中东市场 长城汽车坦克500正式登陆阿联酋 当前头条

2023-06-02 05:14:23

植物妈妈有办法还有哪些植物传播种子的方法仿写_植物妈妈有办法

2023-06-02 04:40:49

主打“冷”“素” 刷屏的极简午餐适合每个人吗? 天天快资讯

2023-06-02 03:37:49

艾瑞泽5和风神a60空间_东风风神a60 1.5手动上路最低多少钱|百事通

2023-06-02 02:46:45

今亮点!孔明直播:《6月2日热点信息+个股公告》

2023-06-02 02:22:48

天大技术打造未来智能无人科技主题公园

2023-06-02 00:53:40

国内首个神经内分泌代谢网络调控大会在深举办

2023-06-02 00:42:41

康铭桐(关于康铭桐的基本详情介绍)_今日观点

2023-06-01 23:41:56

每日视点!魏征水能载舟亦能覆舟_水能载舟亦能覆舟是谁说的

2023-06-01 22:34:44

世界新动态:非法持气枪打猎时误将他人当野兔射杀 男子获刑4年6个月

2023-06-01 22:17:16

好评中国|守护童心 筑梦未来 当前看点

2023-06-01 21:11:15

韩统一部:朝鲜公布发射照或意在强调所射为卫星

2023-06-01 20:59:54

怎样防止微信被定位 怎样防止微信被定位红米手机

2023-06-01 20:15:25

抗原不准了?出现症状后2~3天抗原才阳是正常情况-天天新视野

2023-06-01 19:46:02

每日快讯!山子股份(000981)6月1日主力资金净卖出963.42万元

2023-06-01 17:56:15

【世界新要闻】北京立法保障未成年人合法权益

2023-06-01 17:31:08

【当前独家】塞尔达传说王国之泪幻影加侬在哪里

2023-06-01 17:01:44

今日聚焦!无锡压缩机股份有限公司待遇_无锡压缩机股份有限公司

2023-06-01 15:37:52

【全球聚看点】楼前小棚无灯黑漆漆,为解民忧万户小棚亮起灯

2023-06-01 15:18:18

拳头硬刚LCS罢工图,仅给选手两周时间,否则踢出世界赛

2023-06-01 14:21:00

每日视点!保险科技|回顾十年“蝶变”,下一个十年,如何把握?

2023-06-01 14:03:37

沪深股通|铂科新材5月31日获外资卖出0.18%股份

2023-06-01 12:44:48

法定节假日不放假又没有三倍工资怎么办?妇女节半天假是法定吗?

2023-06-01 12:27:15

逆向设计下,指向深度学习的小学英语“教—学—评”一体化实践

2023-06-01 11:49:18

环球精选!nft是什么意思_nt是什么意思

2023-06-01 10:20:23

芭提雅火山岩温泉小镇二手房怎样?澄迈二手房还能涨!

2023-06-01 09:53:26

儿童节,我的血脉里好像觉醒了什么

2023-06-01 09:11:39

速看:终于明白刘銮雄为何看上蔡少芬了_刘銮雄怎么玩蔡少芬

2023-06-01 08:52:41

浙江建投05月31日获深股通增持94.59万股

2023-06-01 08:11:40

闪图怎么搞qq(闪图签名) 环球快报

2023-06-01 07:23:48

全脂牛奶和纯牛奶的区别在哪里(全脂牛奶和纯牛奶的区别) 世界消息

2023-06-01 06:11:50

乌克兰总统泽连斯基在敖德萨召开最高统帅部会议_每日快播

2023-06-01 06:01:48

潮汐车道是什么意思图片 潮汐车道是什么意思_焦点日报

2023-06-01 04:23:42

【全球聚看点】5月31日基金净值:华安创新混合最新净值1.022,涨0.1%

2023-06-01 02:09:13

环球看热讯:茅台原浆酒53度价格表(茅台原浆酒)

2023-06-01 02:13:03

MSI冠亚夏季赛首战:JDG有可能遭WBG爆冷?新版本成关键!

2023-06-01 00:57:08

炖鸡料炖鸡的做法!详细点,谢谢!急用?|环球新消息

2023-06-01 00:08:37

礼器碑

2023-05-31 23:02:19

*ST嘉凯:明起停牌 公司股票将被终止上市

2023-05-31 22:08:18

热点聚焦:深股通连续6日净卖出五粮液 累计净卖出28.29亿元

2023-05-31 21:27:28

当前播报:洛克王国华贵天鹅绝版了吗(洛克王国华贵天鹅)

2023-05-31 20:45:37

大方一小开展“学习二十大、争做好队员”六一主题活动

2023-05-31 19:54:27

工行咸阳分行深入开展“全国科技周”宣传活动 焦点热讯

2023-05-31 18:50:50

世界时讯:省会英语_省会

2023-05-31 15:32:33

医药ETF(512010)今日已跌1.57%,连续5日获资金净流入超4亿元

2023-05-31 15:13:07

环球快资讯:中金黄金收购莱州中金100%股权,交易总额48.6亿

2023-05-31 14:20:36

陕西延安:赓续“红色”血脉 聚法治之力助推平安之治

2023-05-31 14:33:36

仁怀种植酒用高粱36.5万亩

2023-05-31 13:35:05

央行建立银行风险监测预警,抓早抓小“治未病”-焦点快播

2023-05-31 13:33:35

吉利银河L7上市在即,售价有望低于20万元

2023-05-31 12:53:30

世界动态:自酿啤酒设备一套多少钱

2023-05-31 12:24:50

中超第10轮跑动榜 韩国国脚姜祥佑高居榜首 武汉三镇外援斯坦丘紧随其后

2023-05-31 12:19:08

天天精选!寇准简介_寇准资料

2023-05-31 11:26:27

G3铜陵长江公铁大桥4号主塔封顶在即

2023-05-31 11:18:15

全球新动态:田里上演“农机秀” 助力粮食稳产增产

2023-05-31 11:21:09

黄豆猪蹄汤的做法(黄豆炖猪蹄的做法)|热消息

2023-05-31 10:18:22

当前报道:360无法打开网页怎么办(360无法打开)

2023-05-31 09:58:52

每日信息:幼儿在理发店娱乐区玩耍受伤破相,谁之责?

2023-05-31 09:33:45

网贷催收刑法193条和224条?催收如何预防?

2023-05-31 09:34:37

5月30日基金净值:景顺长城成长龙头一年持有混合A最新净值0.8368,涨0.6%

2023-05-31 09:07:14

环球观焦点:怀孕4个月女子遭家暴 江西涌山镇官方:对家庭暴力行为严厉训诫 双方和解

2023-05-31 08:27:19

限时抢购!Redmi K60 Pro 5G性价比爆款_世界即时看

2023-05-31 07:51:26

微信群内发布售卖野山羊 邓某荣因涉嫌非法狩猎罪被抓获归案|天天即时

2023-05-31 07:44:05

爱在何方电视剧84集_爱在何方主题曲_每日观点

2023-05-31 07:12:18

【全球快播报】美团-W获南向资金连续6天净买入

2023-05-31 06:43:41

宇新股份将于6月2日解禁6737.5万股

2023-05-31 06:27:26

【全球聚看点】土地热线|招商长沙拿地 比亚迪再投深圳龙岗 越秀落子武汉

2023-05-31 06:08:43

安东硕

2023-05-31 05:20:13