Java网络编程——TCP

网络编程,TCP编程

  • TCP通信程序
    • 三次握手
    • 四次挥手
    • 发送步骤
    • 接收步骤
    • TCP发送和接收数据
    • 文件传输
    • 改进文件传输

TCP通信程序

TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象。
通信之前要保证连接已经建立。
有两个很重要的对象 :
Scoket:服务端和客户端都要使用,负责传输数据。
ServerSoket:服务端使用,负责接收客户端的连接请求。
通过Socket产生IO流来进行网络通信。

三次握手

TCP三次握手是指,客户端与服务器连接时:
第一次握手,客户端向服务器发送连接请求,等待服务器确认;
第二次握手,服务器向客户端返回一个响应,告诉客户端收到了请求;
第三次握手,客户端向服务器再次发出确认信息,建立连接。

正是因为有三握手,保证了TCP协议客户端与服务器的连接。

四次挥手

TCP四次挥手是指,客户端与服务器断开连接时:
第一次挥手,客户端向服务器发出取消连接请求;
第二次挥手,服务器向客户端返回一个响应,表示收到请求;
第三次挥手,服务器向客户端发出确认取消信息;
第四次挥手,客户端再次发送确认消息,连接断开。

发送步骤

TCP发送数据步骤

  1. 创建客户端的Socket对象(Socket)与指定服务端连接
    Socket​(String host, int port)
  2. 获取输出流,写数据
    OutputStream getOutputStream​()
  3. 释放资源,输出流和socket都要关闭
    void close​()

接收步骤

TCP接收数据步骤

  1. 创建服务器端的Socket对象(ServerSocket),端口号要一致
    ServerSocket​(int port)
  2. 监听客户端连接,返回一个Socket对象
    Socket accept​()
  3. 获取输入流,读数据,并把数据显示在控制台
    **InputStream getInputStream​() **
  4. 释放资源,输入流以及socket全部都要关闭
    void close​()

TCP发送和接收数据

public class Client {
    public static void main(String[] args) throws IOException {
        //客户端发送消息
        //1.创建客户端socket对象
        Socket socket = new Socket("127.0.0.1", 3000);
        //2.因为要发送消息,所以准备输出流,这个输出流是输出到网络
        OutputStream outputStream = socket.getOutputStream();
        //3.发送消息,把数据写到输出流
        outputStream.write("Hello,Server".getBytes(StandardCharsets.UTF_8));
        //4.关闭,释放资源
        outputStream.close();
        socket.close();
        //没有连接发送会失败报错
    }
}

public class Server {
    public static void main(String[] args) throws IOException {
        //接收客户端发送的消息
        System.out.println("服务器端启动");
        //1.创建一个服务器端socket
        ServerSocket serverSocket = new ServerSocket(3000);
        //2.等待客户端的连接,并创建一个客户端的socket对象
        Socket socket = serverSocket.accept();//会阻塞,有连接才会往下执行
        System.out.println("有客户端连接");
        //3.获取输入流
        InputStream inputStream = socket.getInputStream();
        int length = 0;
        byte[] datas = new byte[1024];
        length = inputStream.read(datas);
        String message = new String(datas, 0, length, StandardCharsets.UTF_8);
        System.out.println(message);

    }
}

先启动服务器端,且服务器端可以接收多个客户端的请求,并且不止接收一次,一般不会关闭,需要用到多线程。

Java网络编程——TCP_第1张图片

文件传输

TCP中,客户端上传文件到服务器,与文件流的copy相似。
此时的I(InPut),是本地文件,数据从本地文件中来;O(OutPut),是网络,通过网络将文件上传到服务器,数据到网络中去。

public class FileClient {
    public static void main(String[] args) throws IOException {
        System.out.println("客户端启动,正在连接服务器");
        //一般不这样写,这样写叫做魔术值,一般将它拆分成一个字符串存储的IP地址,一个int类型的端口号
        Socket socket = new Socket("127.0.0.1", 3000);
        //上传文件
        //I:数据来自于本地硬盘文件
        System.out.println("开始读取本地文件");
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\工程\\成\\fifth.jpg");
        //O:数据去往网络
        OutputStream outputStream = socket.getOutputStream();
		//文件流读写操作
        byte[] datas = new byte[1024];
        int length = 0;
        System.out.println("文件读取完成,正在上传");
        while ((length = fileInputStream.read(datas)) != -1){
            outputStream.write(datas, 0, length);
        }
        System.out.println("文件上传完毕");
        outputStream.close();
        fileInputStream.close();
        socket.close();
    }
}

