Java网络编程--Lesson

发布时间 2023-11-29 23:04:21作者: 回忆也交给时间

一.InetAddress

此类是获取网络地址实例的一个类,但是不能通过new 来实例化这个类,因为它没有构造器,但是可以通过组合的方式来使用类中的方法

拿取主机为localhost的网络地址实例

InetAddress address=InetAddress.getByName("localhost");

 

拿取百度网络地址实例

//拿取主机为www.baidu.com的网络地址实例
InetAddress BaiDu=InetAddress.getByName("www.baidu.com");

 

通过地址实例拿取详细的地址信息

  • 拿取IP地址
//获得真实的IP地址
System.out.println(BaiDu.getCanonicalHostName());
  • 拿取主机名称
//获得地址的主机名 or 域名
System.out.println(BaiDu.getHostName());

 

二.InetSocketAddress

InetSocketAddress也是.net包下的一个类,它的作用是拿取主机的特定端口信息
如拿取百度的80端口信息:
//拿取百度的80端口信息
InetSocketAddress socketAddress = new InetSocketAddress("www.baidu.com", 80);
System.out.println(socketAddress);

 通过new关键字可以实例化InetSocketAddress类,从而通过此对象的方法继续拿到其它信息

  • 地址信息
//获取地址信息
System.out.println(socketAddress.getAddress());
  • 主机信息
//获取主机名称
System.out.println(socketAddress.getHostName());

 

  • 端口信息
//获取端口号
System.out.println(socketAddress.getPort());

 三.模拟使用

TCP实现文件上传

模拟两个角色,一个用户端,一个服务器端

用户端负责发送,服务器端负责接收,

  • 模拟用户端:

TCP连接需要的参数对方的IP地址和端口

//1.创建一个socket连接
Socket socket = new Socket(InetAddress.getByName("127.0.0.1"),5206);

 

建立连接以后需要读取文件再发送给服务器端

//2.创建一个文件输出流
OutputStream outs = socket.getOutputStream();
//3.读取文件
FileInputStream file = new FileInputStream(new File("kq.png"));

 

开始向服务器端写出数据

 

//4.写出文件
byte[] buffer = new byte[1024];
int len;
while ((len=file.read(buffer))!=
    outs.write(buffer,0,len);
}
//通知服务器已经完成了传输
socket.shutdownOutput();

 

等待服务器发送结束标志

//接收服务器端发送的结束标志
InputStream stream = socket.getInputS
ByteArrayOutputStream baos = new Byte
byte[] bytes = new byte[1024];
int len1;
while ((len1=stream.read(buffer))!=-1
    baos.write(buffer,0,len1);
}
System.out.println(baos.toString());

 

收到服务器发送的接收完成的标志,关闭客户端资源

//关闭资源
file.close();
baos.close();
outs.close();
socket.close();

 

  • 模拟服务器端

创建一个连接,并开启需要使用到的端口

//1.创建服务
ServerSocket serverSocket = new ServerSocket(5206);

 

阻塞式监听端口,直到有客户端发来连接

//2.监听用户端口
Socket accept = serverSocket.accept();

 

获取客户端发送的IO流文件

//3.获取输入流
InputStream io = accept.getInputStream();
//4.文件输出流
FileOutputStream file = new FileOutputStream(new File("刻晴.png"));

 

写出IO流文件内容

byte[] buffer = new byte[1024];
int len;
while ((len=io.read(buffer))!=-1){
    file.write(buffer,0,len);
}

 

写出完成后,向客户端发送读取完成标志,并关闭资源

//向客户端发送数据读取完成标志
OutputStream os = accept.getOutputStream();
os.write("我已经读取完成了".getBytes());
//关闭资源
file.close();
io.close();
accept.close();
serverSocket.close();

 

UDP实现信息发送

Udp和TCP传输的最大区别在于Udp是无连接的,它传送不像Tcp需要事先预告,而是直接发向目的地址

TCP的传输就好比打电话,在你呼叫的时候可以选择不接,也可以选择接,这就是连接,如果 想和对方通话,那么对方就必须接并且建立联系

UDP的传输就好比发送消息,你不能选择不接收,就算关机,也只是延迟收到,而发送方只管一键发送,并不在乎你是否收到

所以在下面的实现中,是没有连接的过程的,但是还是需要对方的地址和端口,这是目的地必须要知道,只是不需要链接了

  • 模拟客户端

建立一个socket对象用来发送报文

//1.建立一个socket,发送报文
DatagramSocket socket = new DatagramSocket();

 

发送方的信息及内容

//2.发送方信息即数据
String msg="i miss you";
InetAddress address =InetAddress.getByName("localhost");
int port=5206;

 

打包一个数据包

