每日学习打卡:Java网络编程

网络编程

概述

网络编程三要素:IP地址、端口号、协议

InetAddress类:为了方便我们对ip地址的获取和操作,Java提供了一个InetAddress类供我们使用

  • static InetAddress getByName(String host) 确定主机名称的ip地址,主机名称可以是机器名称或ip地址
  • String getHostName() 获取此ip地址的主机名
  • String getHostAddress() 返回文本显示中的ip地址字符串
import java.net.InetAddress;
import java.net.UnknownHostException;

/**
 * @author: 小码农
 * @create: 2021-08-05 16:33
 **/
public class Demo8 {
    public static void main(String[] args) {
        //InetAddress类
        try {
            InetAddress address = InetAddress.getByName("192.168.249.67");
            String hostName = address.getHostName();
            String ipAddress = address.getHostAddress();
            System.out.println("主机名:"+hostName);
            System.out.println("ip地址:"+ipAddress);
        } catch (UnknownHostException e) {
            e.printStackTrace();
        }
    }
}
/*
    主机名:DESKTOP-7CFI8Q7
    ip地址:192.168.249.67
*/

端口:设备上应用程序的唯一标识

端口号:用两个字节表示的整数,取值范围065535。其中01023用于一些知名的网络服务。普通应用程序使用1024~65535之间的端口号。如果端口号被另外一个服务占用,会导致当前程序启动失败

TCP协议:可靠,三次握手

  • 客户端向服务器端发送连接请求,等待服务器确认
  • 服务器端向客户端回复一个响应,通知客户端收到了连接请求
  • 客户端再次向服务器端发送确认信息,确认连接

UDP协议:不可靠传输,它在通信两端各建立一个Socket对象。Java提供了DatagramSocket类作为UDP协议的Socket

UDP

UDP发送数据

步骤:

  • 使用DatagramSocket创建发送端对象,发送端对象不用带端口号参数

    DatagramSocket ds = new DatagramSocket();
    
  • 构建存放发送数据的字节数组

    byte[] data = new byte[1024];
    
  • 使用DatagramPacket创建数据包对象,参数包括:数据,数据长度,InetAddress主机对象,端口号

    DatagramPacket dp = new DatagramPacket(data,data.length,InetAddress.getByName("192.168.249.67"),10086);
    
  • 调用DatagramSocket对象的send方法发送数据,参数为数据包对象

    ds.send(dp);
    
  • 关闭发送端

    ds.close();
    

DatagramSocket类

DatagramPacket(byte[] b,int len,InetAddress add,int port)

构造一个数据包,发送长度为length的数据包到指定主机上的指定端口号

import java.io.IOException;
import java.net.*;

/**UDP发送端
 * @author: 小码农
 * @create: 2021-08-05 17:12
 **/
