Socket通讯

  • InetAddress

    • 了解了IP地址的作用,我们看学习下JDK中提供了一个InetAdderss类,该类用于封装一个IP地址,并提供了一系列与IP地址相关的方法,下表中列出了InetAddress类的一些常用方法。

    • import java.net.InetAddress;
      
      /**
       * <p>ProjectName: Test</p>
       * <p>ClassName: InetAddress</p>
       * <p>Description: InetAdress</p>
       * <p>Company:www.ecostor.biz </p>
       *
       * @author jiewenbo
       * @version 1.0
       * @date 2019/5/12 14:23
       */
      public class InetAddressDemo {
          public static void main(String[] args) throws Exception {
              //获取ip的类
              InetAddress inetAddress = InetAddress.getLocalHost();
              System.out.println(inetAddress);
              //获得本机的ip
              String hostAddress = inetAddress.getHostAddress();
              System.out.println(hostAddress);
              //获得本机的主机名
              String hostName = inetAddress.getHostName();
              System.out.println(hostName);
      
              //获取网络的主机ip
              InetAddress inetAddress1 = InetAddress.getByName("www.baidu.com");
              InetAddress inetAddress2 = InetAddress.getByName("61.135.169.121");
              System.out.println(inetAddress1);
              System.out.println(inetAddress2);
          }
      }
      

       

    • UDP通信

      • UDP是一种面向无连接的协议,因此,在通信时发送端和接收端不用建立连接。

      • UDP客户端

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;

/**
 * <p>ProjectName: Test</p>
 * <p>ClassName: UDPSend</p>
 * <p>Description: 实现UDP协议的发送端</p>
 * <p>Company:www.ecostor.biz </p>
 * 实现封装数据的类 java.net.DatagramPacket 将数据包包装
 * 实现数据传输的类 java.net.DatagramSocket 将数据发送出去
 * 实现步骤:
 * 1、创建DatagramPacket对象,封装数据,填写ip和端口号
 * 2、创建DatagramSocket对象
 * 3、调用DatagramSocket的send方法,发送数据包
 * 4、关闭资源
 * DatagramPacket的构造方法:
 * <p>
 * DatagramSocket的构造方法
 *
 * @author jiewenbo
 * @version 1.0
 * @date 2019/5/11 20:10
 */
public class UDPSend {
    public static void main(String[] args) throws Exception {
        Scanner scanner = new Scanner(System.in);
        //创建InetAdress,封装自己的Ip
        InetAddress inet = InetAddress.getByName("127.0.0.1");

        //DatagramSocket:发送和接收数据的套接字 套接字:绑定ip和端口号的对象,发送的话直接使用无参构造
        DatagramSocket datagramSocket = new DatagramSocket();
        while (true) {
            String s = scanner.nextLine();
            byte[] bytes = s.getBytes();
            DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length, inet, 6000);
            datagramSocket.send(datagramPacket);
        }
        //关闭资源
//        datagramSocket.close();
    }
}
  • UDP服务端
  • import java.net.DatagramPacket;
    import java.net.DatagramSocket;
    
    /**
    * <p>ProjectName: Test</p>
    * <p>ClassName: UDPReceive</p>
    * <p>Description: 实现UDP协议的接收端</p>
    * <p>Company:www.ecostor.biz </p>
    * 实现封装数据的包 java.net.DatagramPacket 将数据接收
    * 实现数据的传输 java.net.DatagramSocket接收数据包
    * 实现步骤:
    *  1、创建DatagramSocket对象绑定端口号,要和发送的一致
    *  2、创建字节数组,接收发来的数据
    *  3、创建数据包对象 DatagramPacket
    *  4、调用DatagramSocket对象方法receive(DatagramPacket dp)接收数据,放入数据包中
    *  5、拆包 :  发送的ip地址
    *                  DatagramPacket getAddress() 获得InetAddress对象,getHostAddress(),获得ip
    *              发送的字节数
    *                  DatagramPacket getLength()
    *              发送方的端口号
    *  6、关闭资源
    * @version 1.0
    * @author jiewenbo
    * @date 2019/5/11 20:25
    */
    public class UDPReceive {
        public static void main(String[] args) throws Exception{
            DatagramSocket datagramSocket = new DatagramSocket(6000);
            byte[] bytes = new byte[1024];
            while (true) {
                DatagramPacket datagramPacket = new DatagramPacket(bytes, bytes.length);
                //recive()具有多线程,线程阻塞
                datagramSocket.receive(datagramPacket);
                //拆包
                //获得自己数组长度
                int length = datagramPacket.getLength();
                //拿到ip
                String hostAddress = datagramPacket.getAddress().getHostAddress();
                //拿到发送端的端口号
                int port = datagramPacket.getPort();
                String s = new String(bytes,0,length);
                System.out.println(hostAddress);
                System.out.println(s);
                System.out.println(port);
            }
    //        datagramSocket.close();
        }
    }

     

  • TCP通信

  • TCP通信同UDP通信一样,都能实现两台计算机之间的通信,通信的两端都需要创建socket对象。

    区别在于,UDP中只有发送端和接收端,不区分客户端与服务器端,计算机之间可以任意地发送数据。

    而TCP通信是严格区分客户端与服务器端的,在通信时,必须先由客户端去连接服务器端才能实现通信,服务器端不可以主动连接客户端,并且服务器端程序需要事先启动,等待客户端的连接
  • 在JDK中提供了两个类用于实现TCP程序,一个是ServerSocket类,用于表示服务器端,一个是Socket类,用于表示客户端

    通信时,首先创建代表服务器端的ServerSocket对象,该对象相当于开启一个服务,并等待客户端的连接,然后创建代表客户端的Socket对象向服务器端发出连接请求,服务器端响应请求,两者建立连接开始通信。

    1. ServerSocket

