Java学习总结之网络操作

概述

网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。
java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。
Java支持下列常用网络操作:

  • InetAddress:用于表示网络上的硬件资源,即 IP 地址;
  • URL:统一资源定位符;
  • Socket:使用 TCP 协议实现网络通信。TCP 是传输控制协议的缩写,它保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
  • Datagram:使用 UDP 协议实现网络通信。UDP 是用户数据报协议的缩写,一个无连接的协议。提供了应用程序之间要发送的数据的数据包。

下面我们分别来学习:

InetAddress

java.net.InetAddress类是Java对IP地址(包括IPv4和IPv6)的高层表示。大多数其他网络类都要用到这个类,包括Socket,ServerSocket,URL,DatagramSocket,DatagramPacket等。一般地讲,它包括一个主机名和一个IP地址。
主机名到 IP 地址的解析 通过使用本地机器配置信息和网络命名服务(如域名系统(Domain Name System,DNS)和网络信息服务(Network Information Service,NIS))来实现。
反向名称解析 意味着对于任何 IP 地址,都返回与 IP 地址关联的主机。
InetAddress 类提供将主机名解析为其 IP 地址(或反之)的方法。

  • static InetAddress[] getAllByName(String host)
    在给定主机名的情况下,根据系统上配置的名称服务返回所有的 IP 地址。
  • static InetAddress getByAddress(byte[] addr)
    在给定原始 IP 地址的情况下,返回 InetAddress 对象。
  • static InetAddress getByAddress(String host, byte[] addr)
    根据提供的主机名和 IP 地址创建 InetAddress。
  • static InetAddress getByName(String host)
    在给定主机名的情况下确定主机的 IP 地址。
  • String getCanonicalHostName()
    获取此 IP 地址的完全限定域名。
  • String getHostAddress()
    返回 IP 地址字符串,比如192.168.1.1
  • String getHostName()
    获取此 IP 地址的主机名。比如 www.baidu.com
  • static InetAddress getLocalHost()
    返回本地主机。
  • boolean isReachable(int timeout)
    测试是否可以达到该地址。

URL

URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者FTP地址。
URL可以分为如下几个部分:
protocol://host:port/path?query#fragment
实例:http://www.runoob.com/index.html?language=cn#j2se

URL 各部分解析:
protocol(协议):可以是 http、https、ftp 、file等,上面例子是http
host(主机):www.runoob.com
port(端口号):80 ,以上URL实例并未指定端口,因为 HTTP 协议默认的端口号为 80。
path(文件路径):/index.html
query(请求参数):language=cn
fragment(定位位置):j2se,定位到网页中 id 属性为 j2se 的 HTML 元素位置 。

URL 类方法

在java.net包中定义了URL类,该类用来处理有关URL的内容。对于URL类的创建和使用,下面分别进行介绍。
java.net.URL提供了丰富的URL构建方式,并可以通过java.net.URL来获取资源。



URL类中包含了很多方法用于访问URL的各个部分,具体方法及描述如下:



以上实例演示了使用java.net的URL类获取URL的各个部分参数:
URLDemo.java

import java.net.*;
import java.io.*;
 
public class URLDemo
{
   public static void main(String [] args)
   {
      try
      {
         URL url = new URL("http://www.runoob.com/index.html?language=cn#j2se");
         System.out.println("URL 为:" + url.toString());
         System.out.println("协议为:" + url.getProtocol());
         System.out.println("验证信息:" + url.getAuthority());
         System.out.println("文件名及请求参数:" + url.getFile());
         System.out.println("主机名:" + url.getHost());
         System.out.println("路径:" + url.getPath());
         System.out.println("端口:" + url.getPort());
         System.out.println("默认端口:" + url.getDefaultPort());
         System.out.println("请求参数:" + url.getQuery());
         System.out.println("定位位置:" + url.getRef());
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }
}

结果如下:
URL 为:http://www.runoob.com/index.html?language=cn#j2se
协议为:http
验证信息:www.runoob.com
文件名及请求参数:/index.html?language=cn
主机名:www.runoob.com
路径:/index.html
端口:-1
默认端口:80
请求参数:language=cn
定位位置:j2se

URLConnections 类方法

openConnection() 返回一个 java.net.URLConnection。
例如:

