DAY26 网络编程

Socket类

  1. Java类库中,定义了各种Socket类(类名都带Socket),来抽象传输层的功能,供我们的应用程序使用。
  2. Socket套接字 = IP + 端口号 Socket本身是网络协议中的概念,和语言无关
  3. 对于TCP和UDP分别定义类不同类型的Socket类,来实现分别基于TCP和UDP协议的输出传输。
  4. 端口号(只具有本地意义)每个进程都有一个端口号端口号,标识进程的逻辑地址,网络通信说到底是进程与进程间的通信,因此IP+端口号才能构成完整的目标地址
  5. 传输层的协议 TCP和UDP
    TCP 发送数据前要首先建立连接(3次握手机制) 连接建立成功后,会建立数据传输的“通道” 在该通道下进行数据传输 (一对一的通信)
    UDP (1对多) 发送数据时无需建立连接 每个发送的数据报大小限制在64KB
    在这里插入图片描述

UDP传输

	DatagramSocket	
	此类表示用来发送和接收数据报包的套接字。
	
	DatagramSocket(int port) 	
	创建数据报套接字并将其绑定到本地主机上的指定端口
	
	DatagramPacket(byte[] buf, int offset, int length, InetAddress address, int port) 
    构造数据报包,用来将长度为 length 偏移量为 offset 的包发送到指定主机上的指定端口号。

UDP传输的发送端:

  • 建立udp的socket对象
  • 将要发送的数据封装成数据报包
  • 通过udp的socket对象,将数据包发送出
  • 释放资源
   //1
   DatagramSocket datagramSocket = new DatagramSocket(10086);
   //2
   String s = "hello";//由应用程序产生,和传输无关
   byte[] data= s.getBytes();
   //3
   InetAddress ip = InetAddress.getByName("192.168.1.100");
   DatagramPacket packet = new DatagramPacket(data,0,data.length,ip,9999);
   datagramSocket.send(packet);
   //4
   datagramSocket.close();

UDP传输的接收端

  • UDP传输接收端:建立udp的socket对象.
  • 通过socket对象的receive方法接收数据
  • 将收到的数据存储到数据包对象中通过数据包对象的功能来完成对接收到数据进行解析.
  • 可以对资源进行释放
// 发送端将数据发送到那个端口,我们接收端的Socket对象,就必须绑定(监听),才能接收到发送端发送的数据
 DatagramSocket datagramSocket = new DatagramSocket(9999);

 // 2. 创建用于接收数据的数据报包,通过socket对象的receive方法接收数据
 // 创建用于接收数据的数据报包
 byte[] buffer = new byte[1024];
 DatagramPacket receivePacket = new DatagramPacket(buffer,buffer.length);
// 利用socket对象的receive方法,接收发送端发送的数据,并将数据方法接收的数据报包中的字节数组缓冲区中
// receive方法,它是一个阻塞方法,当没有接收到数据的时候,此时,它就一直阻塞
datagramSocket.receive(receivePacket);

 // 通过数据包对象的功能来完成对接收到的数据,进行进行解析的功能.(根据引用程序的逻辑来解析)
 //获取数据报包中,实际用来存放接收到的数据的,字节数组
 byte[] data = receivePacket.getData();
 // 该方法返回,本次实际接收到的字节数
 int length = receivePacket.getLength();
 // 该方法返回,接收到的数据,是从字节数组的哪个位置开始填充的
 int offset = receivePacket.getOffset();
 String result = new String(data, offset, length);
 // 接收数据的数据报包上调用 getAdrress 获取到的数据发送端的ip地址
 // 接收数据的数据报包上调用 getPort 获取到的数据发送端的端口号
 System.out.println("接收到来自:" + receivePacket.getAddress() + "-" +   receivePacket.getPort() + result);
 // 可以对资源进行释放
 datagramSocket.close();

TCP传输

TCP的Socket的数据传输是基于流来实现的