//3.数据包,数据,数据的长度起始,要发送给谁
DatagramPacket packet = new DatagramPacket(msg.getBytes(), 0, msg.getBytes().length, address, port);

 

发送包,完成,关流

//4.发送包
socket.send(packet);
//5.关闭流
socket.close();

 

 

  • 模拟服务器端

开放端口

//开放端口
DatagramSocket socket = new DatagramSocket(5206);

 

接收并展示数据包

//2.接收数据包
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
socket.receive(packet);//阻塞式接收
System.out.println(packet.getAddress());
System.out.println(new String(packet.getData(),0,packet.getLength()));

 

关闭连接

//3.关闭连接
socket.close();

模拟服务器端接收到的参数

 模拟连续对话

使用Udp发消息的基础上,在加上一个循环语句就是可以实现连续对话的

我们模拟的场景是,连续对话也就是一端既要接收数据,又要发送数据

那么我们就可以使用多线程编程,一个线程负责发送消息,一个线程负责接收消息

  • 搭建发送的线程类

多线程需要实现Runnable接口,并且重写Run方法

run方法

    @Override
    public void run() {
        int count=10;
        while (count>0){
            String data = null;
            //接收数据,控制台读入
            sysIn = new BufferedReader(new InputStreamReader(System.in));
            try {
                data = sysIn.readLine();
                byte[] dataBytes = data.getBytes();
                DatagramPacket packet = new DatagramPacket(dataBytes, 0, dataBytes.length, InetAddress.getByName(ToIP), ToPort);
                socket.send(packet);
                count--;
                if (data.equals("bye")){
                    break;
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        //关闭流
        socket.close();
    }

 

创立一个socket对象的代码被提升作用域到构造器中了

构造方法

public class UdpTalkSend implements  Runnable{
    DatagramSocket socket = null;
    BufferedReader sysIn = null;
    private int MyPort;
    private String ToIP;
    private int ToPort;

    public UdpTalkSend(int myPort, String toIP, int toPort) {
        this.MyPort = myPort;
        this.ToIP = toIP;
        this.ToPort = toPort;
        try {
            socket = new DatagramSocket(MyPort);
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public void run() {
    }
}

 

  • 搭建接收的线程

重写run方法

    @Override
    public void run() {
        int count=10;
        while (count>0){
            try {
                //准备接收数据包
                byte[] bytes = new byte[1024];
                packet = new DatagramPacket(bytes, 0, bytes.length);
                socket.receive(packet);
                String data = new String(packet.getData(), 0, packet.getLength());
                System.out.println(username+":"+data);
                count--;
                if (data.equals("bye")){
                    break;
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
        //关闭流
        socket.close();
    }

 

构造方法

public class UdpTalkReceive implements Runnable {
    DatagramSocket socket = null;
    DatagramPacket packet = null;
    private int ToPort;
    private String username;

    public UdpTalkReceive(int toPort, String username) {
        ToPort = toPort;
        this.username = username;
        try {
            socket = new DatagramSocket(ToPort);
        } catch (SocketException e) {
            throw new RuntimeException(e);
        }
    }
    @Override
    public void run() {
    }
}

 

模拟两个用户A和B

A:

public class UserClientA {
    public static void main(String[] args) {
        new Thread(new UdpTalkReceive(5202,"B")).start();
        new Thread(new UdpTalkSend(5203,"127.0.0.1",5201)).start();
    }
}

 

B:

public class UserClientB {
    public static void main(String[] args) {
        new Thread(new UdpTalkReceive(5201,"A")).start();
        new Thread(new UdpTalkSend(5204,"localhost",5202)).start();
    }
}

 

测试结果:

 四.使用java.net.URL类下载

我使用的是在网易云上下载了一首音乐下来

获取下载路径:

//得到url路径资源
URL url = new URL("https://m801.music.126.net/20231129230405/aabdfb2ffd40439ec5c68a80c11a0140/jdyyaac/obj/w5rDlsOJwrLDjj7CmsOj/14096410414/5dd8/3527/d0a8/2bc39cc62c984590b57fff0024c23780.m4a");

 

和URL地址创建连接

//创建连接
HttpURLConnection connection = (HttpURLConnection) url.openConnection();

 

下载也是IO流,所以创建一个流

//创建写入流
InputStream io = connection.getInputStream();
FileOutputStream file = new FileOutputStream(new File("世界美好.m4a"));

 

利用IO流将.m4a文件写入到本地

//开始写入
byte[] buffer = new byte[1024];
int len;
while ((len=io.read(buffer))!=-1){
    file.write(buffer,0,len); //写出数据
}

 

断开连接

//断开连接
file.close();
io.close();
connection.disconnect();

 

最后在本地会得到一个.m4a文件