27.网络编程(UDP,TCP)


UDP传输


一.发送端
1.建立udp的socket对象
2.将要发送的数据封装成数据包
3.通过udp的socket对象,将数据包发送出
4.释放资源

public class Sender {

  public static void main(String[] args) throws IOException {

    // 应用层: 根据应用层的业务逻辑,产生要发送的数据
    String data = "hello, udp";

    //-------------------------------------------------------------
    //  数据传输
    //1. 创建Socket对象
    DatagramSocket datagramSocket = new DatagramSocket(10086);//本机端口

    //2.将要发送的数据封装成数据包
    byte[] dataBytes = data.getBytes();
    // 将要发送的字节数据,封装到数据报包中
    InetAddress targetIp = InetAddress.getByName("192.168.56.1");
    int tartPort = 9998;
    DatagramPacket senderPacket = new DatagramPacket(dataBytes, 0,
        dataBytes.length, targetIp, tartPort);

    // 3. 利用DatagramSocket对象的send方法,将数据报包,发送出去
    datagramSocket.send(senderPacket);

    // 4. 释放Socket套接字
    datagramSocket.close();

  }

}

a. DatagramSocket(基于UDP)
此类表示用来 发送 和 接收 数据报包 的套接字。
构造方法
DatagramSocket(int port) 该Socket对象,本机ip + 指定端口号 port
创建数据报套接字并将其绑定到本地主机上的指定端口。
b. 发送数据的数据报包
DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port)
构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。
参数:
buf - (要发送的)包数据。
offset - 包数据偏移量。
length - 包数据长度。
address - 目的地址。
port - 目的端口号。
c. 利用DatagramSocket对象的send方法
public void send(DatagramPacket p)
1)从此套接字发送数据报包。
2)DatagramPacket 包含的信息指示:将要发送的数据、其长度、远程主机的 IP 地址和远程主机的端口号。
发现,即使还没有接收端(接收端根本就没运行), 基于UDP协议的发送端,仍然可以正常向接收端发送数据。所以,再次证明,UDP协议是一种无连接的 不可靠 的协议。
 
二:接收端
1.建立udp的socket对象.
2.创建用于接收数据的数据报包,
3.通过socket对象的receive方法接收数据
4.可以对资源进行释放

public class Receiver {

  public static void main(String[] args) throws IOException {
     // 1.创建接收端,用来发送和接收数据的DatagramSocket对象
    DatagramSocket datagramSocket = new DatagramSocket(9998);

    // 2. 创建用来接收数据的数据报包
    byte[] buf = new byte[1024];

    //演示offset
    int off = 5;

    //创建用来接收数据的数据报包
    DatagramPacket receiverPacket = new DatagramPacket(buf, off, buf.length - off);

    //3.调用datagramSocket的receive方法,接收发送端发送的数据
    datagramSocket.receive(receiverPacket);


    //4. 释放资源
     datagramSocket.close();

    // -----------------------------------------------------------------
    // 应用层,解析并处理接收到数据(字节)

    // 接收到的多个字节数据
    byte[] data = receiverPacket.getData();
    // 获取,实际接收到的字节数据的起始位置
    int offset = receiverPacket.getOffset();
    System.out.println("应用层: " + offset);
    //获取,本次实际接收到的字节数
    int length = receiverPacket.getLength();
    System.out.println("应用层: " + length);

    // 解析接收到的字节数据
    String s = new String(data, offset, length);
    // 在接受数据的数据报包上调用以下方法:
    // 1. InetAddress receiverPacket.getAddress() 获取发送方ip
    // 2. int         receiverPacket.getPort() 发送方的端口号
    System.out.println(receiverPacket.getAddress() + ":" + receiverPacket.getPort() + ", " +s);

  }

}

