Java 网络编程

 

说明:文中的示例引用地址http://www.oschina.net/code/snippet_1461886_46846

 

一.Java网络编程简介

通过java网络通信的支持可以非常方便的访问HTTP,FTP等服务,而且可以直接取得互联网上的远程资源,向远程资源发生GET.POST请求.

Java提供了TCP网络通信支持,建立连接后就可以通过IO流进行通信.

Java也提供了UDP网络通信支持.可以实现接收和发送数据报.多点广播通信等.

二.基本网络工具

1.InetAddress

代表IP地址,有子类Inet4Address,Inet6Address,分别代表IPv4和IPv6的地址.

使用示例:

  1:     InetAddress idd; 
  2: //    idd=InetAddress.getByName("www.baidu.com");
  3:     idd=InetAddress.getByAddress(new byte[]{(byte)180,97,33,108});
  4:     Object[] objs=new Object[]{
  5:         "是否可达:",idd.isReachable(10000),
  6:         "全限定域名:",idd.getCanonicalHostName(),
  7:         "IP字符串:",idd.getHostAddress(),
  8:         "主机名:",idd.getHostName(),
  9:         "本地IP:",InetAddress.getLocalHost()
 10:     };
 11:     print(objs);
2.URLDecoder和URLEncoder

URLDecoder和URLEncoder完成普通字符串和application/x-www-from-urlencoded MIME字符串之间的互相转换.

使用示例:

  1: public static void de_en(String str)throws UnsupportedEncodingException{
  2:     String keyWord;
  3:     keyWord=URLEncoder.encode(str, "utf-8");
  4:     System.out.println(str+"<=utf-8=>"+keyWord);
  5:     
  6:     keyWord=URLEncoder.encode(str, "gbk");
  7:     System.out.println(str+"<=gbk=>"+keyWord);
  8:     
  9:     keyWord=URLEncoder.encode(str, "unicode");
 10:     System.out.println(str+"<=unicode=>"+keyWord);
 11:   }

 

3. URL,URLConnection和URLPermission(jdk8)

URL(Uniform Resource Locator)对象代表统一资源定位器,它是指向互联网"资源"的指针.资源可以是简单的文件或目录,也可以是复杂对象的引用(数据库或搜索引擎查询).

URL由协议名,主机,端口和资源组成:

protocol://host:port/resourceName

URLConnection,标识应用程序和URL之间的通信连接;

URLPermission,用于管理HttpURLConnection的权限问题