通过前面的学习知道,在开发TCP程序时,首先需要创建服务器端程序。JDK的java.net包中提供了一个ServerSocket类,该类的实例对象可以实现一个服务器段的程序。通过查阅API文档可知,ServerSocket类提供了多种构造方法,接下来就对ServerSocket的构造方法进行逐一地讲解。

使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上(参数port就是端口号)。

接下来学习一下ServerSocket的常用方法,如表所示。

ServerSocket对象负责监听某台计算机的某个端口号,在创建ServerSocket对象后,需要继续调用该对象的accept()方法,接收来自客户端的请求。当执行了accept()方法之后,服务器端程序会发生阻塞,直到客户端发出连接请求,accept()方法才会返回一个Scoket对象用于和客户端实现通信,程序才能继续向下执行。

  1. Socket

讲解了ServerSocket对象可以实现服务端程序,但只实现服务器端程序还不能完成通信,此时还需要一个客户端程序与之交互,为此JDK提供了一个Socket类,用于实现TCP客户端程序。

通过查阅API文档可知Socket类同样提供了多种构造方法,接下来就对Socket的常用构造方法进行详细讲解。

使用该构造方法在创建Socket对象时,会根据参数去连接在指定地址和端口上运行的服务器程序,其中参数host接收的是一个字符串类型的IP地址。

该方法在使用上与第二个构造方法类似,参数address用于接收一个InetAddress类型的对象,该对象用于封装一个IP地址。

在以上Socket的构造方法中,最常用的是第一个构造方法。

接下来学习一下Socket的常用方法,如表所示。

方法声明

功能描述

int getPort()

该方法返回一个int类型对象,该对象是Socket对象与服务器端连接的端口号

InetAddress getLocalAddress()

该方法用于获取Socket对象绑定的本地IP地址,并将IP地址封装成InetAddress类型的对象返回

void close()

该方法用于关闭Socket连接,结束本次通信。在关闭socket之前,应将与socket相关的所有的输入/输出流全部关闭,这是因为一个良好的程序应该在执行完毕时释放所有的资源

InputStream getInputStream()

该方法返回一个InputStream类型的输入流对象,如果该对象是由服务器端的Socket返回,就用于读取客户端发送的数据,反之,用于读取服务器端发送的数据

OutputStream getOutputStream()

该方法返回一个OutputStream类型的输出流对象,如果该对象是由服务器端的Socket返回,就用于向客户端发送数据,反之,用于向服务器端发送数据

在Socket类的常用方法中,getInputStream()和getOutStream()方法分别用于获取输入流和输出流。当客户端和服务端建立连接后,数据是以IO流的形式进行交互的,从而实现通信。

接下来通过一张图来描述服务器端和客户端的数据传输,如下图所示。

 tcpclient 简单的(非文件上传)

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

/**
 * <p>ProjectName: Test</p>
 * <p>ClassName: TCPClient</p>
 * <p>Description: </p>
 * <p>Company:www.ecostor.biz </p>
 *Socket 的构造方法 Socket("ip地址",端口号)
 *
 * @author jiewenbo
 * @version 1.0
 * @date 2019/5/11 23:38
 */
public class TCPClient {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("127.0.0.1", 6001);
        //创建客户端输入流
        InputStream inputStream = socket.getInputStream();
        //创建客户端输出流
        OutputStream outputStream = socket.getOutputStream();
        byte[] bytes = "向服务器发送数据".getBytes();
        //将数据写向服务器
        outputStream.write(bytes);
        byte[] bytes1 = new byte[1024];
        int len = inputStream.read(bytes1);
        System.out.println(new String(bytes1,0,len));
        socket.close();
    }
}

