TCP协议(1)

TCP全称为 “传输控制协议(Transmission Control Protocol”). 人如其名, 要对数据的传输进行一个详细的控制;


确认应答(ACK)机制
在这里插入图片描述
每一个ACK都带有对应的确认序列号, 意思是告诉发送者, 我已经收到了哪些数据; 下一次你从哪里开始发


超时重传机制
在这里插入图片描述

  • 主机A发送数据给B之后, 可能因为网络拥堵等原因, 数据无法到达主机B;
  • 如果主机A在一个特定时间间隔内没有收到B发来的确认应答,就会进行重发;

但是还有一种情况是主机A未收到B发来的确认应答,也可能是因为ack丢失了
在这里插入图片描述
因此主机B会收到很多重复数据. 那么TCP协议需要能够识别出那些包是重复的包, 并且把重复的丢弃掉.
这时候我们可以利用前面提到的序列号, 就可以很容易做到去重的效果


连接管理机制
在正常情况下,TCP要经过三次握手建立连接,四次挥手断开连接


实现TCP服务器

class TCPServer{
    public static void main(String[] args) throws IOException {
        //监听socket
        ServerSocket serverSocket = new ServerSocket(8888);
        while (true){
            //双方通信socket 
            System.out.println("等待client连接");
            Socket socket = serverSocket.accept();
            System.out.println("由client连接上来");
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            PrintWriter printWriter = new PrintWriter(
                    new OutputStreamWriter(os,"UTF-8"),
                    false
            );
            Scanner scanner = new Scanner(is,"UTF-8");
            while (scanner.hasNext()){
                String message = scanner.nextLine();
                System.out.println("收到对方消息" + message);
                String responseMessage = message;
                System.out.println("发给对方的消息" + message);
                printWriter.println(responseMessage);
                printWriter.flush();
            }
            socket.close();
        }
    }
}

cmd命令窗口 telnet127.0.0.1
ctrl + ] 停止


Client客户端

class Client{
    //客户端
    public static void main(String[] args) throws IOException {
//        String messages = "Cat\r\ndog\r\n";
        Socket socket = new Socket("127.0.0.1",8888);

        InputStream is = socket.getInputStream();
        OutputStream os = socket.getOutputStream();

        Scanner 读本地用户准备发送的Scanner = new Scanner(System.in);
        Scanner 读Server发送的Scanner = new Scanner(is, "UTF-8");

        while (true) {
            System.out.println("请提交命令");
            String messages = 读本地用户准备发送的Scanner.nextLine();
            byte[] sendBuffer = messages.getBytes("UTF-8");
            os.write(sendBuffer);
            os.write('\r');
            os.write('\n');
            //读
            System.out.println(读Server发送的Scanner.nextLine());
        }
//        socket.close();
    }
}

同时启动

服务器
等待client连接
由client连接上来
收到对方消息Cat
发给对方的消息Cat
收到对方消息dog
发给对方的消息dog

客户端
Cat
dog


TCP短链接

package package1225;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;

public class TCPShortConnection {
}
class Server2{
    public static void main(String[] args)  throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        while (true){
            System.out.println("等待连接");
            Socket socket = serverSocket.accept();
            System.out.println("连接建立成功");
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();
            PrintWriter printWriter = new PrintWriter(
                    new OutputStreamWriter(os,"UTF-8"),
                    false
            );
            Scanner scanner = new Scanner(is,"UTF-8");
            System.out.println("等待对方输入");
            String message = scanner.nextLine();
            System.out.println("接受了对方的输入" + message);
            String echoMessage = message;
            printWriter.println(echoMessage);
            printWriter.flush();

            socket.shutdownInput();
        }
    }
}
class Client2{
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);

        while (true){
            Socket socket = new Socket("127.0.0.1",8888);//不停键连接
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();

            String message = scanner.nextLine();
            message = message + "\r\n";
            os.write(message.getBytes("UTF-8"));

            Scanner TcpScaner = new Scanner(is,"UTF-8");
            System.out.println(TcpScaner.nextLine());

            socket.close();
        }
    }
}

TCP长连接

public class Server {
    private static class Woker implements Runnable{
        private final Socket socket;
        Woker(Socket socket){
            this.socket = socket;
        }
        @Override
        public void run() {
            try {
                InputStream is = socket.getInputStream();
                OutputStream os = socket.getOutputStream();
                Scanner scanner = new Scanner(is,"UTF-8");
                PrintStream out = new PrintStream(os,false,"UTF-8");//写

                while (scanner.hasNext()){
                    System.out.println(Thread.currentThread().getName() + " 等待客户端发送消息");
                    String message = scanner.nextLine();
                    System.out.println(Thread.currentThread().getName() + " 收到消息" + message);
                    String echoMessage = message;
                    out.println(echoMessage);
                }
            }catch (IOException e){
                e.printStackTrace();
            } finally {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(8888);
        int i = 0;
        while (true){
            System.out.println("main:等待连接");
            Socket socket = serverSocket.accept();//accept 出来的连接通信的socket
            System.out.println("main: 连接建立");
            Thread thread = new Thread(new Woker(socket),"工作人员( " + i++ + " )");
            thread.start();

        }
    }
}
class Client2{
    public static void main(String[] args) throws IOException {
        Scanner scanner = new Scanner(System.in);

        while (true){
            Socket socket = new Socket("127.0.0.1",8888);//不停键连接
            InputStream is = socket.getInputStream();
            OutputStream os = socket.getOutputStream();

            String message = scanner.nextLine();
            message = message + "\r\n";
            os.write(message.getBytes("UTF-8"));

            Scanner TcpScaner = new Scanner(is,"UTF-8");
            System.out.println(TcpScaner.nextLine());

            socket.close();
        }
    }
}

用线程池来解决

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

        ServerSocket serverSocket = new ServerSocket(8888);
        BlockingQueue<Runnable> queue = new LinkedBlockingDeque<>();
        ExecutorService pool = new ThreadPoolExecutor(
                //线程池
                10,1000,1, TimeUnit.SECONDS,queue
        );
        int i = 0;
        while (true){
            System.out.println("main:等待连接");
            Socket socket = serverSocket.accept();//accept 出来的连接通信的socket
            System.out.println("main: 连接建立");
            pool.execute(new Woker(socket));
        }
    }

1UDP面向报文 无连接
只要读即可(无连接),读到的数据包一定是发送的数据(面向报文的特点)
.
2.TCP 面向连接,面向流
先accept然后read(面向连接),读到的数据可能不是你发送时的样子(面向流)

1.面向流
数据分割(1.通过特殊字符分隔\r\n 2.带上长度 3.通过关闭连接通知你结束了)
2.有连接
写server accept()上可能阻塞/read()可能阻塞(没人进来,没人发)
解决方案:线程池解决

-1.建立socket
2.bind本地ip+本地端口
3.listen           
ServerSocket(8888)
while(true):
    4.等待客户端连接
    Socket socket = severSocket.accept();
    5.把socket交给线程池去处理
    线程池任务:
       while()
         1.从socket中读取一行数据 scanner.nextLine()
         2.进行业务处理(echo|字典|计算器)
         3.把结果包装成消息(尾巴添加\r\n)
         4.写入消息 out.println(message)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值