演示示例,向WEB站点发送GET,POST请求,并获取响应内容:

  1: 
  2: public class WEBRequestDemo {
  3:   /**
  4:    * 通用请求头信息
  5:    */
  6:   private static Map<String,String> requestInfo=new HashMap<String,String>();
  7:   static{
  8:     requestInfo.put("accept","*/*");
  9:     requestInfo.put("Connection","Keep-Alive");
 10:     requestInfo.put("Content-Type","text/html;charset=utf-8");
 11:     requestInfo.put("Accept-Language","zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3");
 12:     requestInfo.put("User-Agent","Mozilla/5.0 (Windows NT 6.1; WOW64; rv:36.0) Gecko/20100101 Firefox/36.0");
 13:   }
 14:   public static void main(String[] args) {
 15:     WEBRequestDemo wrd=new WEBRequestDemo();
 16:     wrd.sendGet("http://www.w3cschool.cc/search/index.php", "q=哈");
 17:     wrd.sendPost("http://www.w3cschool.cc/search/index.php", "q=哈");
 18:   }
 19:   /**
 20:    * 使用GET方法获取远程资源
 21:    * @param url
 22:    * @param param 键值对形式的字符串"a=b&c=d"
 23:    */
 24:   public void sendGet(String urlString,String param){
 25:     String urlAddress = urlString;
 26:     try {
 27:       urlAddress = urlString+"?"+URLEncoder.encode(param,"utf-8");
 28:     } catch (UnsupportedEncodingException e1) {
 29:       e1.printStackTrace();
 30:     }
 31:     try {
 32:       //打开连接
 33:       URL url=new URL(urlAddress);
 34:       URLConnection conn=url.openConnection();
 35:       //设置请求头
 36:       setRequestHeader(conn,requestInfo);
 37:       //连接
 38:       conn.connect();
 39:       
 40:       System.out.println("响应头信息:");
 41:       Map<String, List<String>> responseInfo=conn.getHeaderFields();
 42:       for(String key : responseInfo.keySet()){
 43:         System.out.println(key+"="+Arrays.toString(responseInfo.get(key).toArray()));
 44:       }
 45:       //读取内容到文件
 46:       read("get_out.txt",conn.getInputStream());
 47:       
 48:     } catch (MalformedURLException e) {
 49:       e.printStackTrace();
 50:     } catch (IOException e) {
 51:       e.printStackTrace();
 52:     }
 53:   }
 54:   /**
 55:    * 以POST方式获取远程资源
 56:    * @param urlString
 57:    * @param param
 58:    */
 59:   public void sendPost(String urlString,String param){
 60:     try {
 61:       //打开连接
 62:       URL url=new URL(urlString);
 63:       URLConnection conn=url.openConnection();
 64:       //设置请求头
 65:       setRequestHeader(conn,requestInfo);
 66:       //发送POST请求必须设置下面两行
 67:       conn.setDoInput(true);
 68:       conn.setDoOutput(true);
 69:       try(
 70:           PrintWriter out=new PrintWriter(conn.getOutputStream());
 71:           ){
 72:         out.print(URLEncoder.encode(param, "utf-8"));
 73:         out.flush();
 74:       }
 75:       
 76:       System.out.println("响应头信息:");
 77:       Map<String, List<String>> responseInfo=conn.getHeaderFields();
 78:       for(String key : responseInfo.keySet()){
 79:         System.out.println(key+"="+Arrays.toString(responseInfo.get(key).toArray()));
 80:       }
 81:       //读取内容到文件
 82:       read("post_out.txt",conn.getInputStream());
 83:       
 84:     } catch (MalformedURLException e) {
 85:       e.printStackTrace();
 86:     } catch (IOException e) {
 87:       e.printStackTrace();
 88:     }
 89:   }
 90:   /**
 91:    * 设置请求头信息
 92:    * @param conn
 93:    * @param requestInfo
 94:    */
 95:   private void setRequestHeader(URLConnection conn,Map<String, String> requestInfo) {
 96:     for(String key : requestInfo.keySet()){
 97:       conn.setRequestProperty(key, requestInfo.get(key));
 98:     }
 99:   }
100:   public void read(String fileName,InputStream in){
101:     try(
102:       BufferedReader bufIn=new BufferedReader(new InputStreamReader(in,"utf-8"));
103:       PrintStream out=new PrintStream(fileName);
104:     ){
105:       String line;
106:       while((line=bufIn.readLine())!=null){
107:         out.println(line);
108:       }
109:     }catch(IOException e){
110:       e.printStackTrace();
111:     }
112:   }
113: }
 

四.基于TCP协议的Socket网络编程

1.TCP通信

java封装了基于TCP/IP协议的网络通信,使用Scoket对象来代表两段的通信端口,并通过Socket产生IO流来进行网络通信.

用法:

创建服务端口 ServerSocket serverSocket = new ServerSocket(port);

监听客户端连接 Socket s = serverSocket.accept();

-----------可以为每一个客户端启动一个线程来一对一服务.

客户端连接服务器 Socket socket = new Socket(host, port);

综合示例:多人聊天室 :工程文件的Client.java和Server.java

2.半关闭的Socket

在不关闭输入Socket的情况下关闭输入输出流,称为半关闭的Socket.

Socket提供了两个半关闭的方法:

shutdownInput() : 只关闭输入流.

shutdownOutput() : 只关闭输出流.

3.使用 NIO 实现非阻塞通信

image

从1.4开始java提供了NIO API来支持开发高性能的网络服务器.

NIO非阻塞服务器使用Selector来监听通信需求.通过SelectionKey保存要通信的管道.

通过将连接端口注册到Selector来监听通信,当有通信产生时,将管道与Selector连接所代表的SelectionKey加入

集合中,通过调用Selector的selectedKeys()方法获取.

