软件结构、网络编程、InetAddress类、UDP协议、TCP协议

软件结构

C/S结构 :

全称为Client/Server结构,是指客户端和服务器结构。常见程序有QQ、迅雷等软件。

B/S结构 :

全称为Browser/Server结构,是指浏览器和服务器结构。常见浏览器有谷歌、火狐等。

两种架构各有优势,但是无论哪种架构,都离不开网络的支持。网络编程,就是在一定的协议下,实现两台计算机
的通信的程序。

网络编程

  • 网络编程就是Socket编程,Socket编程就是网络编程。

网络编程的三要素:

  • IP地址
  • 端口号
  • 协议

IP地址的作用:

  1. 网络设备的唯一标识。
  2. 通过IP地址可以找到对应的计算机。

IP的常用命令:

  • 查看本机IP地址,在控制台(cmd)输入:ipconfig
  • 检查网络是否连通,在控制台输入:ping  空格  IP地址 
  • 特殊的IP地址:本机IP地址: 127.0.0.1 、localhost 。

IP分类:IPV4和IPV8

IPV4格式:

  • xxx.xxx.xxx.xxx 由四段数字 组成,每段数字的取值范围是0到255,每一个IP地址有4个字节组成。

IPV6格式:

每一个IP地址由16个字节组成。

端口号的概述:

就是一个十进制的整数。

作用:

进程的唯一标识,每一个程序都会有一个端口号。

取值范围:

0 到 65535

注意事项:

  • 0 到 1023 的端口号是系统保留使用的,程序员要使用 1024 或 1024 以上的端口号。

协议作用:

用来规定计算机与计算机之间数据传输的格式。

协议的分类:

  1. UDP协议
  2. TCP协议

小结:

  • 通过IP找主机,通过端口号找程序,通过协议确定如何传输数据。

InetAddress类

InetAddress类概述:

一个该类的对象就代表一个IP地址。

InetAddress类静态方法:

static InetAddress getLocalHost()

  • 获得本地主机IP地址对象(获得自己的)。
  • 主机名 / IP地址字符串

static InetAddress getByName(String host)

  • 根据主机名或IP地址字符串获得IP地址对象 (获得别人的)。

InetAddress类成员方法:

String getHostName()

  • 获得主机名。

String getHostAddress()

  • 获得IP地址字符串。

UDP协议

UDP ==> User DatagramPacket Protocol ==> 用户数据报包协议

UDP协议的特点:

  1. 面向无连接协议。
  2. 只管发送,不确定对方是否收到。
  3. 基于数据包(报)传输数据 : 将要发送的数据,接受端IP地址,端口号等信息打包到一个数据包中发送。
  4. 传输数据大小限制在64k以内。
  5. 速度快,但不可靠(会出现数据丢失的情况)。

UDP协议的使用场景:

  1. 即时通讯(qq,微信,陌陌)。
  2. 在线视频。
  3. 网络语音电话

UDP协议通讯两个相关类:

DatagramPacket

  • 数据包对象。
  • 作用:用来封装要发送或接收的数据。
  • 比喻:集装箱。

​​​​​​​DatagramSocket

  • 发送或接收对象。
  • 作用:用来发送数据包或接收数据包。
  • 比喻:码头。

DatagramPacket类构造方法:

DatagramPacket(byte[] buf, int length, InetAddress address, int port)

  • 创建发送端的数据包对象。
  • buf:字节数组,用来封装要发送的数据。
  • length:要发送内容的长度 单位是:字节。
  • address:接收端的IP地址对象
  • port:接收端的端口号。

DatagramPacket(byte[] buf, int length)

  • 创建接收端的数据包对象。
  • buf:字节数组,用来封装接收到内容。
  • length:能够接收内容的长度,单位:字节。

DatagramSocket类构造方法:

DatagramSocket()

  • 创建发送端的Socket对象,随机生成一个端口号。

​​​​​​​DatagramSocket(int port)

  • 根据端口号创建Socket对象。(发送端创建不建议,接收端必须要指定端口号

DatagramSocket类成员方法:

void send(DatagramPacket dp)

  • 发送数据包。

​​​​​​​void receive(DatagramPacket dp)

  • 接受数据包。

接收端专用方法:

Inetaddress getAddress()

  • 获得发送端的IP对象。

​​​​​​​Int getPort()

  • 获得发送端的端口号。

​​​​​​​Int getlength()

  • 获得实际接受到的字节个数。

UDP协议示例代码:

public class UDPSender {
    public static void main(String[] args) throws IOException {
        byte[] bytes = "你好".getBytes();
        DatagramPacket dp = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),6666);
        DatagramSocket ds = new DatagramSocket();
        ds.send(dp);
        ds.close();
    }
}
public class UDPReceive {
    public static void main(String[] args) throws Exception {
        DatagramSocket ds = new DatagramSocket(6666);
        byte[] bf = new byte[1024];
        DatagramPacket dp = new DatagramPacket(bf,bf.length);
        ds.receive(dp);
        int length = dp.getLength();
        System.out.println(new String(bf,0,length));
        System.out.println(dp.getAddress().getHostAddress());
        System.out.println(dp.getPort());
        ds.close();
    }
}

TCP协议

TCP协议的概述:

  • TCP协议是面向连接的通信协议,即在传输数据前先在客户端和服务器端建立逻辑连接,然后再传输数据。它
    提供了两台计算机之间可靠无差错的数据传输。

TCP协议的特点:

  1. 面向连接的协议。
  2. 通过三次握手建立连接:形成数据传输通道。
  3. 通过四次挥手断开连接。
  4. 基于IO流进行数据传输。
  5. 传输数据大小没有限制。
  6. 数度慢但可靠。