  • 如果你连接HTTP协议的URL, openConnection() 方法返回 HttpURLConnection 对象。
  • 如果你连接的URL为一个 JAR 文件, openConnection() 方法将返回 JarURLConnection 对象。

URLConnection 方法列表如下:



以下实例中URL采用了HTTP 协议。 openConnection 返回HttpURLConnection对象,并通过该对象得到URL的输入流,读取字节流数据:

public static void main(String[] args) throws IOException {

    URL url = new URL("http://www.baidu.com");

    /* 字节流 */
    InputStream is = url.openStream();

    /* 字符流 */
    InputStreamReader isr = new InputStreamReader(is, "utf-8");

    /* 提供缓存功能 */
    BufferedReader br = new BufferedReader(isr);

    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }

    br.close();
}

Socket 编程

套接字使用TCP提供了两台计算机之间的通信机制。 客户端程序创建一个套接字,并尝试连接服务器的套接字。
当连接建立时,服务器会创建一个 Socket 对象。客户端和服务器现在可以通过对 Socket 对象的写入和读取来进行通信。
java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。
以下步骤在两台计算机之间使用套接字建立TCP连接时会出现:

  • 服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信。

  • 服务器调用 ServerSocket 类的 accept() 方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。

  • 服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。

  • Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。

  • 在服务器端,accept() 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。

连接建立后,通过使用 I/O 流在进行通信,每一个socket都有一个输出流和一个输入流,客户端的输出流连接到服务器端的输入流,而客户端的输入流连接到服务器端的输出流
TCP 是一个全双工的通信协议,因此数据可以通过两个数据流在同一时间发送。以下是一些类提供的一套完整的有用的方法来实现 socket。

ServerSocket 类的方法

服务器应用程序通过使用 java.net.ServerSocket 类以获取一个端口,并且侦听客户端请求
ServerSocket 类有四个构造方法:


如果 ServerSocket 构造方法没有抛出异常,就意味着你的应用程序已经成功绑定到指定的端口,并且侦听客户端请求。

这里有一些 ServerSocket 类的常用方法:


Socket 类的方法

java.net.Socket 类代表客户端和服务器都用来互相沟通的套接字。客户端要获取一个 Socket 对象通过实例化 ,而服务器获得一个 Socket 对象则通过 accept() 方法的返回值。

Socket 类有五个构造方法:


当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。
下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法:


Socket 客户端实例

如下的 GreetingClient 是一个客户端程序,该程序通过 socket 连接到服务器并发送一个请求,然后等待一个响应。
GreetingClient.java

import java.net.*;
import java.io.*;
 
public class GreetingClient
{
   public static void main(String [] args)
   {
      String serverName = args[0];
      int port = Integer.parseInt(args[1]);
      try
      {
         System.out.println("连接到主机:" + serverName + " ,端口号:" + port);
         Socket client = new Socket(serverName, port);
         System.out.println("远程主机地址:" + client.getRemoteSocketAddress());
         OutputStream outToServer = client.getOutputStream();
         DataOutputStream out = new DataOutputStream(outToServer);
 
         out.writeUTF("Hello from " + client.getLocalSocketAddress());
         InputStream inFromServer = client.getInputStream();
         DataInputStream in = new DataInputStream(inFromServer);
         System.out.println("服务器响应: " + in.readUTF());
         client.close();
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }
}

Socket 服务端实例

如下的GreetingServer 程序是一个服务器端应用程序,使用 Socket 来监听一个指定的端口。
GreetingServer.java

import java.net.*;
import java.io.*;
 
public class GreetingServer extends Thread
{
   private ServerSocket serverSocket;
   
   public GreetingServer(int port) throws IOException
   {
      serverSocket = new ServerSocket(port);
      serverSocket.setSoTimeout(10000);
   }
 
