Java学习之网络编程实现

网络编程实现

  • Java网络编程常用类
    • InetAddress
    • InetSocketAddress
    • URL类
  • TCP通信的实现
  • UDP通信的实现


Java网络编程常用类

Java为了可移植性,不允许直接调用操作系统,而是由java.net包来提供网络功能能,JVM负责提供与操作系统的实际连接。


InetAddress

作用
InetAddress用于封装计算机的IP地址和DNS(无端口信息,DNS-Domain Name System是系统域名)。
特点
InetAddress类没有构造器,如果要得到对象,只能通过静态方法getLocalHost()、getByName()、getAllByName()、getAddress()、getAddress()和getHostName()实现。
使用如下:

import java.net.InetAddress;
import java.net.UnknownHostException;

public class Study{
     
    public static void main(String[] args) throws UnknownHostException {
     
        //使用getLocalHost方法创建InetAddress对象
        InetAddress address = InetAddress.getLocalHost();
        /*getAddress()方法返回的byte数组是有符号的,在Java中byte类型的取值范围是-128〜127,如果
        返回的IP地址的某个字节是大于127的整数,在byte数组中就是负数。由于Java中没有无符号byte类型因
        此,要想显示正常的IP地址,必须使用int或long类型。下面代码演示了如何利用getAddress返回IP地
        址,以及如何将IP地址转换成正整数形式*/
        byte[] ip = address.getAddress();
        for(byte temp : ip){
     
            int Ip = (temp < 0) ? temp + 256 : temp;
            System.out.print(Ip + " ");
        }
        System.out.println();
        System.out.println(address.getHostAddress());//输出IP地址
        System.out.println(address.getHostName());//输出计算机的名字
        //根据域名得到InetAddress对象
        InetAddress address1 = InetAddress.getByName("blog.csdn.net");
        System.out.println(address1.getHostAddress());//输出csdn服务器IP
        System.out.println(address1.getHostName());//输出csdn域名
        //根据IP得到InetAddress对象
        InetAddress address2 = InetAddress.getByName("47.95.47.253");//csdnIP
        System.out.println(address2.getHostAddress());//输出csdn服务器IP
        //输出IP地址而不是域名。如果这个IP地址不存在或者DNS服务器不允许进行IP地址和域名的映射,
        //getHostName方法就直接返回这个IP地址
        System.out.println(address2.getHostName());
    }
}

InetSocketAddress

InetSocketAddress用于包含IP地址和端口信息,常用于Socket通信。该类实现IP套接字地址(IP地址+端口号),不依赖任何协议。使用如下:

import java.net.InetSocketAddress;
import java.net.UnknownHostException;

public class Study{
     
    public static void main(String[] args) throws UnknownHostException {
     
        InetSocketAddress socketAddress = new InetSocketAddress("127.0.0.1", 8888);
        InetSocketAddress socketAddress1 = new InetSocketAddress("localhost", 9999);
        System.out.println(socketAddress.getHostName());
        System.out.println(socketAddress1.getAddress());
    }
}//输出如下
127.0.0.1
localhost/127.0.0.1

URL类

IP地址唯一表示了Internet上的计算机,而URL则标识了这些计算机上的资源。URL类代表一个统一资源定位符,它是指向物联网资源的指针。资源可以是简单的文件或目录,也可以是对更为复杂的对象的引用。
JDK提供URL类,全名是java.net.URL,有了它就可以使用它的各种方法来对URL对象进行分割、合并等处理。
使用如下:

import java.net.MalformedURLException;
import java.net.URL;

public class Study{
     
    public static void main(String[] args) throws MalformedURLException {
     
        //正在编写的网络编程url
        URL url = new URL("https://editor.csdn.net/md?articleId=107335888");
        System.out.println("获取与此URL关联的协议的默认端口:" + url.getDefaultPort());
        System.out.println("端口号后面的内容:" + url.getFile());
        System.out.println("主机名:" + url.getHost());
        System.out.println("路径:" + url.getPath());//端口号后、参数前的内容
        //若blog.csdn.net:443则返回433(加了端口号),否则返回-1
        System.out.println("端口:" + url.getPort());
        System.out.println("协议:" + url.getProtocol());
        System.out.println("参数部分:" + url.getQuery());
        URL url1 = new URL("https://blog.csdn.net/");//相对路径构建URL对象
        URL url2 = new URL(url1 , "m0_45240384");
        System.out.println(url2.toString());
    }
}//输出如下
获取与此URL关联的协议的默认端口:443
端口号后面的内容:/md?articleId=107335888
主机名:editor.csdn.net
路径:/md
端口:-1
协议:https
参数部分:articleId=107335888
https://blog.csdn.net/m0_45240384