一般建立流程:

  1:       //实例一个Selector
  2:       Selector selector=Selector.open();
  3:       
  4:       //通过open()方法打开一个未绑定的ServerScoketChannel实例
  5:       ServerSocketChannel serverChannel = ServerSocketChannel.open();
  6:       InetSocketAddress ass=new InetSocketAddress(host,port);
  7:       //绑定IP地址
  8:       serverChannel.bind(ass);
  9:       //设置为非阻塞模式,并注册到Selector
 10:       serverChannel.configureBlocking(false);
 11:       serverChannel.register(selector, SelectionKey.OP_ACCEPT);
 12:       
 13:       //实例化一个Socket管道
 14:       SocketChannel socketChannel =SocketChannel.open(ass);
 15:       //设置操作与模式
 16:       socketChannel.configureBlocking(false);
 17:       socketChannel.register(selector, SelectionKey.OP_READ);
 18:       
 19:       //监控通信需求
 20:       while(selector.select()>0){
 21:         //遍历所有要通信的管道
 22:         for(SelectionKey sk : selector.selectedKeys()){
 23:           //处理 
 24:         }
 25:       }

完整示例程序: 工程文件的NIOServer.java和NIOClient.java

4.使用Java7的AIO实现非阻塞通信

简单的例子:

  1: 
  2: /**
  3:  * 实现一个简单的AIO服务器例子
  4:  *
  5:  */
  6: public class SimpleAIOServer {
  7:   public static void main(String[] args) throws Exception {
  8:     new SimpleAIOServer().init();
  9:   }
 10:   public static int PORT = 9090;
 11:   private Charset charset = Charset.forName("utf-8");
 12: 
 13:   public void init() throws Exception {
 14:     AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel
 15:         .open().bind(new InetSocketAddress(PORT));
 16:     while(true){
 17:       AsynchronousSocketChannel socketChannel=serverChannel.accept().get();
 18:       socketChannel.write(charset.encode("欢迎进入")).get();
 19:     }
 20:   }
 21: }
 22: 
 23: /**
 24:  *AIO简单实现客户端 
 25:  *
 26:  */
 27: public class SimpleAIOClient {
 28: 
 29:   public static void main(String[] args) throws Exception {
 30:     new SimpleAIOClient().init();
 31:   }
 32:   
 33:   private Charset charset=Charset.forName("utf-8");
 34:   private static int PORT =9090;
 35:   public void init() throws Exception{
 36:     ByteBuffer buffer=ByteBuffer.allocate(1024);
 37:     AsynchronousSocketChannel socketChannel=AsynchronousSocketChannel.open();
 38:     socketChannel.connect(new InetSocketAddress("127.0.0.1",PORT)).get();
 39:     socketChannel.read(buffer).get();
 40:     buffer.flip();
 41:     System.out.println("服务器信息:"+charset.decode(buffer));
 42:   }
 43: }

上面的例子非常简单,为了充分展现AIO的优势,应该使用线程池管理IOChannel.

  1: //创建线程池
  2: ExecutorService executor =Executors.newFixedThreadPool(20);
  3: //异步ChannelGroup
  4: AsynchronousChannelGroup channelGroup=AsynchronousChannelGroup.withThreadPool(executor);
  5: //通过ChannelGroup打开Server
  6: AsynchronousServerSocketChannel server=AsynchronousServerSocketChannel.open(channelGroup).bind(new InetSocketAddress(PORT));

综合示例,使用AIO实现多人聊天室:工程文件AIOServer.java和AIOClient.java

 

五.UDP协议编程基础

1.在什么情况下使用UDP协议?

UDP协议是无连接的,可靠性低的传输层协议,

UDP和TCP的区别:

UDP不必建立传输链路,不知道接收方是谁,也不必管数据被收到没有.就只是把数据发出去就行了.

TCP是一种可靠的,需要建立连接的协议.又要负责连接,又要负责保证数据正确传达.

因为UDP面向无连接,所以通信效率高,适用于传输少量类容,实时性强,可靠性要求不高的应用环境,例如网络游戏,视频等.

2.Java中如何基于UDP协议编程?

发送用法:请将数据,IP地址,端口给我,我给你打包后发送出去,其他的你不用管.

接收用法:监听一个端口,如果有人传给我一个数据包,你可以从我这取走.

说明:我是谁?我就是DatagramSocket,数据包是什么?DatagramPacket是也.

 