   public void run()
   {
      while(true)
      {
         try
         {
            System.out.println("等待远程连接,端口号为:" + serverSocket.getLocalPort() + "...");
            Socket server = serverSocket.accept();
            System.out.println("远程主机地址:" + server.getRemoteSocketAddress());
            DataInputStream in = new DataInputStream(server.getInputStream());
            System.out.println(in.readUTF());
            DataOutputStream out = new DataOutputStream(server.getOutputStream());
            out.writeUTF("谢谢连接我:" + server.getLocalSocketAddress() + "\nGoodbye!");
            server.close();
         }catch(SocketTimeoutException s)
         {
            System.out.println("Socket timed out!");
            break;
         }catch(IOException e)
         {
            e.printStackTrace();
            break;
         }
      }
   }
   public static void main(String [] args)
   {
      int port = Integer.parseInt(args[0]);
      try
      {
         Thread t = new GreetingServer(port);
         t.run();
      }catch(IOException e)
      {
         e.printStackTrace();
      }
   }
}

编译以上两个 java 文件代码,并执行以下命令来启动服务,使用端口号为 6066:

$ javac GreetingServer.java 
$ java GreetingServer 6066
等待远程连接,端口号为:6066...

新开一个命令窗口,执行以上命令来开启客户端:

$ javac GreetingClient.java 
$ java GreetingClient localhost 6066
连接到主机:localhost ,端口号:6066
远程主机地址:localhost/127.0.0.1:6066
服务器响应: 谢谢连接我:/127.0.0.1:6066
Goodbye!

Datagram

UDP和TCP的特点

用户数据报协议 UDP(User Datagram Protocol)无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加 UDP 首部),支持一对一、一对多、多对一和多对多的交互通信,效率高但不可靠。事实上,可以用UDP实现一个可靠的文件传输协议,而且很多人确实是这样做的:网络文件系统,简单FTP都使用了UDP协议。在这些协议中由应用程序来负责可靠性
传输控制协议 TCP(Transmission Control Protocol)面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块),每一条 TCP 连接只能是点对点的(一对一),效率低但安全可靠。

java中对UDP编程的支持

java中的UDP实现分为两个类:DatagramPacketDatagramSocket。DatagramPacket类将数据字节填充到UDP包中,这称为数据报。 DatagramSocket来发送这个包。要接受数据,可以从DatagramSocket中接受一个 DatagramPack对象,然后从该包中读取数据的内容。
这种职责的划分与TCP使用的SocketServerSocket有所不同。首先,UDP没有两台主机间唯一连接的概念,它不需要知道对方是哪个远程主机。它可以从一个端口往多个主机发送信息,但是TCP是无法做到的。其次,TCP socket把网络连接看作是流:通过从Socket得到的输入和输出流来收发数据。UDP不支持这一点,你处理总是单个数据包。填充在一个数据报中的所有数据会以包的形式进行发送,这些数据要么作为一个组要么全部接收,要么全部丢弃。一个包不一定与下一个包相关。给定两个包,没有办法知道哪个先发哪个后发。对于流来说,必须提供数据的有序队列,与之不同,数据报会尽可能快的蜂拥到接收方。

DatagramSocket类

java.net.DatagramSocket 此类表示用来发送和接收数据报包的套接字

该类主要有下列构造方法:

  • DatagramSocket() 构造数据报套接字并将其绑定到本地主机上任何可用的端口。
  • DatagramSocket(int port, InetAddress laddr) 创建数据报套接字,将其绑定到指定的地址。

常用的方法:

  • send(DatagramPacket p) 从此套接字发送数据报包。
  • receive(DatagramPacket p)从此套接字接收数据报包。
  • close() 关闭此数据报套接字。

DatagramPacket类

此类表示数据报包。

构造方法(因为UDP是无连接的,所以在用于发送的数据包中附加目的地址,而用于接收的数据包不用加地址信息):

  • DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
    构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
  • DatagramPacket(byte[] buf, int length, InetAddress address, int port)
    构造数据报包,用来将长度为 length 的包发送到指定主机上的指定端口号。
  • DatagramPacket(byte[] buf, int length)
    构造 DatagramPacket,用来接收长度为 length 的数据包。

DatagramSocket 客户端实例

UDPClient.java