接下来实现一个简单的爬虫:

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;

public class Study{
     
    public static void main(String[] args) throws MalformedURLException {
     
        BasicSpider();
    }
    static void BasicSpider(){
     
        URL url = null;
        InputStream is = null;
        OutputStream os = null;
        BufferedReader br = null;
        BufferedWriter bw = null;
        //StringBuilder sb = new StringBuilder();
        String temp = "";
        try {
     
            url = new URL("https://blog.csdn.net/m0_45240384/article/details/107077506");
            is = url.openStream();
            br = new BufferedReader(new InputStreamReader(is));
            os = new FileOutputStream("study.txt");
            bw = new BufferedWriter(new OutputStreamWriter(os));
            while ((temp = br.readLine()) != null){
     
                bw.write(temp);
                br.readLine();
            }
            //System.out.println(sb);
        }catch (MalformedURLException e){
     
            e.printStackTrace();
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            try {
     
                bw.close();
            }catch (IOException e){
     
                e.printStackTrace();
            }try {
     
                os.close();
            }catch (IOException e){
     
                e.printStackTrace();
            }try{
     
                br.close();
            }catch (IOException e){
     
                e.printStackTrace();
            }try {
     
                is.close();
            }catch (IOException e){
     
                e.printStackTrace();
            }
        }
    }
}

TCP通信的实现

TCP协议是面向连接的,在通信是客户端与服务器必须建立连接。在网络通信中,第一次主动发起通信的程序被称作客户端(Client)程序,简称客户端;而在第一次通信中等待连接的程序被称作为服务器端(Server)程序,简称服务器。一旦通信建立,则客户端和服务器端完全一样,没有本质区别。
“请求-响应”模式
在“请求-响应”模式中,Socket类用于发送TCP消息; ServerSocket类用于创建服务器。
套接字Socket是一种进程间的数据交换机制。这些进程既可以在同一机器上,也可以在通过网络连接的不同机器上。换句话说,套接字起到了通信端点的作用。单个套接字是一个端点,而一对套接字则构成一个双向通信信道,使非关联进程可以在本地或通过网络进行数据交换。一旦建立套接字连接,数据即可在相同或不同的系统中双向或单向发送,直到其中一个端点关闭连接。套接字与主机地址和端口地址相关联。主机地址就是客户端或服务器程序所在主机的IP地址。端口地址是指客户端或服务器程序使用的主机的通信端口。
在客户端和服务器中,分别创建独立的Socket,并通过Socket的属性将两个Socket进行连接,这样,客户端和服务器通过套接字所建立的连接即可使用输入/输出流进行通信。
TCP/IP套接字是最可靠的双向流协议,使用TCP/IP可以发送任意数量的数据。
实际上,套接字只是计算机上已编号的端口。如果发送方和接收方计算机确定好端口,它们之间就可以进行通信了。
Java学习之网络编程实现_第1张图片
TCP/IP通信连接的简单过程
TCP/IP通信连接过程是:位于A计算机上的TCP/IP软件向B计算机发送包含端口号的消息; B计算机的TCP/IP软件接收该消息并进行检查,查看是否有它知道的程序正在该端口上接收消息。如果有,它将该消息交给这个程序。
要使程序有效地运行,就必须有- -个客户端和一个服务器。
通过Socket的编程顺序
顺序如下:
1)创建服务器ServerSocket。在创建时,定义ServerSocket监听端口(用来接收客户端发来的消息)
2)ServerSocket调用accept()方法,使之处于阻塞状态
3)创建客户端Socket,并设服务器的IP地址以及端口
4)客户端发出连接请求,建立连接
5)分别取得服务器和客户端Socket的InputStream和OutputSteam
6)利用Socket和ServerSocket进行数据传输
7)关闭流以及Socket
TCP–单向通信Socket服务器端

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class BasicSocketServer {
     
    public static void main(String[] args) {
     
        Socket socket = null;
        BufferedWriter bw = null;
        try{
     
            //创建服务器端套接字->指定监听端口
            ServerSocket serverSocket = new ServerSocket(888);
            System.out.println("服务器建立监听");
            socket = serverSocket.accept();//监听、等待客户端请求,并愿意接受连接
            //获取socket的输出流,并使用缓冲流进行包装
            bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            //向客户端发送反馈信息
            bw.write("芜湖起飞!");
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(bw != null){
     
                try {
     
                    bw.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if (socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}

TCP–单向通信Socket客户端

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.Socket;

public class BasicSockedClient {
     
    public static void main(String[] args) {
     
        Socket socket = null;
        BufferedReader br = null;
        try {
     
            //创建Socket对象,指定要连接的服务器的IP地址和端口而不是自己机器的端口,发送端口是随机的
            socket = new Socket(InetAddress.getLocalHost(), 888);
            //获取socket的输入流,使用缓冲流包装
            br = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //接受服务器端发送的信息
            System.out.println(br.readLine());
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(br != null) {
     
                try {
     
                    br.close();
                } catch (IOException e) {
     
                    e.printStackTrace();
                }
            }if (socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}

运行第一个程序后运行第二个程序,输出如下
在这里插入图片描述在这里插入图片描述
TCP–双向通信Socket服务器

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
     
    public static void main(String[] args) {
     
        Socket socket = null;
        BufferedReader read = null;
        BufferedWriter write = null;
        BufferedReader to = null;
        try {
     
            ServerSocket serverSocket = new ServerSocket(888);
            socket = serverSocket.accept();
            read = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            write = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            to = new BufferedReader(new InputStreamReader(System.in));
            while (true){
     
                String message = read.readLine();
                System.out.println("客户:" + message);
                String tomessage = "";
                if(message.equals("再见"))
                    break;
                tomessage = to.readLine();
                write.write(tomessage + "\n");
                write.flush();
            }
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(read != null){
     
                try {
     
                    read.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(write != null){
     
                try {
     
                    write.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(to != null){
     
                try {
     
                    to.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}

TCP–双向通信Socket客户端

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class SockedClient {
     
    public static void main(String[] args) {
     
        Socket socket = null;
        BufferedReader read = null;
        BufferedWriter write = null;
        BufferedReader to = null;
        try {
     
            socket = new Socket(InetAddress.getLocalHost(), 888);
            read = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            write = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
            to = new BufferedReader(new InputStreamReader(System.in));
            while (true){
     
                String tomessage = to.readLine();
                write.write(tomessage + "\n");
                write.flush();
                if(tomessage.equals("再见"))
                    break;
                System.out.println("客服:" + read.readLine());
            }
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(read != null){
     
                try {
     
                    read.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(write != null){
     
                try {
     
                    write.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(to != null){
     
                try {
     
                    to.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}

示例如下:
Java学习之网络编程实现_第2张图片
Java学习之网络编程实现_第3张图片
上述代码只能一问一答,不够灵活,使用多线程可以实现更加灵活的双向通信。使用多线程技术,可以让一个线程发送消息,一个线程接收消息。实现如下:
服务器端

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketServer {
     
    public static void main(String[] args) {
     
        Socket socket = null;
        BufferedReader reader = null;
        try {
     
            ServerSocket serverSocket = new ServerSocket(999);
            socket = serverSocket.accept();
            new Thread(new ServerThread(socket)).start();
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while(true){
     
                String message = reader.readLine();
                System.out.println("旭旭宝宝:" + message);
            }
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(reader != null){
     
                try {
     
                    reader.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}
class ServerThread implements Runnable{
     
    Socket socket = null;
    BufferedReader reader = null;
    BufferedWriter writer = null;
    public ServerThread(Socket socket){
     
        this.socket = socket;
        try {
     
            reader = new BufferedReader(new InputStreamReader(System.in));
            writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        }catch (IOException e){
     
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
     
        try{
     
            while(true){
     
                String message = reader.readLine();
                writer.write(message + "\n");
                writer.flush();
            }
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(writer != null){
     
                try {
     
                    writer.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(reader != null){
     
                try {
     
                    reader.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}

客户端

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

public class SockedClient {
     
    public static void main(String[] args) {
     
        Socket socket = null;
        BufferedReader reader = null;
        try {
     
            socket = new Socket(InetAddress.getByName("127.0.0.1"), 999);
            new Thread(new ClientThread(socket)).start();
            reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            while(true){
     
                System.out.println("大斌子:" + reader.readLine());
            }
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(reader != null){
     
                try {
     
                    reader.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}
class ClientThread implements Runnable{
     
    Socket socket = null;
    BufferedReader reader = null;
    BufferedWriter writer = null;
    public ClientThread(Socket socket){
     
        this.socket = socket;
        try{
     
            reader = new BufferedReader(new InputStreamReader(System.in));
            writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
        }catch (IOException e){
     
            e.printStackTrace();
        }
    }

    @Override
    public void run() {
     
        try {
     
            while (true){
     
                String message = reader.readLine();
                writer.write(message + "\n");
                writer.flush();
            }
        }catch (IOException e){
     
            e.printStackTrace();
        }finally {
     
            if(writer != null){
     
                try {
     
                    writer.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(reader != null){
     
                try {
     
                    reader.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }if(socket != null){
     
                try {
     
                    socket.close();
                }catch (IOException e){
     
                    e.printStackTrace();
                }
            }
        }
    }
}

示例输出如下(滑稽):
Java学习之网络编程实现_第4张图片
Java学习之网络编程实现_第5张图片


UDP通信的实现

UDP协议是面向无连接的,双方不需要建立连接就可通信。UDP通信所发送的数据通常需要进行封包操作(使用DatagramPacket类),然后才能接受或者发送(使用DatagramSocket类)。
DatagramPacket:数据容器(封包)
DatagramPacket类表示数据报包。数据报包用来实现封包功能,其常用方法如下:

  • DatagramPacket(byte[] buf, int length):构造数据报包,用来接收长度为length的数据包
  • DatagramPacket(byte[] buf, int length, InetAddress address, int port):构造数据报包,用来将长度为length的包发送到指定主机上的指定端口号
  • getAddress():获取发送或接受方计算机的IP地址,此数据报将要发往该机器或者是从该机器接收到的
  • getData():获取发送或接收的数据
  • setData(byte[] buf):设置发送的数据

DatagramSocket:用于发送或接受数据报包
当服务器要向客户端发送数据时,需要在服务器端产生一个DatagramSocket对象,在客户端产生一个DatagramSocket对象。服务器的DatagramSocket将DatagramPacket发送到网络上,然后被客户端的DatagramSocket接受。
DatagramSocket有两种常用的构造器,一种无参,常用于客户端,另一种需要指定端口,常用于服务器:

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

常用方法如下:

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

UDP通信编程基本步骤
1)创建客户端的DatagramSocket。创建的时候,定义客户端的监听端口
2)创建服务器端的DatagramSocket。创建时,定义服务器端的监听接口
3)在服务器端定义DatagramPacket对象,封装待发送的数据包
4)客户端将数据报包发送出去
5)服务器端接受数据报包

UDP单向通信服务器端

import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
     
    public static void main(String[] args) throws Exception{
     
        DatagramSocket ds = new DatagramSocket(888);
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b, b.length);
        ds.receive(dp);
        String message = new String(dp.getData(), 0 , dp.getLength());
        System.out.println(message);
        ds.close();
    }
}

UDP单向通信客户端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class Client {
     
    public static void main(String[] args) throws Exception{
     
        byte[] b = "UDP单向通信".getBytes();
        DatagramPacket dp = new DatagramPacket(b, b.length, new InetSocketAddress("127.0.0.1", 888));
        DatagramSocket ds = new DatagramSocket(889);
        ds.send(dp);
        ds.close();
    }
}

通过字节数组流ByteArrayInputStream、ByteArrayOutputStream与数据流DataInputStream、DataOutputStream联合使用可以传递基本数据类型。
服务器端

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
     
    public static void main(String[] args) throws Exception{
     
        DatagramSocket ds = new DatagramSocket(857);
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b, b.length);
        ds.receive(dp);
        DataInputStream dis = new DataInputStream(new ByteArrayInputStream(dp.getData()));
        System.out.println(dis.readLong());
        dis.close();
        ds.close();
    }
}

客户端

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class Client {
     
    public static void main(String[] args) throws Exception{
     
        long n = 20000000000000L;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(bos);
        dos.writeLong(n);
        byte[] b = bos.toByteArray();
        DatagramPacket dp = new DatagramPacket(b, b.length, new InetSocketAddress("127.0.0.1", 857));
        DatagramSocket ds = new DatagramSocket(858);
        ds.send(dp);
        dos.close();
        bos.close();
        ds.close();
    }
}

输出为20000000000000


通过字节数组流ByteArrayInputStream、ByteArrayOutputStream与数据流ObjectInputStream、ObjectOutputStream联合使用可以传递对象类型。
服务器端

import java.io.ByteArrayInputStream;
import java.io.ObjectInputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

public class Server {
     
    public static void main(String[] args) throws Exception{
     
        DatagramSocket ds = new DatagramSocket(857);
        byte[] b = new byte[1024];
        DatagramPacket dp = new DatagramPacket(b, b.length);
        ds.receive(dp);
        ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(dp.getData()));
        System.out.println(ois.readObject());
        ois.close();
        ds.close();
    }
}

客户端

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;

public class Client {
     
    public static void main(String[] args) throws Exception{
     
        Person p = new Person("aabb", 18);
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(p);
        byte[] b = bos.toByteArray();
        DatagramPacket dp = new DatagramPacket(b, b.length, new InetSocketAddress("127.0.0.1", 857));
        DatagramSocket ds = new DatagramSocket(858);
        ds.send(dp);
        oos.close();
        bos.close();
        ds.close();
    }
}
class Person implements Serializable{
     
    private static final long serialVersionUID = 1L;
    String name;
    int age;
    public Person(String name, int age){
     
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
     
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

输出为Person{name=‘aabb’, age=18}

你可能感兴趣的:(Java学习笔记)