您的位置:首页 > 编程语言

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()
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");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: