特点:面向连接,可靠通信

目的:保证在不可靠的信道上实现可靠传输

三个步骤:三次握手建立连接(全手工,三次连接是指1.客户端向服务器端发出连接请求,2.服务器端返回响应,3.客户端再次发出确认信息,建立连接,确认双方能发能收),传输数据进行确认,四次挥手断开连接(1.客户端发送断开请求,2.服务器端返回稍等响应,3.服务器端返回响应确认断开,4.客户端发出正式断开连接。确保双方收发数据都已完成)。

Java提供了一个java.net.Socket类来实现

TCP通信_输入流

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建Socket对象,并把请求与服务端的端口连接
        Socket socket = new Socket("127.0.0.1", 8888);

        // 2. 从socket通信管道中得到一个字节输出流,用来发送数据给服务端的数据
        OutputStream os = socket.getOutputStream();

        // 3. 把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        // 4. 开始写数据出去了
        dos.writeUTF("在一起,好吗?");
        dos.close();
        
        socket.close();
    }
}

TCP通信_System_02

public class Server {
    public static void main(String[] args) throws Exception {
        // 1. 创建ServerSocket的对象, 同时为服务端指定端口。
        ServerSocket serverSocket = new ServerSocket(8888);

        // 2. 使用serverSocket对象, 调用一个accept方法, 等待客户端的连接请求到来。
        Socket socket = serverSocket.accept();

        // 3. 从socket通信管道中得到一个字节输入流。
        InputStream is = socket.getInputStream();

        // 4. 把低级的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        // 5. 使用数据输入流读取客户端发送过来的消息
        String rs = dis.readUTF();
        System.out.println(rs);

        // 实际开发中可以获取客户端的IP地址
        System.out.println(socket.getRemoteSocketAddress());

        dis.close();
        socket.close();
    }
}

多发多收

public class Client {
    public static void main(String[] args) throws Exception {
        // 1. 创建Socket对象,并把请求与服务端的端口连接
        Socket socket = new Socket("127.0.0.1", 8888);

        // 2. 从socket通信管道中得到一个字节输出流,用来发送数据给服务端的数据
        OutputStream os = socket.getOutputStream();

        // 3. 把低级的字节输出流包装成数据输出流
        DataOutputStream dos = new DataOutputStream(os);

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请说:");
            String msg = sc.nextLine();
        
            // 一旦用户输入了exit,就退出客户端程序
            if ("exit".equals(msg)) {
                System.out.println("欢迎您下次光临!退出成功!");
                dos.close();
                socket.close();
                break;
            }
        
            // 4. 开始写数据出去
            dos.writeUTF(msg);
            dos.flush();
        }

    }
}
public class Server {
    public static void main(String[] args) throws Exception {
        // 1. 创建ServerSocket的对象, 同时为服务端指定端口。
        ServerSocket serverSocket = new ServerSocket(8888);

        // 2. 使用serverSocket对象, 调用一个accept方法, 等待客户端的连接请求到来。
        Socket socket = serverSocket.accept();

        // 3. 从socket通信管道中得到一个字节输入流。
        InputStream is = socket.getInputStream();

        // 4. 把低级的字节输入流包装成数据输入流
        DataInputStream dis = new DataInputStream(is);

        // 5. 使用数据输入流读取客户端发送过来的消息
        while (true) {
            String rs = dis.readUTF();
            System.out.println(rs);
        }


    }
}

客户端停止运行,服务端会报错。使用try catch

while (true) {
    try {
        // 5. 使用数据输入流读取客户端发送过来的消息
        String rs = dis.readUTF();
        System.out.println(rs);
    } catch (Exception e) {
        System.out.println(socket.getRemoteSocketAddress() + " 断线了!");
        dis.close();
        socket.close();
        break;
    }
}

主程序只有一个主线程,不可以与多个客户端进行通信。

TCP与多个客户端通信

服务端

public class server {
    public static void main(String[] args) throws Exception {

        ServerSocket serverSocket = new ServerSocket(8080);


        // 5. 使用数据输入流读取客户端发送过来的消息
        while (true) {

        Socket socket = serverSocket.accept();
        System.out.println( socket.getRemoteSocketAddress() + "客户端连接成功");
        new ServerReaderThread(socket).start();


    }
}



    }

端口

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;

public class ServerReaderThread extends Thread {
    private  Socket socket;

    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {

        try {
            InputStream inputStream = socket.getInputStream();
            DataInputStream dataInputStream = new DataInputStream(inputStream);
            while (true) {
                try {
                    String message = dataInputStream.readUTF();
                    System.out.println("Server received message: " + message);
                } catch (IOException e) {
                    System.out.println("Server reader thread stopped."+socket.getRemoteSocketAddress());
                    dataInputStream.close();
                    inputStream.close();
                    socket.close();
                    break;
                }
            }
        } catch (IOException e) {
        }
    }
}