【IO 流】IO 流与网络编程

1. 网络编程基础

什么叫网络编程?

直接或间接地通过网络协议与其它计算机实现数据交换,进行通讯,这就叫网络编程

但在交互过程中,会有以下两个问题:

  1. 如何准确地定位网络上一台或多台主机:定位主机上的特定的应用(IP + 端口)
  2. 找到主机后,如何可靠、高效地进行数据传输(网络通信协议)

当然,以上两个问题都已经有了相应的解决方案了。

IP

IP:唯一的标识 Internet 上的计算机

端口

端口被规定为一个16位的整数:0~65535。在同一主机中,不同的进程有不同的端口。

端口被分为:

  • 公认端口:0~1023。被预先定义的服务通信占用(如:HTTP 占用 80 端口、FTP 占用 21 端口)
  • 注册端口:1024~49151。分配给用户进程或应用程序(如:Tomcat 占用 8080 端口、Mysql 占用 3306 端口)
  • 动态/私有端口:49152~65535

所以,Socket = IP + 端口

网络通信协议

网络协议太复杂,所以,将通信协议进行分层。由上至下为:应用层、传输层(TCP、UDP)、网络层(IP)、数据链路层、物理层

TPC 特点:

  1. 使用 TCP 协议前,必须先建立 TCP 连接,形成传输数据通道
  2. 传输前,采用“三次握手”方式,点对点通信,是可靠传输
  3. TCP 协议进行通信的两个应用进程:客户端、服务端
  4. 在连接中,可进行大数据量的传输
  5. 传输完毕,需要释放已建立的连接(效率低)

UDP 特点:

  1. 将数据、源、目的封装成数据包,不需要建立连接
  2. 每个数据包的大小限制在 64k 内
  3. 发送不管对方是否准备好,接收方收到也不确认,不可靠传输
  4. 可以广播发送
  5. 发送数据结束时,无需释放资源(开销小、速度快)

2. 网络编程示例

2.1 TCP 协议

场景一:客户端通过 TCP 协议向服务端发送数据,服务端接收后,将收到的数据打印到控制台中,并指明来自于哪个客户端

public class TCPServer {

    public static void main(String[] args) throws Exception{
        // 指明需要监听的端口
        ServerSocket ss = new ServerSocket(1234);
        // 监听来自客户端的 Socket 请求
        Socket socket = ss.accept();
		// 获取 Socket 对象的输入流
        InputStream is = socket.getInputStream();

        // 如果客户端传来的是汉字(三个字节编码),使用字节流读取可能会存在乱码
        /*byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = is.read(bytes)) != -1) {
            // 当把一个汉字劈成两半,再还原为字符串时就会乱码
            System.out.print(new String(bytes, 0 ,len));
        }*/

        // 创建一个字节数据输出流
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[5];
        int len = 0;
        // 读取输入流中的数据
        while ((len = is.read(buffer)) != -1) {
            baos.write(buffer, 0 ,len);
        }
        System.out.println(baos.toString());
        System.out.println("收到了来自于:" + socket.getInetAddress().getHostAddress() + "的数据");

        baos.close();
        is.close();
        socket.close();
        ss.close();
    }
}
public class TCPClient {

    public static void main(String[] args) throws Exception{
        // 创建 Socket 对象,指明服务器的 ip 和端口
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 1234);
        // 通过 Socket 对象获取它的输出流
        OutputStream os = socket.getOutputStream();
        String data = "您好,我是客户端 GG";
        // 向服务器发送数据
        os.write(data.getBytes());

        os.close();
        socket.close();
    }
}

场景二:客户端将文件发送给服务端,服务端将文件保存起来

public class TCPServer2 {

    public static void main(String[] args) throws Exception{
        ServerSocket ss = new ServerSocket(1234);
        Socket socket = ss.accept();

        InputStream is = socket.getInputStream();
        FileOutputStream fos = new FileOutputStream(new File("2.jpg"));
        byte[] bytes = new byte[1024];
        int len = 0;

        while ((len = is.read(bytes)) != -1) {
            fos.write(bytes, 0 ,len);
        }

        fos.close();
        is.close();
        socket.close();
        ss.close();
    }
}
public class TCPClient2 {

    public static void main(String[] args) throws Exception{
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 1234);
        OutputStream os = socket.getOutputStream();

        FileInputStream fis = new FileInputStream(new File("1.jpg"));
        byte[] bytes = new byte[1024];
        int len = 0;
        while ((len = fis.read(bytes)) != -1) {
            os.write(bytes, 0, len);
        }

        fis.close();
        os.close();
        socket.close();
    }
}

场景三:客户端将文件发送给服务端,服务端将文件保存起来。并且,服务端需要返回“发送成功”给客户端,然后关闭相应连接

public class TCPServer3 {

    public static void main(String[] args) throws Exception{
        ServerSocket ss = new ServerSocket(1234);
        Socket socket = ss.accept();

        InputStream is = socket.getInputStream();
        FileOutputStream fos = new FileOutputStream(new File("2.jpg"));
        byte[] bytes = new byte[1024];
        int len = 0;

        while ((len = is.read(bytes)) != -1) {
            fos.write(bytes, 0 ,len);
        }

        // 服务端给予客户端反馈
        OutputStream os = socket.getOutputStream();
        String data = "发送成功";
        os.write(data.getBytes());

        fos.close();
        is.close();
        os.close();
        socket.close();
        ss.close();
    }
}
public class TCPClient3 {

    public static void main(String[] args) throws Exception{
        Socket socket = new Socket(InetAddress.getByName("127.0.0.1"), 1234);
        OutputStream os = socket.getOutputStream();

        FileInputStream fis = new FileInputStream(new File("1.jpg"));
        byte[] bytes = new byte[1024];
        int len = 0;

        // read() 方法是一个阻塞方法,没有明确指出传输完毕,就会一直阻塞
        while ((len = fis.read(bytes)) != -1) {
            os.write(bytes, 0, len);
        }

        // 给出明确指示(传输完毕)
        socket.shutdownOutput();

        // 客户端接收服务端传送过来的数据
        InputStream is = socket.getInputStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buffer = new byte[20];
        int length = 0;

        while ((length = is.read(buffer)) != -1) {
            baos.write(buffer, 0, length);
        }
        System.out.println(baos.toString());

        fis.close();
        os.close();
        baos.close();
        socket.close();
    }
}

2.2 UDP 协议

public class UDPReceiver {

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket(1234);

        byte[] buffer = new byte[100];
        DatagramPacket packet = new DatagramPacket(buffer, 0, buffer.length);
        socket.receive(packet);
        System.out.println(new String(packet.getData(), 0, packet.getLength()));

        socket.close();
    }
}
public class UDPSender {

    public static void main(String[] args) throws Exception {
        DatagramSocket socket = new DatagramSocket();

        // 封装一个数据包(所有信息都在数据包中)
        String msg = "我是 UDP 发送方式的数据";
        byte[] data = msg.getBytes();
        DatagramPacket packet = new DatagramPacket(data, 0, data.length, InetAddress.getByName("127.0.0.1"), 1234);

        socket.send(packet);
        socket.close();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值