tcp服务端

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

/**
 * <p>ProjectName: Test</p>
 * <p>ClassName: TCPServer</p>
 * <p>Description: </p>
 * <p>Company:www.ecostor.biz </p>
 * 实现TCP服务器程序
 * 表示服务器的程序的类 java.net.ServerSocket
 * 构造方法 new ServerSocket(int Port)传递端口号
 * <p>
 * <p>
 * 很重要的事情:获得客户端的套接字 Socket accept()
 *
 * @author jiewenbo
 * @version 1.0
 * @date 2019/5/11 23:48
 */
public class TCPServer {
    public static void main(String[] args) throws Exception {
        ServerSocket serverSocket = new ServerSocket(6001);
        //调用服务器套接字中的方法accept() 获得客户端套接字
        Socket socket = serverSocket.accept();
        //获取客户端发送的数据
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream = socket.getOutputStream();
        byte[] bytes = new byte[1024];
        int len = inputStream.read(bytes);
        System.out.println(new String(bytes, 0, len));
        byte[] bytes1 = "服务器端返回的数据".getBytes();
        outputStream.write(bytes1);
        serverSocket.close();
    }
}

tcpsocket实现文件长传,开启多线程

//创建线程类

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

/**
 * <p>ProjectName: Test</p>
 * <p>ClassName: SocketThread</p>
 * <p>Description: </p>
 * <p>Company:www.ecostor.biz </p>
 *
 * @author jiewenbo
 * @version 1.0
 * @date 2019/5/12 16:05
 */
public class SocketThread extends Thread {
    private Socket socket;

    SocketThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //创建接受的文件的名称
            File file = new File("d:/aaa"+System.currentTimeMillis()+".docx");
            OutputStream fileOutputStream = new FileOutputStream(file);
            BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
            //获取客户端的信息
            InetAddress inetAddress = socket.getInetAddress();
            System.out.println("客户端ip:" + inetAddress.getHostAddress());
            System.out.println("客户端名称:" + inetAddress.getHostName());
            System.out.println("客户端port:" + socket.getPort());
            //获得输入输出流
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            byte[] bytes = new byte[1024];
            int i;
            while ((i = inputStream.read(bytes)) != -1) {
                bufferedOutputStream.write(bytes, 0, i);
            }
            //向客户端返回上传成功的信息
            outputStream.write("长传成功".getBytes());
            outputStream.close();
            bufferedOutputStream.close();
            fileOutputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

编写服务器端程序

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

/**
 * <p>ProjectName: Test</p>
 * <p>ClassName: TCPServiceFile</p>
 * <p>Description: </p>
 * <p>Company:www.ecostor.biz </p>
 *
 * @author jiewenbo
 * @version 1.0
 * @date 2019/5/12 15:11
 */
public class TCPServiceFile {
    public static void main(String[] args) throws Exception {
        //创建服务器端的ServerSocket
        ServerSocket serverSocket = new ServerSocket(6666);
        Socket socket;
        while (true) {
            //获得客户端的Socket
            socket = serverSocket.accept();
            new SocketThread(socket).run();
        }


//        serverSocket.close();
    }
}

编写客户端程序

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

/**
 * <p>ProjectName: Test</p>
 * <p>ClassName: TCPClientFile</p>
 * <p>Description: </p>
 * <p>Company:www.ecostor.biz </p>
 *
 * @author jiewenbo
 * @version 1.0
 * @date 2019/5/12 15:38
 */
public class TCPClientFile {
    public static void main(String[] args) throws Exception {
        //创建Socket套接字
        Socket socket = new Socket("127.0.0.1", 6666);
        //选择上传的相片
        File file = new File("f:/关于印发市县审计机关在线实时联网审计建设方案的通知(2).docx");
        FileInputStream fileInputStream = new FileInputStream(file);
        BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream);
        InputStream inputStream = socket.getInputStream();
        OutputStream outputStream = socket.getOutputStream();

        byte[] bytes = new byte[1024];
        int i;
        while ((i = bufferedInputStream.read(bytes)) != -1) {
            outputStream.write(bytes, 0, i);
        }
        //上传完成传递终止符
        socket.shutdownOutput();
        //上传完成接收服务器端回执消息
        int read = inputStream.read(bytes);
        System.out.println(new String(bytes, 0, read));
        //关闭资源
        fileInputStream.close();
        inputStream.close();
        outputStream.close();
        socket.close();
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值