TCP协议的使用场景:

  1. 文件上传下载。
  2. 邮件发送和接收。
  3. 远程登录。

TCP协议相关的两个类:

Socket

  • 一个该类的对象就代表一个客户端程序。

​​​​​​​ServerSocket

  • 一个该类的对象就代表一个服务器端程序。

Socket类构造方式:

Socket(String host, int port)

  • 根据服务器端IP地址和端口号创建客户端Socket对象。
  • host:服务器IP地址。
  • port:服务器端口号。
  • 注意:一旦执行该方法,就会立即连接指定的服务器,如果服务器没有开启,则连接失败抛出异常。

Socket类成员方法:

public void close()

  • 关闭Socket。
  • 一旦一个socket被关闭,它不可再使用。
  • 关闭此socket也将关闭相关的InputStream和OutputStream 。
  • 关闭Socket的作用是:释放端口号。

OutputStream getOutputStream()

  • 获得字节输出流对象

InputStream getInputStream()

  • 获得字节输入流对象。

​​​​​​​InetAddress getInetAddress()

  • 服务器专用,用来获得进入服务器该客户端的对象。

​​​​​​​ void shutdownOutput()

  • 表示输出数据结束。
  • 注意:一但shutdownOutput(),那么就不能再输出数据,重新getOutputStream也不可以。当循环输出后面还要用输入流或输出流时,则一定要用shutdownOutput,否则不能终止传输,会报错。若不是循环输出或者后面没有使用输入流或输出流,则可以不用shutdownOutput。

ServerSocket类构造方法:

ServerSocket(int port)

  • 根据端口号创建服务器端Socket对象, 相当于开启了一个服务器。

ServerSocket类成员方法:

Socket accept()

  • 等待客户端连接并获得与客户端相关的Socket对象。
  • 该方法是阻塞方法,会一直阻塞直到建立连接。

​​​​​​​void close()

  • 关闭ServerSocket。

TCP客户端实现步骤:

  1. 创建Socket对象指定服务器端IP地址和端口号。
  2. 调用Socket对象的getOutputStream方法获得字节输出流对象。
  3. 调用字节输出流对象的write方法往服务器端输出数据。
  4. 调用Socket对象的getInputStream方法获得字节输入流对象。
  5. 调用字节输入流对象的read方法读取服务器端返回的数据。
  6. 关闭Socket对象断开连接。

TCP服务器端代码实现步骤:

  1. 创建ServerSocket对象并指定端口号。
  2. 调用ServerSocket对象的accept方法等待客户端连接并获得与客户端相关的Socket对象。
  3. 调用Socket对象的getInputStream方法获得字节输入流对象。
  4. 调用字节输入流对象的read方法读取客户端发送的数据。
  5. 调用Socket对象的getOutputStream方法获取字节输出流对象。
  6. 调用字节输出流对象的write方法往客户端返回数据。
  7. 调用close方法关闭Socket和ServerSocket对象。
  • 可以只关闭Socket,不关闭ServerSocket。
  • 可以都关闭。
  • 可以都不关闭。
  • 若只关闭ServerSocket,不关闭Socket,会报错。

文件上传的案例:

图解:

示例代码:

客户端:

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

public class Sender {
    public static void main(String[] args) throws IOException {
        Socket s = new Socket("192.168.81.56",8888);
        OutputStream os = s.getOutputStream();
        FileInputStream fis = new FileInputStream("f:/a.png");
        int len = -1;
        byte[] bf = new byte[1024];
        while ((len = fis.read(bf)) != -1){
            os.write(bf,0,len);
        }
        s.shutdownOutput();
        fis.close();
        InputStream is = s.getInputStream();
        len = is.read(bf);
        System.out.println(new String(bf,0,len));
        s.close();
    }
}

服务器:

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

public class Receive {
    public static void main(String[] args) throws Exception {
        ServerSocket ss = new ServerSocket(8888);
        Socket socket = ss.accept();
        try(ss;socket) {
            InputStream is = socket.getInputStream();
            String s = "f:/" + System.currentTimeMillis() + ".png";
            FileOutputStream fos = new FileOutputStream(s);
            int len = -1;
            byte[] bf = new byte[1024];
            while((len = is.read(bf)) != -1){
                fos.write(bf,0,len);
            }
            fos.close();
            System.out.println(socket.getInetAddress());
            OutputStream os = socket.getOutputStream();
            os.write("上传成功".getBytes());
        }catch (Exception e){
            OutputStream stream = socket.getOutputStream();
            stream.write("上传失败".getBytes());
        }
}
}

若要实现多线程:

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

public class Receive1 {
    public static void main(String[] args) throws IOException {
        ServerSocket ss = new ServerSocket(8888);
        while(true){
            Socket socket = ss.accept();
            new Thread(() -> {
                try(socket) {
                    InputStream is = socket.getInputStream();
                    String s = "f:/" + System.currentTimeMillis() + ".png";
                    FileOutputStream fos = new FileOutputStream(s);
                    int len = -1;
                    byte[] bf = new byte[1024];
                    while((len = is.read(bf)) != -1){
                        fos.write(bf,0,len);
                    }
                    fos.close();
                    System.out.println(socket.getInetAddress());
                    OutputStream os = socket.getOutputStream();
                    os.write("上传成功".getBytes());
                }catch (Exception e){
                    OutputStream stream = null;
                    try {
                        stream = socket.getOutputStream();
                        stream.write("上传失败".getBytes());
                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }
            }).start();
        }

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值