网络编程(3)TCP通信协议

TCP通信协议

1️⃣TCP通信原理:

  • TCP通信协议是一种可靠的网络协议,它在通信的两端各建立一个Socket对象。
  • 通信之前要保证连接已经建立,否则报错
  • 通过Socket产生IO流来进行网络通信

2️⃣TCP发送数据的步骤:

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

客户端代码演示:

import java.io.IOException;
import java.io.OutputStream;
import java.net.*;
import java.util.Scanner;

public class ClientDemo{
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 10000);
        OutputStream os = socket.getOutputStream();
        os.write("数据".getBytes());
        os.close();
        socket.close();
    }
}

3️⃣TCP接收数据的步骤:

  1. 创建服务器端的Socket对象(ServerSocket)---->ServerSocket(int port)
  2. 监听客户端连接,返回一个Socket对象 ----》Socket accept()
  3. 获取输入流,读数据,并把数据显示在控制台---》InputStream getInputStream()
  4. 释放资源 void close()

服务器端的代码演示:

import java.io.IOException;
import java.io.InputStream;
import java.net.*;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10000);
        Socket accept = serverSocket.accept();
        InputStream is = accept.getInputStream();
        int b;
        while((b=is.read())!=-1){
            System.out.println((char)b);
        }
        is.close();
        serverSocket.close();
    }
}

先运行服务器端,再运行客户端,运行结果如下:

image-20200610020052657

出现乱码的原因是,使用了字节流,当使用(char)进行对带有占2个字节的中文的数据进行强转换时,发送了错误。使用字符流可以解决这个问题。

4️⃣原理剖析:

  1. accept方法是阻塞的,作用是等待客户端连接
  2. 客户端创建对象并连接服务器,此时是通过三次握手协议保证跟服务器之间的连接
  3. 针对客户端来讲,是往外写,所以是输出流,针对服务器来讲,是输入流
  4. read方法也是阻塞的,会一直保持读取的状态,直到读到结束标记
  5. 在关闭流的时候,还多了一个往服务器写结束标记的动作
  6. 最后一步断开连接,是通过四次挥手协议保证连接终止

5️⃣三次握手

6️⃣四次挥手

7️⃣TCP通信程序练习1

练习要求:

  • 客户端:发送数据,接收服务器反馈
  • 服务端:接收数据,给出反馈

客户端代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.*;

public class ClientDemo{
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 10000);
        OutputStream os = socket.getOutputStream();
        os.write("hello".getBytes());
        socket.shutdownOutput();  //仅仅关闭输出流,不影响Socket

        BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
        String line;
        while((line=br.readLine())!=null){
            System.out.println(line);
        }
        os.close();
        socket.close();
    }
}

服务器端的代码:

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.*;

public class ServerDemo {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10000);
        Socket accept = serverSocket.accept();
        InputStream is = accept.getInputStream();
        int b;
        while((b=is.read())!=-1){
            System.out.println((char)b);
        }
        BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        bw.write("你谁啊?");
        bw.flush();

        bw.close();
        is.close();
        accept.close();
        serverSocket.close();
    }
}

先运行服务端,再运行客户端,运行结果如下:

image-20200610022539308

image-20200610022526864

可以看到,客户端收到了服务端的反馈,而且通过转换流解决了中文发送的问题。

8️⃣TCP练习2

练习要求:文件上传

  1. 【客户端】输入流,从硬盘读取文件数据到程序中。
  2. 【客户端】输出流,写出文件数据到服务端。
  3. 【服务端】输入流,读取文件数据到服务端程序。
  4. 【服务端】输出流,写出文件数据到服务器硬盘中。

客户端代码:

public class FileUPload_Client {
	public static void main(String[] args) throws IOException {
        // 1.创建流对象
        // 1.1 创建输入流,读取本地文件  
        BufferedInputStream bis  = new BufferedInputStream(new FileInputStream("test.jpg"));
        // 1.2 创建输出流,写到服务端 
        Socket socket = new Socket("localhost", 6666);
        BufferedOutputStream   bos   = new BufferedOutputStream(socket.getOutputStream());

        //2.写出数据. 
        byte[] b  = new byte[1024 * 8 ];
        int len ; 
        while (( len  = bis.read(b))!=-1) {
            bos.write(b, 0, len);
            bos.flush();
        }
        System.out.println("文件发送完毕");
        // 3.释放资源

        bos.close(); 
        socket.close();
        bis.close(); 
        System.out.println("文件上传完毕 ");
	}
}

服务端代码:

public class FileUpload_Server {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器 启动.....  ");
        // 1. 创建服务端ServerSocket
      	ServerSocket serverSocket = new ServerSocket(6666);
  		// 2. 建立连接 
        Socket accept = serverSocket.accept();
      	// 3. 创建流对象
      	// 3.1 获取输入流,读取文件数据
        BufferedInputStream bis = new BufferedInputStream(accept.getInputStream());
        // 3.2 创建输出流,保存到本地 .
        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("copy.jpg"));
		// 4. 读写数据
        byte[] b = new byte[1024 * 8];
        int len;
        while ((len = bis.read(b)) != -1) {
            bos.write(b, 0, len);
        }
        //5. 关闭 资源
        bos.close();
        bis.close();
        accept.close();
        System.out.println("文件上传已保存");
    }
}
posted @ 2020-08-27 23:41  Whatever_It_Takes  阅读(185)  评论(0编辑  收藏  举报