public class FileServer {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器端启动");
        ServerSocket serverSocket = new ServerSocket(3000);
        System.out.println("等待客户端连接");
        Socket socket = serverSocket.accept();
        System.out.println("客户端连接,准备接收文件");
        //创建输入流,数据从网络来
        InputStream inputStream = socket.getInputStream();
        //创建输出流,数据到本地
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\test.jpg");

        byte[] datas = new byte[1024];
        int length = 0;
        System.out.println("正在接收文件");
        System.out.println("正在将文件写入磁盘");
        while ((length = inputStream.read(datas)) != -1){
            fileOutputStream.write(datas, 0, length);
        }
        System.out.println("文件写入完毕");
        fileOutputStream.close();
        inputStream.close();
        socket.close();
    }
}

Java网络编程——TCP_第2张图片

改进文件传输

上面的代码虽然实现了客户端与服务器的文件传输,但是一般来说,服务器接收完之后应该向客户端再返回一个确认消息,告知数据已经接收完毕,客户端根据这个消息来判断是否断开连接。

public class FileClientPlus {
    public static void main(String[] args) throws IOException {
        System.out.println("客户端启动,正在连接服务器");
        Socket socket = new Socket("127.0.0.1", 3000);
        //上传文件
        //I:数据来自于本地硬盘文件
        System.out.println("开始读取本地文件");
        FileInputStream fileInputStream = new FileInputStream("C:\\Users\\Administrator\\Desktop\\工程\\成\\fifth.jpg");
        //O:数据去往网络
        OutputStream outputStream = socket.getOutputStream();

        byte[] datas = new byte[1024];
        int length = 0;
        System.out.println("文件读取完成,正在上传");
        while ((length = fileInputStream.read(datas)) != -1){
            outputStream.write(datas, 0, length);
        }
        //关闭output流,告诉服务器流数据传输完毕,但是不断掉与服务器的连接,这样才能继续接收服务器的消息,如果不关闭,服务器无法得知上传已经完成,所以也不会继续往后执行,返回客户端一个确认消息
        socket.shutdownOutput();

        System.out.println("文件上传完毕");
        System.out.println("等待服务器发送确认消息");
        //接收服务器端发送的确认消息,接收到以后再关闭
        //1.接收首先要有一个输入流
        InputStream inputStream = socket.getInputStream();
        length = inputStream.read(datas);
        String message = new String(datas, 0, length, StandardCharsets.UTF_8);
        System.out.println("已收到来自服务器端的确认消息:" + message);

		//全部操作完成后关闭输入输出流、socket
        inputStream.close();
        outputStream.close();
        fileInputStream.close();
        socket.close();
    }
}

public class FileServerPlus {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器端启动");
        ServerSocket serverSocket = new ServerSocket(3000);
        System.out.println("等待客户端连接");
        Socket socket = serverSocket.accept();
        System.out.println("客户端连接,准备接收文件");
        //创建输入流,数据从网络来
        InputStream inputStream = socket.getInputStream();
        //每一次存的文件名字不再固定
        String uuid = UUID.randomUUID().toString();
        //创建输出流,数据到本地
        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\"+ uuid + ".jpg");
        //也可以用时间戳,目的都是为了就算上传的文件一致,但是都可以储存
//        String currentTimeMillis = System.currentTimeMillis() + "";
//        FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Administrator\\Desktop\\"+ currentTimeMillis + ".jpg");

        byte[] datas = new byte[1024];
        int length = 0;
        System.out.println("正在接收文件");
        System.out.println("正在将文件写入磁盘");
        while ((length = inputStream.read(datas)) != -1){
            fileOutputStream.write(datas, 0, length);
        }
        System.out.println("文件写入完毕");
        System.out.println("准备向客户端发送确认消息");
        //发送消息给客户端,告知结果
        OutputStream outputStream = socket.getOutputStream();
        outputStream.write("ok".getBytes(StandardCharsets.UTF_8));

        System.out.println("消息发送完成");
        outputStream.close();
        fileOutputStream.close();
        inputStream.close();
        socket.close();
    }
}

Java网络编程——TCP_第3张图片
Java网络编程——TCP_第4张图片
如果客户端没有使用**socket.shutdownOutput()**关闭输出流的话,运行的结果将会是这样的
Java网络编程——TCP_第5张图片
服务器不知道有没有上传完,无法进入下一步。
Java网络编程——TCP_第6张图片
客户端得不到服务器的确认消息,也无法继续执行。
这样一来,就陷入了死循环。

你可能感兴趣的:(笔记,网络,tcp/ip,java)