客户端

  • 建立客户端的Socket服务,并明确要连接的服务器。
  • 如果连接建立成功,就表明已经建立了数据传输的通道.就可以在该通道通过IO进行数据的读取和写入
  • 根据需要从socket对象中获取输入,或输出流
  • 向流中读取或写入数据
  • 释放资源
// 建立客户端的Socket服务,并明确要连接的服务器。
// 这里的ip地址和端口号指的是要连接的对端的ip地址和端口号
// 此时该Socket对象,所绑定的端口号,是系统随机选取的
 Socket socket = new Socket("192.168.0.100", 8989);
//只要客户端Socket对象成功创建,我们就可以认为连接已经创建好了
// 接下来,就从建立连接的客户端的Socket对象中,拿出输出流,向接收端发送数据
 OutputStream outputStream = socket.getOutputStream();
 String s = "hello tcp";
 outputStream.write(s.getBytes());
 // 这里要注意,在释放资源的时候,我们只需要close Socket对象即可,因为Socket对象会负责自己关闭自己的输入,输出流
 socket.close();

服务器端

  • 创建Serversocket对象,在指定端口,监听客户端连接请求
  • 收到客户端连接请求后,建立Socket连接
  • 如果连接建立成功,就表明已经建立了数据传输的通道.就可以在该通道通过IO进行数据的读取和写入
  • 从socket中根据需要获取输入,或输出流
  • 根据需要向流中写入数据或从流中读数据
  • 释放资源
ServerSocket serverSocket = new ServerSocket(8989);
// 对在指定端口接收到的,连接请求之后,和客户端的Socket对象建立连接
// accept方法会返回一个Socket对象,实际本次连接实际就是在该Socket对象和客户端Socket对象之间建立的
Socket accept = serverSocket.accept();  // 没有连接请求时,阻塞在这里
//从服务器端socket对象中,根据需要拿出流,进行数据传输
InputStream inputStream = accept.getInputStream();
byte[] buffer = new byte[1024];
int readBytes = inputStream.read(buffer);
String result = new String(buffer, 0, readBytes);
System.out.println("接收到," + accept.getInetAddress() + "-" + accept.getPort() + "发送是的数据:"  + result);
//关闭ServerSocket和Socket对象
serverSocket.close();
accept.close();

(附)UDP聊天框架

package com.cskaoyan.udp.edition4.oneperson;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * @author zhangshuai@Cskaoyan.onaliyun.com on 2020/3/30.
 * @version 1.0
 */
public class OnePerson {
  public static boolean isOffLine = false;

  public static void main(String[] args) throws SocketException, UnknownHostException {

    // 创建用来接收数据或者发送数据的DatagramSocket对象
    DatagramSocket datagramSocket = new DatagramSocket(10086);

    // 接收数据的任务
    ReceiverTask receiverTask = new ReceiverTask(datagramSocket);

    InetAddress targetIp = InetAddress.getLocalHost();
    int targetPort = 9999;
    SenderTask senderTask = new SenderTask(datagramSocket, targetIp, targetPort);

    new Thread(receiverTask).start();
    new Thread(senderTask).start();
  }
}

public class SenderTask implements Runnable {
  private DatagramSocket datagramSocket;
  private InetAddress targetIp;
  private int targetPort;
  
  public SenderTask(DatagramSocket datagramSocket, InetAddress targetIp, int targetPort) {
    this.datagramSocket = datagramSocket;
    this.targetIp = targetIp;
    this.targetPort = targetPort;
  }

