Socket编程(三)-协议处理框架
2015-04-07 17:06
120 查看
1. 无论ftp服务器, 还是http服务器, 都以自身的协议支撑着socket通信, Java抽象了协议处理框架, 使得自己实现基于协议的socket通信(URL不支持jdbc与rmi协议,报异常)
2. 框架里的类 :
1) URL : 客户端要访问的远程资源
2) URLConnection : 客户端与服务器的连接 (可从中获取输入输出流)
3) URLStreamHandler : 创建与协议相关的URLConnection (协议处理器)
4) ContentHandler : 解析服务器发送的数据, 将其封装成java对象 (内容处理器)
一. URL :
通过url.openStream()下载网页
1) URL类通过构造方法中的协议类型, 选择创建与之匹配的URLStreamHandler子类实例
1. 查找URL类内部的缓存, 看其中是否有对应的URLStreamHandler
2. 查看用户是否通过UR.setURLStreamHandlerFactory()设置了工厂类, 若是, 则通过工厂类的createURLStreamHandler()创建协议处理器
3. 用户通过java -Djava.protocal,handler.pkgs=类, 设置了协议处理器
4. 若以上都不是, 则实例化sun.net.www.protocal.协议名.Handler, 作为URLStreamHandler
2) url.openConnection() 调用了 URLStreamHandler的openConnection(), 创建URLConnection
3) url.openStream() 调用了URLConnection的getInputStream()获取输入流
4) url.getContent() 调用了URLConnection的getConnection() --> ContentHandler的getContent()
1) URLConnection的2个属性 : doInput, doOutput (boolean)
分别用来控制是否允许客户端获取输入流(向服务器写数据), 输出流(向服务器发数据)
2) 方法 :
(1) getHeaderField(String name) : 获取服务器响应头中name属性的值
(2) getContentType() : 获取响应正文的类型 (HTTP服务器中,响应头包含响应正文的类型)
(3) getContentLength() : 获取响应正文的长度 (HTTP服务器中,响应头包含响应正文的长度)
(4) getContentEncoding() : 获取响应正文编码
(5) 静态方法 : 根据文件名获取文件的MIME类型 guessContentTypeFromName(String fileName)
三. 协议处理框架流程
1) 设置URLStreamHandlerFactory和URLContentHandlerFactory
2) 当URLStreamHandlerFactory发现协议为echo, 创建EchoURLSTreamHandler, 在该类的openConnection()中创建EchoURLConnection
3) EchoURLConnection中 包含一个连接服务器的Socket, 从该Socket中获取输入输出流
4) 当eCHOURLConnectionHandlerFactory发现服务器发回来的响应正文mime的类型为text/plain, 创建EchoContentHandler
5) 创建EchoContentHandler的getContent()从输入流中获取字符串
2. 框架里的类 :
1) URL : 客户端要访问的远程资源
2) URLConnection : 客户端与服务器的连接 (可从中获取输入输出流)
3) URLStreamHandler : 创建与协议相关的URLConnection (协议处理器)
4) ContentHandler : 解析服务器发送的数据, 将其封装成java对象 (内容处理器)
一. URL :
通过url.openStream()下载网页
1) URL类通过构造方法中的协议类型, 选择创建与之匹配的URLStreamHandler子类实例
1. 查找URL类内部的缓存, 看其中是否有对应的URLStreamHandler
2. 查看用户是否通过UR.setURLStreamHandlerFactory()设置了工厂类, 若是, 则通过工厂类的createURLStreamHandler()创建协议处理器
3. 用户通过java -Djava.protocal,handler.pkgs=类, 设置了协议处理器
4. 若以上都不是, 则实例化sun.net.www.protocal.协议名.Handler, 作为URLStreamHandler
2) url.openConnection() 调用了 URLStreamHandler的openConnection(), 创建URLConnection
3) url.openStream() 调用了URLConnection的getInputStream()获取输入流
4) url.getContent() 调用了URLConnection的getConnection() --> ContentHandler的getContent()
public class HttpClient_URL { //url.openStream()获取输入流 public static void main(String[] args) throws IOException { URL url = new URL("http://www.baidu.com"); InputStream in = url.openStream(); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int len= 0; while((len=in.read(b))!=-1){ out.write(b,0,len); } System.out.println(new String(out.toByteArray())); //打印网页 } }二. URLConnection (客户端与服务器的连接)
1) URLConnection的2个属性 : doInput, doOutput (boolean)
分别用来控制是否允许客户端获取输入流(向服务器写数据), 输出流(向服务器发数据)
2) 方法 :
(1) getHeaderField(String name) : 获取服务器响应头中name属性的值
(2) getContentType() : 获取响应正文的类型 (HTTP服务器中,响应头包含响应正文的类型)
(3) getContentLength() : 获取响应正文的长度 (HTTP服务器中,响应头包含响应正文的长度)
(4) getContentEncoding() : 获取响应正文编码
(5) 静态方法 : 根据文件名获取文件的MIME类型 guessContentTypeFromName(String fileName)
//利用URLConnection获取服务器的响应结果 public class HttpClient_URLConnection { public static void main(String[] args) throws IOException { URL url = new URL("http://www.baidu.com"); URLConnection urlConnection = url.openConnection(); //利用URLStreamHandler的openConnection() System.out.println("响应正文长度:"+urlConnection.getContentLength()); System.out.println("相应正文类型:"+urlConnection.getContentType()); InputStream in = urlConnection.getInputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int len = 0; while((len=in.read(b))!=-1){ out.write(b, 0, len); } System.out.println(new String(out.toByteArray())); } @Test public void testURLConnection(){ String contentType = URLConnection.guessContentTypeFromName("123.png"); System.out.println(contentType); //image/png } @Test public void testURLEncoder(){ String str = URLEncoder.encode("白色"); System.out.println(str); // %E7%99%BD%E8%89%B2 } }
//用URLCOnnection进行post请求 public class URLConnection_post { public String doPost(String bookName) throws IOException{ URL url = new URL("http://www.javathinker.org/aboutBook.jsp"); //初始化一个与协议相关的URLStreamHandler URLConnection urlConnection = url.openConnection(); urlConnection.setDoOutput(true); OutputStream out = urlConnection.getOutputStream(); PrintWriter writer = new PrintWriter(out); writer.print("title"); //print()方法把一切数据转换何成string,用write()写出 writer.print("="); writer.print(URLEncoder.encode(bookName,"GB2312")); InputStream in = urlConnection.getInputStream(); ByteArrayOutputStream bos = new ByteArrayOutputStream(); byte[] b = new byte[1024]; int len = 0; while((len=in.read(b))!=0){ bos.write(b,0,len); } return new String(bos.toByteArray()); } public static void main(String[] args) throws IOException { String result = new URLConnection_post().doPost("JavaScriptで画像を振動(ブルブル)させる"); System.out.println(result); } }
三. 协议处理框架流程
1) 设置URLStreamHandlerFactory和URLContentHandlerFactory
2) 当URLStreamHandlerFactory发现协议为echo, 创建EchoURLSTreamHandler, 在该类的openConnection()中创建EchoURLConnection
3) EchoURLConnection中 包含一个连接服务器的Socket, 从该Socket中获取输入输出流
4) 当eCHOURLConnectionHandlerFactory发现服务器发回来的响应正文mime的类型为text/plain, 创建EchoContentHandler
5) 创建EchoContentHandler的getContent()从输入流中获取字符串
//客户端调用协议处理框架 public class EchoClient { public static void main(String[] args) throws IOException { // 1.设置URLStreamHandler,ContentHandler URL.setURLStreamHandlerFactory(new EchoURLStreamHandlerFactory()); URLConnection.setContentHandlerFactory(new EchoContentHandlerFactory()); URL url = new URL("echo://localhost:12121"); EchoURLConnection urlConnection = (EchoURLConnection) url.openConnection(); urlConnection.setDoOutput(true); PrintWriter writer = new PrintWriter(urlConnection.getOutputStream(),true); for(;;){ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); String msg = reader.readLine(); writer.println(msg); String content = (String)urlConnection.getContent(); System.out.println(content); } } }
public class EchoContentHandlerFactory implements ContentHandlerFactory { public ContentHandler createContentHandler(String mimetype) { if(mimetype.equals("text/plain")) return new EchoContentHandler(); return null; } }
//用于处理服务器发回来的数据 (2个重载方法) public class EchoContentHandler extends ContentHandler { @Override public Object getContent(URLConnection connection) throws IOException { //读取服务器发回的一行数据,把他转换为字符串 InputStream in = connection.getInputStream(); BufferedReader reader = new BufferedReader(new InputStreamReader(in,"utf-8")); System.out.println(reader.readLine()); return reader.readLine(); } @Override //getContent(URLConnection, Class[])会先试图把输入流读到的内容,转换成class数组的第一个对象,失败在转换成第二个对象 public Object getContent(URLConnection connection, Class[] classes) throws IOException { InputStream in = connection.getInputStream(); for(Class c:classes){ if(c == InputStream.class) return in; if(String.class == c) return this.getContent(connection); } return null; } } /** URLconnetcion的getContent()发放流程 1) 在自身的缓存HashTable中查找是否已经存在该协议的Contenthandler 2) 用private的getContenthandler()返回一个 内容处理器,若用户已经setContentHandler(),则可以成功调用该类的getContent 3) 系统属性设置 : java -Djava.content.handler.pkgs=com.EchoURLStreamHandler 4) 实例化sun.net.www.content包中的内容处理器,eg:(sun.net.www.content.http.Handler) */
//该工厂类根据协议类型创建RLStreamHandler public class EchoURLStreamHandlerFactory implements URLStreamHandlerFactory{ public URLStreamHandler createURLStreamHandler(String protocol) { if(protocol.equals("echo")) return new EchoURLStreamHandler(); return null; } }
//该类, 创建URLConnection类 public class EchoURLStreamHandler extends URLStreamHandler{ @Override protected URLConnection openConnection(URL u) throws IOException { return new EchoURLConnection(u); } }
//URLConnection负责在框架中连接给出的URL,和协议自身的默认端口 public class EchoURLConnection extends URLConnection { private Socket soket = null; private final static int port = 12121; protected EchoURLConnection(URL url) { //父类URLConnection接收URL super(url); } @Override public synchronized void connect() throws IOException { if(!this.connected) this.soket = new Socket(this.url.getHost(),this.port); this.connected = true; } @Override public synchronized InputStream getInputStream() throws IOException { if(!this.connected) this.connect(); return this.soket.getInputStream(); } @Override public synchronized OutputStream getOutputStream() throws IOException { if(!this.connected) this.connect(); return this.soket.getOutputStream(); } public synchronized void disConnect() throws IOException{ if(this.connected){ this.soket.close(); this.connected = false; } } // 必须有该方法,否则java.net.UnknownServiceException: no content-type @Override public String getContentType() { return ("text/plain"); } }
相关文章推荐
- Socket开发之通讯协议及处理
- Socket开发之通讯协议及处理
- Socket 编程经验谈---如何处理socket连接后服务器端或客户端的断开
- <转载>Socket开发之通讯协议及处理(解决粘包问题)
- 客户端协议处理框架(URLConnection)
- Socket 编程经验谈---如何处理socket连接后服务器端或客户端的断开
- HTTP协议处理框架 - 最简单的GET请求拼装和Response解析
- linux socket编程基于本地unix域格式的协议族
- 关于Silverlight Socket编程中不能传输汉字的临时处理方法
- Linux - socket编程处理EINTR错误
- Socket开发之通讯协议及处理
- Socket开发之通讯协议及处理
- Socket开发之通讯协议及处理
- linux socket --sctp协议编程
- Socket开发之通讯协议及处理(中软国际 Fourth Day)
- Socket开发之通讯协议及处理
- 探讨与比较Java和.NET的事件处理框架-Java基础-Java-编程开发
- 基于 TCP (面向连接)和无连接UDP协议的 socket 套接字编程
- C++多线程编程以及epoll处理socket通信时多端口问题
- 简单的TCP协议 socket编程(C语言版服务器和客户端)