public class Demo9 {
    //创建Socket对象
    DatagramSocket ds;
    {
        try {
            ds = new DatagramSocket();
            //创建数据
            byte[] bytes = "Hello World".getBytes();
            //调用send方法发送数据
            DatagramPacket dp = new DatagramPacket(bytes,bytes.length,InetAddress.getByName("192.168.249.67"),10086);
            ds.send(dp);
            //关闭发送端
            ds.close();
        } catch (SocketException e) {
            e.printStackTrace();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
UDP接收数据

步骤:

  • 创建接收端的Socket对象(DatagramSocket),UDP接收端的Socket对象需要传入端口号参数

    DatagramSocket ds = new DatagramSocket(10086);
    
  • 创建一个字节数组,用于接收数据

    byte[] bytes = new byte[1024];
    
  • 调用DatagramSocket对象的方法并接收数据,构建DatagramPacket对象传入参数:容器,容器长度

    DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
    ds.receive(dp);
    
  • 解析数据包,并把数据包在控制台显示

    String str = new String(dp.getData(),0,dp.getLength());
    System.out.println("接收到的数据:"+str);
    
  • 关闭接收端

    ds.close();
    
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author: 小码农
 * @create: 2021-08-05 17:24
 **/
public class Demo10 {
    public static void main(String[] args) throws IOException {
        //创建接收端对象
        DatagramSocket ds = new DatagramSocket(10086);
        byte[] bytes = new byte[1024];
        //创建数据包
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length);
        //接收数据
        ds.receive(dp);
        //解析数据包,得到接收到的整体的数据包,有可能包含空字符
//        byte[] bytes1 = dp.getData();
        //使用getLength方法的到接受到的数据长度
        String str = new String(dp.getData(),0,dp.getLength());
        System.out.println("接收到的数据:"+str);
        //关闭接收端
        ds.close();
    }
}

练习:UDP通信程序

UDP发送数据:数据来自于键盘录入,知道输入的数据是886,发送数据结束

UDP接收数据:因为接收端不知道发送端什么时候停止发送,故采用死循环接收

TCP

TCP通信原理

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象,从而在通信的两端形成网络虚拟链路,一旦建立了虚拟的网络链路,两端的程序就可以铜鼓哦虚拟链路进行通信

TCP发送数据

发送数据步骤:

  • 创建客户端的Socket对象(Socket)
Socket socket = new Socket(InetAddress.getByName("192.168.249.67"),10010);
Socket socket2 = new Socket("192.168.249.67",10010);//参数一可以直接使用接收方IP地址
  • 获取输入流,写数据
//获取输出流,写数据
OutputStream os = socket.getOutputStream();
byte[] bytes = "Hello World".getBytes();
os.write(bytes);
  • 释放资源
//释放资源
socket.close();
import java.io.IOException;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * @author: 小码农
 * @create: 2021-08-05 19:43
 **/
public class Demo_TCP_Send {
    public static void main(String[] args) throws IOException {
        //构造方法1 Socket(主机名,端口)
        Socket socket = new Socket(InetAddress.getByName("192.168.249.67"),10010);
        //构造方法2 Socket(IP,端口)
        Socket socket2 = new Socket("192.168.249.67",10010);

        //获取输出流,写数据
        OutputStream os = socket.getOutputStream();

        byte[] bytes = "Hello World".getBytes();
        os.write(bytes);

        //释放资源
        socket.close();
        socket2.close();
    }
}
TCP接收数据

接收数据步骤:

  • 创建服务器端的Socket对象(ServerSocket)
//创建服务器端ServerSocket 构造方法:ServerSocket(端口)
ServerSocket ss = new ServerSocket(10010);
  • 监听客户端连接,返回一个Socket对象
//Socket accept()监听要连接到此套接字并接受它
Socket s = ss.accept();
  • 获取输入流,读数据,并输出
//获取输入流,读数据,并把数据显示在控制台
InputStream is = s.getInputStream();
byte[] bytes = new byte[1024];
int len = is.read(bytes);
String str = new String(bytes,0,len);
System.out.println("接收数据:"+str);
  • 释放资源
ss.close();
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author: 小码农
 * @create: 2021-08-05 19:51
 **/
public class Demo_TCP_receive {
    public static void main(String[] args) throws IOException {
        //创建服务器端ServerSocket 构造方法:ServerSocket(端口)
        ServerSocket ss = new ServerSocket(10010);

        //Socket accept()监听要连接到此套接字并接受它
        Socket s = ss.accept();
        //获取输入流,读数据,并把数据显示在控制台
        InputStream is = s.getInputStream();
        byte[] bytes = new byte[1024];
        int len = is.read(bytes);
        String str = new String(bytes,0,len);
        System.out.println("接收数据:"+str);
        //释放资源
        s.close();
        ss.close();
    }
}

中断输入输出流的方法:

中断输出流:Socket对象.shutdownOutput();

中断输入流:Socket对象.shutdownInput();

练习1:

  • 客户端:发送数据,接收服务器反馈。先写数据,再读数据
  • 服务器:接收数据,发送反馈。先读数据,再写数据

客户端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;


/**
 * 客户端程序
 * @author: 小码农
 * @create: 2021-08-05 20:06
 **/
public class Demo12_Send {
    public static void main(String[] args) throws IOException {
        //创建客户端Socket对象
        Socket s = new Socket("192.168.249.67",10101);
        //获取输入流,写数据
        OutputStream os = s.getOutputStream();
        os.write("来自客户端的一条消息".getBytes());
        //接收服务器端反馈
        InputStream is = s.getInputStream();
        byte[] b = new byte[1024];
        int len = is.read(b);
        String str = new String(b,0,len);
        System.out.println("服务端反馈:"+str);
        //释放资源
        s.close();
    }
}

服务器端

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;


/**
 * 服务器端程序
 * @author: 小码农
 * @create: 2021-08-05 20:06
 **/
public class Demo12_Receive {
    public static void main(String[] args) throws IOException {
        //创建服务器端ServerSocket对象
        ServerSocket ss = new ServerSocket(10101);
        //监听客户端连接,返回一个Socket对象
        Socket s = ss.accept();
        //接收数据
        InputStream is = s.getInputStream();
        byte[] b = new byte[1024];
        int len = is.read(b);
        String str = new String(b,0,len);
        System.out.println("接收数据:"+str);

        //向客户端发送反馈
        OutputStream os = s.getOutputStream();
        os.write("接收完成".getBytes());

        //释放资源
        ss.close();

    }
}

练习2:

  • 客户端:将键盘数据数据发送到服务端,输入886时停止
  • 服务器:将接收到的数据打印在控制台

客户端

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

/**
 * @author: 小码农
 * @create: 2021-08-05 20:19
 **/
public class Demo13_send {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("192.168.249.67",10110);
        //数据来自键盘录入
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        //封装输出流对象,利用转换流OSW将获取的输入字节流,转化为字符输出流
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String str;
        while ((str = br.readLine())!=null){
            if (str.equals("886")){
                break;
            }
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
        s.close();
    }
}

服务器端

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

/**
 * @author: 小码农
 * @create: 2021-08-05 20:19
 **/
public class Demo13_receive {
    public static void main(String[] args) throws IOException {
        //创建服务器端ServerSocket对象
        ServerSocket ss = new ServerSocket(10110);
        //监听客户端连接,返回一个对应的Socket对象
        Socket s = ss.accept();
        //使用字符输入流来读取数据,利用转换流ISR将输入的字节转化为字符
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str;
        while ((str=br.readLine())!=null){
            if (str.equals("886")){
                break;
            }
            System.out.println(str);
        }
        ss.close();
    }
}

练习3:

  • 客户端:将键盘数据数据发送到服务端,输入886时停止
  • 服务器:将接收到的数据写入文本文件

客户端

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

/**
 * @author: 小码农
 * @create: 2021-08-05 20:42
 **/
public class Demo14_send {
    public static void main(String[] args) throws IOException {
        //第一步,创建Socket对象
        Socket s = new Socket("192.168.249.67",10110);
        //创建字符输出流对象
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

        String str;
        while ((str=br.readLine())!=null){
            if (str.equals("886")){
                break;
            }
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
        s.close();

    }
}

服务器端

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

/**
 * @author: 小码农
 * @create: 2021-08-05 20:46
 **/
public class Demo14_receive {
    public static void main(String[] args) throws IOException {
        //创建ServerSocket对象
        ServerSocket ss = new ServerSocket(10110);
        //创建监听对象Socket
        Socket s = ss.accept();
        //创建File对象
        BufferedWriter bw = new BufferedWriter(new FileWriter("data.txt",true));
        //创建字符输入流对象
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str;
        while((str=br.readLine())!=null){
            if (str.equals("886")){
                break;
            }
            System.out.println("写入:"+str);
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
        bw.close();
        ss.close();
    }
}

练习4:

  • 客户端:将文本文件数据发送到服务端
  • 服务器:将接收到的数据写入文本文件

在本练习中,服务端与练习3服务端相同,客户端不同

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

/**
 * @author: 小码农
 * @create: 2021-08-05 21:00
 **/
public class Demo15 {
    public static void main(String[] args) throws IOException {
        //第一步,创建Socket对象
        Socket s = new Socket("192.168.249.67",10110);
        //创建字符输出流对象
        BufferedReader br = new BufferedReader(new FileReader("data2.txt"));
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));

        String str;
        while ((str=br.readLine())!=null){
            bw.write(str);
            bw.newLine();
            bw.flush();
        }
        s.close();
    }
}

练习5

  • 客户端:数据来自于文本文件,接收服务器反馈
  • 服务器:接收到的数据写入文本文件,给出反馈

客户端

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

/**
 * @author: 小码农
 * @create: 2021-08-05 21:08
 **/
public class Demo16_Client {
    public static void main(String[] args) throws IOException {
        //创建Socket对象
        Socket s = new Socket("192.168.249.67",10111);

        //创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("data2.txt"));
        //创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        //创建输入流对象2,来接收服务器端的反馈
        BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str;
        String str2;
        while ((str=br.readLine())!=null){
            bw.write(str);
            bw.newLine();
            bw.flush();
        }

        //中断输出流
        s.shutdownOutput();
        //接收服务器反馈
        str2 = br2.readLine();
        System.out.println(str2);
        //关闭资源
        bw.close();
        br.close();
        s.close();
    }
}

服务器端

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

/**
 * @author: 小码农
 * @create: 2021-08-05 21:08
 **/
public class Demo16_Server {
    public static void main(String[] args) throws IOException {
        //创建ServerSocket对象
        ServerSocket ss = new ServerSocket(10111);
        //创建监听器
        Socket s = ss.accept();

        //创建字符输入流对象
        BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
        //创建BufferedWriter2 用于将收到的数据写入文件
        BufferedWriter bw2= new BufferedWriter(new FileWriter("data.txt",true));
        //创建字符输出流对象,用于向客户端发送反馈信息
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        String str;
        while ((str=br.readLine())!=null){
            bw2.write(str);
            bw2.newLine();
            bw2.flush();
        }

        //给客户端反馈
        bw.write("已写入");
        bw.newLine();
        bw.flush();
        //关闭资源
        bw.close();
        bw2.close();
        ss.close();
    }
}

练习6

  • 客户端:数据来自于文本文件,接收服务器反馈
  • 服务器:接收到的数据写入文本文件,给出反馈。代码用线程进行封装,为每个客户端开启一个线程

ServerThread线程类

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

/**
 * @author: 小码农
 * @create: 2021-08-05 21:41
 **/
public class ServerThread implements Runnable {
    private Socket s;
    public ServerThread(Socket s){
        this.s=s;
    }
    @Override
    public void run() {
        //接收数据写到文本文件
        BufferedReader br = null;
        BufferedWriter bw = null;
        BufferedWriter bw2 = null;
        try {
            br = new BufferedReader(new InputStreamReader(s.getInputStream()));
            //为了避免文件名重复,我们使用动态文件名的方式来构建目标文件名
            int cut = 0;
            File file = new File("data-"+cut+".txt");
            //如果文件存在,则进入循环,找到一个不存在的文件名后离开循环
            while (file.exists()){
                cut++;
                file = new File("data-"+cut+".txt");
            }
            bw = new BufferedWriter(new FileWriter(file));
            String str;
            while ((str=br.readLine())!=null){
                bw.write(str);
                bw.newLine();
                bw.flush();
            }
            //给出反馈
            bw2 = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
            bw2.write("文件上传成功");
            bw2.newLine();
            bw2.flush();
            //释放资源
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (br!=null){
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bw!=null){
                try {
                    bw.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bw2!=null){
                try {
                    bw2.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

服务端

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

/**
 * @author: 小码农
 * @create: 2021-08-05 21:38
 **/
public class Demo17_Server {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(10111);
        while(true){
            //监听客户端连接,返回一个对应的Socket对象
            Socket s = ss.accept();
            //为每一个客户端开启一个线程
            new Thread(new ServerThread(s)).start();
        }
    }
}

客户端(可以多个)

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

/**
 * @author: 小码农
 * @create: 2021-08-05 21:38
 **/
public class Demo17_Client {
    public static void main(String[] args) throws IOException {
        //创建Socket对象
        Socket s = new Socket("192.168.249.67",10111);

        //创建字符输入流对象
        BufferedReader br = new BufferedReader(new FileReader("data2.txt"));
        //创建字符输出流对象
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
        //创建输入流对象2,来接收服务器端的反馈
        BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
        String str;
        String str2;
        while ((str=br.readLine())!=null){
            bw.write(str);
            bw.newLine();
            bw.flush();
        }

        //中断输出流
        s.shutdownOutput();
        //接收服务器反馈
        str2 = br2.readLine();
        System.out.println(str2);
        //关闭资源
        bw.close();
        br.close();
        s.close();
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值