  @Override
  public void run() {
    // 用该缓冲字符流从键盘读取字符串
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    String s;
    try {

      while ((s = br.readLine()) != null) {
        byte[] data = s.getBytes();
        // 将要发送的数据,封装到数据报包中
        DatagramPacket packet = new DatagramPacket(data, 0, data.length, targetIp, targetPort);
        // 发送数据
        datagramSocket.send(packet);

        if ("886".equals(s)) {
          OnePerson.isOffLine = true;
          break;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

public class ReceiverTask implements Runnable {

  private DatagramSocket datagramSocket;

  public ReceiverTask(DatagramSocket datagramSocket) {
    this.datagramSocket = datagramSocket;
  }

  @Override
  public void run() {
    byte[] buffer = new byte[1024];
    DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);
    boolean flag = true;
    //不停的接收,另外一个人发送过来的数据
    try {
      while (flag) {
        //接收数据
        datagramSocket.receive(receivePacket);

        byte[] data = receivePacket.getData();
        int length = receivePacket.getLength();
        int offset = receivePacket.getOffset();

        String result = new String(data, offset, length);

        System.out.println("接收到来自:" + receivePacket.getAddress() + "-" + receivePacket.getPort() + result);
        if ("886".equals(result)) {
        break;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {

      while (!OnePerson.isOffLine) {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      datagramSocket.close();
    }
  }
}

package com.cskaoyan.udp.edition4.anotherperson;

import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;
import java.net.UnknownHostException;

/**
 * @author zhangshuai@Cskaoyan.onaliyun.com on 2020/3/30.
 * @version 1.0
 */
public class AnotherPerson {

  /*
      该变量,是专门用来标识,发送线程状态的,当发送线程发送完886之后,
      将isOffline的值置为true
   */
  public static boolean isOffline = false;

  public static void main(String[] args) throws SocketException, UnknownHostException {

    // 创建用来接收数据或者发送数据的DatagramSocket对象
    DatagramSocket datagramSocket = new DatagramSocket(9999);

    // 接收数据的任务
    ReceiverTask receiverTask = new ReceiverTask(datagramSocket);

    InetAddress targetIp = InetAddress.getLocalHost();
    int targetPort = 10086;
    SenderTask senderTask = new SenderTask(datagramSocket, targetIp, targetPort);

    new Thread(receiverTask).start();
    new Thread(senderTask).start();

  }

}

public class ReceiverTask implements Runnable {

  private DatagramSocket datagramSocket;

  public ReceiverTask(DatagramSocket datagramSocket) {
    this.datagramSocket = datagramSocket;
  }

  @Override
  public void run() {

    byte[] buffer = new byte[1024];
    DatagramPacket receivePacket = new DatagramPacket(buffer, buffer.length);

    boolean flag = true;


    //不停的接收,另外一个人发送过来的数据
    try {
      while (flag) {
          //接收数据
          datagramSocket.receive(receivePacket);

          byte[] data = receivePacket.getData();
          int length = receivePacket.getLength();
          int offset = receivePacket.getOffset();

          String result = new String(data, offset, length);

          System.out.println("接收到来自:" + receivePacket.getAddress()+ "-" + receivePacket.getPort() + result);
          if ("886".equals(result)) {
            break;
          }
      }
    } catch (IOException e) {
      e.printStackTrace();
    } finally {
      while (!AnotherPerson.isOffline) {
        try {
          Thread.sleep(1000);
        } catch (InterruptedException e) {
          e.printStackTrace();
        }
      }
      datagramSocket.close();
    }
  }
}


public class SenderTask implements Runnable {

  private DatagramSocket datagramSocket;
  private InetAddress targetIp;
  private int targetPort;

  public SenderTask(DatagramSocket datagramSocket, InetAddress targetIp, int targetPort) {
    this.datagramSocket = datagramSocket;
    this.targetIp = targetIp;
    this.targetPort = targetPort;
  }

  @Override
  public void run() {
    // 用该缓冲字符流从键盘读取字符串
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

    String s;
    try {
      while ((s = br.readLine()) != null) {
        byte[] data = s.getBytes();

        // 将要发送的数据,封装到数据报包中
        DatagramPacket packet = new DatagramPacket(data, 0, data.length, targetIp, targetPort);

        // 发送数据
        datagramSocket.send(packet);

        if ("886".equals(s)) {
          // 发送端任务完成
          AnotherPerson.isOffline = true;
          break;
        }
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值