用来接受数据的数据报包:
a.DatagramPacket(byte[] buf, int offset, int length)
构造 DatagramPacket,用来接收长度为 length 的包,在缓冲区中指定了偏移量。
参数:
buf - 保存传入数据报的缓冲区。
offset - 缓冲区的偏移量
length - 读取的字节数。
b.
public void receive(DatagramPacket p)
a.从此套接字接收数据报包。
b.当此方法返回时,DatagramPacket 的缓冲区填充了接收的数据。
c. 数据报包也包含发送方的 IP地址和发送方机器上的端口号。
d. 此方法在接收到数据报前一直阻塞
注意事项:
1. receive方法是一个阻塞方法
2. 当我们两次运行Receiver接收端,BindException: Address already in use (ip + port)一个端口号只能同时绑定一个进程,所以当两次启动Receiver端的时候,相当于要让两个进程绑定同一个端口号。
 


TCP传输


一:发送端
1.建立客户端的Socket对象,并明确要连接的对端的(服务器端)地址。
2.如果Socket对象建立成功,就表明客户端和服务器端已经建立好了连接。此时如果要发送数据,就可以在Socket对象中获取用来发送数据的流
3.向流中读取或写入数据
4.释放资源
 
a. public class Socket
此类实现 客户端 套接字(也可以就叫“套接字”)。
Socket(String host, int port)
创建一个流套接字 并将其连接到 指定主机上的指定端口号。
host:客户端要连接的,服务器端主机的目标ip地址
port: 客户端要连接的, 服务器端主机中目标进程的端口
注意:我们创建出来的Socket对象,它本身绑定的是本机ip地址 + 绑定一个系统随机分配的端口号。
注意事项:当服务器端还未运行的时候,直接运行客户端,会报错ConnectException: Connection refused, 因为,基于tcp协议的数据传输,要先建立好连接,才能传输数据
所以tcp协议是一种有连接的 可靠 的协议

public class Client {

  public static void main(String[] args) throws IOException {
    // 1.创建基于TCP协议的Socket对象
    Socket socket = new Socket("127.0.0.1", 9999);

    // 2. 从Socket对象中获取用来发送数据的流
    OutputStream out = socket.getOutputStream();

    //3. 利用流发送数据
    out.write("hello, tcp".getBytes());

    //4. 关闭Socket,释放资源
    socket.close(); // socket会负责关闭,并释放其底层流
  }

}

二:接收端
1.创建ServerSocket对象,在指定端口监听客户端连接请求
2.收到客户端连接请求后,建立Socket连接
3.如果连接建立成功,就表明已经建立了数据传输的通道.就可以在该通道通过IO进行数据的读取和写入
从socket中根据需要获取输入或输出流
4.根据需要向流中写入数据或从流中读数据
5.释放资源
 
public class ServerSocket
此类实现服务器套接字。服务器套接字等待(连接)请求通过网络传入(ServerSocket接收并处理连接请求)
ServerSocket(int port)
1.侦听并接受到此套接字的连接。
2.此方法在连接传入之前一直阻塞。
注意事项:
1. accept方法是阻塞方法
2. 服务器端,不能同时启动两次 BindException: Address already in use

public class Server {

  public static void main(String[] args) throws IOException {
    //1. 创建ServerSocket对象
    ServerSocket serverSocket = new ServerSocket(9999);

    //2.收到客户端连接请求后,建立Socket连接
    Socket socket = serverSocket.accept();
    //根据需要从服务器端的Socket对象,获取流
    InputStream in = socket.getInputStream();

    byte[] buf = new byte[1024];
    //4.根据需要向流中写入数据或从流中读数据
    int len = in.read(buf);

    String s = new String(buf, 0, len);
    // 通过Socket对象的getAnetAddress() 以及 getPort(), 可以分别获取到发送端额ip地址和端口号
    System.out.println("接收到来自," + socket.getInetAddress() + ":" + socket.getPort()+ " " + s);

    //5.释放资源
    socket.close();
    serverSocket.close();
  }

}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值