Java 网络编程基础

Java 网络编程

网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来。

java.net 包中 J2SE 的 API 包含有类和接口,它们提供低层次的通信细节。你可以直接使用这些类和接口,来专注于解决问题,而不用关注通信细节。

java.net 包中提供了两种常见的网络协议的支持:

  • TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。
  • UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层。一个无连接的协议。提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。

1、Socket编程(TCP)

套接字使用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 类有四个构造方法:

构造方法方法描述
public ServerSocket(int port) throws IOException创建绑定到特定端口的服务器套接字。
public ServerSocket(int port, int backlog) throws IOException利用指定的 backlog 创建服务器套接字并将其绑定到指定的本地端口号。
public ServerSocket(int port, int backlog, InetAddress address) throws IOException使用指定的端口、侦听 backlog 和要绑定到的本地 IP 地址创建服务器。
public ServerSocket() throws IOException创建非绑定服务器套接字。

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

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

方法方法描述
public int getLocalPort()返回此套接字在其上侦听的端口。
public Socket accept() throws IOException侦听并接受到此套接字的连接。
public void setSoTimeout(int timeout)通过指定超时值启用/禁用 SO_TIMEOUT,以毫秒为单位。
public void bind(SocketAddress host, int backlog)将 ServerSocket 绑定到特定地址(IP 地址和端口号)。

Socket 类的方法

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

Socket 类有五个构造方法:

构造方法方法描述
public Socket(String host, int port) throws UnknownHostException, IOException创建一个流套接字并将其连接到指定主机上的指定端口号。
public Socket(InetAddress host, int port) throws IOException创建一个流套接字并将其连接到指定 IP 地址的指定端口号。
public Socket(String host, int port, InetAddress localAddress, int localPort) throws IOException创建一个套接字并将其连接到指定远程主机上的指定远程端口。
public Socket(InetAddress host, int port, InetAddress localAddress, int localPort) throws IOException创建一个套接字并将其连接到指定远程地址上的指定远程端口。
public Socket()通过系统默认类型的 SocketImpl 创建未连接套接字

当 Socket 构造方法返回,并没有简单的实例化了一个 Socket 对象,它实际上会尝试连接到指定的服务器和端口。

下面列出了一些感兴趣的方法,注意客户端和服务器端都有一个 Socket 对象,所以无论客户端还是服务端都能够调用这些方法。

方法方法描述
public void connect(SocketAddress host, int timeout) throws IOException将此套接字连接到服务器,并指定一个超时值。
public InetAddress getInetAddress()返回套接字连接的地址。
public int getPort()返回此套接字连接到的远程端口。
public int getLocalPort()返回此套接字绑定到的本地端口。
public SocketAddress getRemoteSocketAddress()返回此套接字连接的端点的地址,如果未连接则返回 null。
public InputStream getInputStream() throws IOException返回此套接字的输入流。
public OutputStream getOutputStream() throws IOException返回此套接字的输出流。
public void close() throws IOException关闭此套接字。

InetAddress 类的方法

这个类表示互联网协议(IP)地址。下面列出了 Socket 编程时比较有用的方法:

方法方法描述
static InetAddress getByAddress(byte[] addr)在给定原始 IP 地址的情况下,返回 InetAddress 对象。
static InetAddress getByAddress(String host, byte[] addr)根据提供的主机名和 IP 地址创建 InetAddress。
static InetAddress getByName(String host)在给定主机名的情况下确定主机的 IP 地址。
String getHostAddress()返回 IP 地址字符串(以文本表现形式)。
String getHostName()获取此 IP 地址的主机名。
static InetAddress getLocalHost()返回本地主机。
String toString()将此 IP 地址转换为 String。

TCP实现文件上传功能

客户端:

//文件从客户端上传到服务端
public class FileUploadClient {
    public static void main(String[] args) throws Exception {
        //1、要先知道服务器的地址,端口号
        InetAddress ip = InetAddress.getByName("127.0.0.1");
        int port = 8888;

        //2、创建一个Socket连接
        Socket socket = new Socket(ip, port);

        //3、创建一个输出流
        OutputStream os = socket.getOutputStream();

        //4、读取文件
        FileInputStream fis = new FileInputStream(new File("src//image.png"));

        //5、写文件
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fis.read(buffer)) != -1){
            os.write(buffer, 0, len);
        }

        //通知服务器,已传输完毕
        socket.shutdownOutput();//关闭客户端的输出流

        //确定服务器接收完毕,才能够断开连接
        InputStream is = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();

        byte[] buffer2 = new byte[1024];
        int len2;
        while ((len2 = is.read(buffer2)) != -1){
            baos.write(buffer2, 0, len2);
        }
        System.out.println(baos.toString());

        //5、关闭资源
        baos.close();
        is.close();
        fis.close();
        os.close();
        socket.close();
    }
}

服务端:

//服务端接收客户端上传的文件
public class FileUploadServer {
    public static void main(String[] args) throws Exception {
        //1、创建服务器地址
        ServerSocket serverSocket = new ServerSocket(8888);

        //2、等待客户端连接进来
        Socket socket = serverSocket.accept();

        //3、获取输入流
        InputStream is = socket.getInputStream();

        //4、文件输出
        FileOutputStream fos = new FileOutputStream(new File("d://image.png"));
        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1){
            fos.write(buffer, 0, len);
        }

        //通知客户端我接收完毕了
        OutputStream os = socket.getOutputStream();
        os.write("我已接收完毕,你可以断开连接了".getBytes());


        //关闭资源
        os.close();
        fos.close();
        is.close();
        socket.close();
        serverSocket.close();
    }
}

2、UDP通信

多线程实现两用户通信:

发送消息动作:

public class TalkSend implements Runnable {
    private DatagramSocket socket = null;
    private int fromPoint;
    private String toIP;
    private int toPoint;

    public TalkSend(int fromPoint, String toIP, int toPoint) {
        this.fromPoint = fromPoint;
        this.toIP = toIP;
        this.toPoint = toPoint;
        try {
            socket = new DatagramSocket(fromPoint);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
        while (true) {
            try {
                //1、从控制台拿到需要发送的数据
                Scanner in = new Scanner(System.in);
                String data = in.nextLine();
                byte[] buffer = data.getBytes();

                //2、将数据封装成数据包,用于socket传送
                DatagramPacket packet = new DatagramPacket(buffer, buffer.length, new InetSocketAddress(toIP, toPoint));

                //3、发送
                socket.send(packet);

                //4、如果此次发送的是bye,就关闭通信
                if(data.equals("bye"))
                    break;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        socket.close();
    }
}

接收消息动作:

public class TalkReceive implements Runnable {
    private int myPoint;
    private DatagramSocket socket = null;
    private String fromMsg = null;

    public TalkReceive(int myPoint, String fromMsg) {
        this.myPoint = myPoint;
        this.fromMsg = fromMsg;
        try {
            socket = new DatagramSocket(myPoint);
        } catch (SocketException e) {
            e.printStackTrace();
        }
    }


    @Override
    public void run() {
        while (true){
            try {
                //1、准备接受的包裹
                byte[] container = new byte[1024];
                DatagramPacket packet = new DatagramPacket(container,0, container.length);

                //2、接受数据并放入数据包中
                socket.receive(packet);

                //3、拿出数据包中的数据
                byte[] data = packet.getData();
                String receiveData = new String(data, 0, data.length);

                //4、打印数据
                System.out.println(fromMsg + ":" + receiveData);

                //4、如果对方发送的是bye,就关闭通信
                if(receiveData.equals("bye"))
                    break;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        socket.close();
    }
}

用户一:

public class chatOne {
    public static void main(String[] args) {
        new Thread(new TalkSend(7777, "localhost", 6666)).start();
        new Thread(new TalkReceive(9999, "Two")).start();
    }
}

用户二;

public class charTwo {
    public static void main(String[] args) {
        new Thread(new TalkSend(8888, "localhost", 9999)).start();
        new Thread(new TalkReceive(6666, "One")).start();
    }
}

3、URL处理

URL(Uniform Resource Locator)中文名为统一资源定位符,有时也被俗称为网页地址。表示为互联网上的资源,如网页或者 FTP 地址。

URL 可以分为如下几个部分。

protocol://host:port/path?query#fragment

protocol(协议)可以是 HTTP、HTTPS、FTP 和 File,port 为端口号,path为文件路径及文件名。

HTTP 协议的 URL 实例如下:

http://www.baidu.com/index.html?language=cn#j2se

URL 解析:

  • **协议为(protocol):**http
  • 主机为(host:port):www.baidu.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来获取资源。

构造方法方法描述
public URL(String protocol, String host, int port, String file) throws MalformedURLException通过给定的参数(协议、主机名、端口号、文件名)创建URL。
public URL(String protocol, String host, String file) throws MalformedURLException使用指定的协议、主机名、文件名创建URL,端口使用协议的默认端口。
public URL(String url) throws MalformedURLException通过给定的URL字符串创建URL
public URL(URL context, String url) throws MalformedURLException使用基地址和相对URL创建

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

方法方法描述
public String getPath()返回URL路径部分。
public String getQuery()返回URL查询部分。
public String getAuthority()获取此 URL 的授权部分。
public int getPort()返回URL端口部分
public int getDefaultPort()返回协议的默认端口号。
public String getProtocol()返回URL的协议
public String getHost()返回URL的主机
public String getFile()返回URL文件名部分
public String getRef()获取此 URL 的锚点(也称为"引用")。
public URLConnection openConnection() throws IOException打开一个URL连接,并运行客户端访问资源。

测试URL方法
public class URLDemo
{
   public static void main(String [] args)
   {
      try
      {
         URL url = new URL("http://www.baidu.com:8080/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.baidu.com:8080/index.html?language=cn#j2se
协议为:http
验证信息:www.baidu.com:8080
文件名及请求参数:/index.html?language=cn
主机名:www.baidu.com
路径:/index.html
端口:8080
默认端口:80
请求参数:language=cn
定位位置:j2se

URLConnections 类方法

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

例如:

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

URLConnection 方法列表如下:

方法方法描述
Object getContent()检索URL链接内容
Object getContent(Class[] classes)检索URL链接内容
String getContentEncoding()返回头部 content-encoding 字段值。
int getContentLength()返回头部 content-length字段值
String getContentType()返回头部 content-type 字段值
int getLastModified()返回头部 last-modified 字段值。
long getExpiration()返回头部 expires 字段值。
long getIfModifiedSince()返回对象的 ifModifiedSince 字段值。
public void setDoInput(boolean input)URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输入,则将 DoInput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 true。
public void setDoOutput(boolean output)URL 连接可用于输入和/或输出。如果打算使用 URL 连接进行输出,则将 DoOutput 标志设置为 true;如果不打算使用,则设置为 false。默认值为 false。
public InputStream getInputStream() throws IOException返回URL的输入流,用于读取资源
public OutputStream getOutputStream() throws IOException返回URL的输出流, 用于写入资源。
public URL getURL()返回 URLConnection 对象连接的URL

使用URL下载网络资源

public class UrlTest {
    public static void main(String[] args) throws IOException {
        //1、创建资源的URL
        URL url = new URL("https://www.baidu.com/img/pc_10cd458fd1807b67b2ba322e4cf973e1.gif");

        //2、根据URL拿到连接
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();

        //3、从连接中拿到输入流
        InputStream is = connection.getInputStream();

        //4、下载该资源到本地
        FileOutputStream fos = new FileOutputStream(new File("d://baidu.gif"));

        byte[] buffer = new byte[1024];
        int len;
        while ((len = is.read(buffer)) != -1)
            fos.write(buffer, 0, len);

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值