public class UDPClient {
    public static void main(String[] args) {
        try {
            //1.创建数据报套接字
            DatagramSocket datagramSocket =  new DatagramSocket(6666);
            //2.创建数据报包用于封装数据和目标地址
            String str="hello world!";
            byte[] content = str.getBytes();//将字符串转换为字节的数组
            DatagramPacket datagramPacket = new DatagramPacket(content, content.length,InetAddress.getLocalHost(), 9999);
            //3.调用send方法进行发送数据
            datagramSocket.send(datagramPacket);
            //4.释放资源
            datagramSocket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

DatagramSocket 服务端实例

UDPServer.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
/**
 * DatagramSocket(int port)
 * DatagramPacket(byte[] buf, int length)  构造 DatagramPacket,用来接收长度为 length 的数据包。
 * DataPacket类中方法:
 *     getData() 返回数据缓冲区。
 *  getLength()返回将要发送或接收到的数据的长度。
 *  getPort() 返回某台远程主机的端口号,此数据报将要发往该主机或者是从该主机接收到的
 *  getAddress()返回某台机器的 IP 地址,此数据报将要发往该机器或者是从该机器接收到的。
 * 
 */
public class UDPServer {
    public static void main(String[] args) {
        try {
            //1.创建数据报套接字
            DatagramSocket socket = new DatagramSocket(9999);
            //2.创建一个数据报包
            byte[] content = new byte[1024];
            DatagramPacket datagramPacket = new DatagramPacket(content,content.length);
            //3.调用receive方法接收数据包
            socket.receive(datagramPacket);
            //4.从数据报包中获取数据
            byte[] data=  datagramPacket.getData();//获取数据报包中的数据
            int length = datagramPacket.getLength();//
            InetAddress ip = datagramPacket.getAddress();
            int port = datagramPacket.getPort();
            System.out.println("内容:"+new String(data,0,length));
            System.out.println("数据长度:"+length);
            System.out.println("发送方的IP地址:"+ip);
            System.out.println("发送方的端口号:"+port);
            //5.释放资源
            socket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

利用UDP实现聊天功能

UdpChatClient.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * 利用UDP实现聊天功能
 * @author Administrator
 *
 */
public class UdpChatClient {
    public static void main(String[] args) {
        System.out.println("---------顾客---------");
        try {
            //1.创建数据报套接字
            DatagramSocket socket = new DatagramSocket(6666);
            Scanner input = new Scanner(System.in);
            while(true){
                //2.获取用户输入
                String message = input.next();
                byte[] bs = message.getBytes();
                //3.创建数据报包
                DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"),8888);
                //4.发送数据
                socket.send(packet);
                //接收数据
                byte[] bs2 = new byte[1024];
                DatagramPacket packet2 = new DatagramPacket(bs2, bs2.length);
                socket.receive(packet2);//接收数据
                byte[] serverMesage = packet2.getData();
                String str=new String(serverMesage,0,serverMesage.length);
                System.out.println("客服说:"+str);
                if(message.equals("bye")){
                    break;
                }
            }
            //释放资源
            socket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}

UdpChatServer.java

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Scanner;

/**
 * 利用UDP实现聊天功能
 * @author Administrator
 *
 */
public class UdpChatServer {
    public static void main(String[] args) {
        System.out.println("---------客服---------");
        try {
            //1.创建数据报套接字
            DatagramSocket socket = new DatagramSocket(8888);
            Scanner input = new Scanner(System.in);
            while(true){
                //接收数据
                byte[] bs2 = new byte[1024];
                DatagramPacket packet2 = new DatagramPacket(bs2, bs2.length);
                socket.receive(packet2);//接收数据
                byte[] serverMesage = packet2.getData();
                String str=new String(serverMesage,0,serverMesage.length);
                System.out.println("顾客说:"+str);
                
                //2.获取用户输入
                String message = input.next();
                byte[] bs = message.getBytes();
                //3.创建数据报包
                DatagramPacket packet = new DatagramPacket(bs, bs.length, InetAddress.getByName("127.0.0.1"),6666);
                //4.发送数据
                socket.send(packet);
                if(message.equals("bye")){
                    break;
                }
            }
            //释放资源
            socket.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • 计算机网络概述 网络编程的实质就是两个(或多个)设备(例如计算机)之间的数据传输。 按照计算机网络的定义,通过一定...
    蛋炒饭_By阅读 1,209评论 0 10
  • 网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编...
    程序员欧阳阅读 1,998评论 1 37
  • 一、概述 1、概述: 1、网络模型:OSI参考模型和TCP/IP参考模型 2、网络通信要素:IP地址,端口号、传输...
    玉圣阅读 624评论 0 0
  • 在幼教行业里工作了三年,今天我第一次发飙了。说是发飙,其实是我自己惩罚了自己。其实起因是件很小的事情。中午站队的时...
    阿宝的育儿宝典阅读 295评论 0 0
  • 我实在已经等不下去了,我不能再等,曾经在自己心中暗自下定的决心,怎么可以说放弃就放弃。 我一直认为我的耐力还是不错...
    唯川阅读 295评论 13 14