简单示例:

  1: 
  2: /**
  3:  * 
  4:  *基于UDP协议的数据传输
  5:  */
  6: public class UDPServer {
  7: 
  8:   public static void main(String[] args) throws SocketException {
  9:     new UDPServer().init();
 10:   }
 11:   
 12:   /**
 13:    * 一个自发自收的程序
 14:    */
 15:   private DatagramSocket outSocket;
 16:   private int outNum=0;
 17:   private int inNum=0;
 18:   private DatagramSocket inSocket;
 19:   private int PORT=9090;
 20:   public void init() throws SocketException{
 21:     outSocket=new DatagramSocket();
 22:     inSocket=new DatagramSocket(PORT);
 23:     new Thread(){
 24:       public void run(){
 25:         while(true){
 26:           try {
 27:             send();
 28:             Thread.sleep(100);
 29:           } catch (Exception e) {
 30:             e.printStackTrace();
 31:           }
 32:         }
 33:       }
 34:     }.start();
 35:     new Thread(){
 36:       public void run(){
 37:         while(true){
 38:           try {
 39:             receive();
 40: //            Thread.sleep(2000);
 41:           } catch (Exception e) {
 42:             e.printStackTrace();
 43:           }
 44:         }
 45:       }
 46:     }.start();
 47:     long start=System.currentTimeMillis();
 48:     new Thread(){
 49:       public void run(){
 50:         while(System.currentTimeMillis()-start<1000*60){
 51:         }
 52:         System.out.println("接收数据"+inNum+",发送数据 "+outNum+",比率="+(inNum*1.0/outNum*100.0)+"%");
 53:         System.exit(0);
 54:       }
 55:     }.start();
 56:     
 57:   }
 58:   public void send() throws IOException{
 59:     byte[] outb=new byte[1024];
 60:     String content=String.valueOf(new Random().nextInt(10000));
 61:     outb=content.getBytes("utf-8");
 62:     DatagramPacket outPacket = new DatagramPacket(outb,outb.length,InetAddress.getLocalHost(),PORT);
 63:     outSocket.send(outPacket);
 64:     outNum++;
 65:     System.out.println("发送数据"+content);
 66:     
 67:   }
 68:   public void receive() throws IOException{
 69:     DatagramPacket inPacket = new DatagramPacket(new byte[1024],1024);
 70:     inSocket.receive(inPacket);
 71:     byte[] inb=inPacket.getData();
 72:     String content=new String(inb,"utf-8");
 73:     inNum++;
 74:     System.out.println("收到内容:"+content);
 75:     
 76:   }
 77:   
 78: }

 

3.使用MulticastSocket多点广播

DatagramSocket只能将数据传输到指定地址,而MulticastSocket可以将数据包以广播形式发送到对个地址.

当MulticastSocket用于发送数据时,需要指定发送的多点广播地址.

当MulticastSocket用于接收数据时,需要为其指定端口.

示例,多人聊天室MulticastSocketDemo.java

六.使用代理服务器

1.为什么要使用代理服务器?

一般浏览器访问资源时,直接向目的服务器请求资源.如果使用代理服务器,那么浏览器就向代理服务器发送信息,再由代理服务器向资源所在服务器请求.也就是代理浏览器请求资源.

代理服务器可以缓存请求的资源,当浏览器请求的资源在代理服务器中存在且是最新的,那么代理服务器就直接返回资源给浏览器,加快了资源请求速度.而且使用代理服务器可以隐藏自身IP,突破IP限制.

2.如何使用代理?

URLConnection和Socket的构造方法中都可以传入Proxy.剩下的操作是一样的.

构造一个Proxy需要代理服务器地址和服务器类型两个参数.

  1: Proxy proxy=new Proxy(Proxy.Type.HTTP,new InetSocketAddress(ProxyAddress,ProxyPort));
  2: URLConnection conn=url.openConnection(proxy);
  3: Socket socket=new Socket(proxy);
  4: 
3.自动选择代理服务器

如果有多个代理服务器,使用ProxySelector可以为程序自动构建代理服务器,免去了重复构建的繁琐.

为了使用自动代理,你需要实现ProxySelector类的两个方法:

List<Proxy> select(URI uri) : 返回代理服务器列表

connectionFailed(URI uri,SocketAddress sa,IOException) : 连接代理服务器失败时调用.

在实现了ProxySelector类之后,调用ProxySelector.setDefault(ProxySelector ps)注册代理选择器.

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值