TCP流套接字编程②

客户端代码的实现

代码:

public class TcpEchoClient {
    private Socket socket = null;
    public TcpEchoClient(String serverIp,int serverPort) throws IOException {
        socket = new Socket(serverIp,serverPort);
    }
    public void start(){
        System.out.println("客户端启动!");
        try (InputStream inputStream = socket.getInputStream();
             OutputStream outputStream = socket.getOutputStream();
             Scanner scannerConsole = new Scanner(System.in);
             Scanner scannerNetwork = new Scanner(inputStream);
             PrintWriter writer = new PrintWriter(outputStream)){
            //这里的流程和UDP类似
            while (true){
                //1.从控制台读取输入的字符串
                if (!scannerConsole.hasNext()){
                    break;
                }
                System.out.println("->");
                String request = scannerConsole.next();
                //2.把请求发给服务器,这里需要使用println来发送,为了让发送的末尾有\n
                writer.println(request);
                //通过flush主动刷新缓冲区,确保数据真的发出去
                writer.flush();
                //3.从服务器读取响应
                String response = scannerNetwork.next();
                //4.把响应显示出来
                System.out.println(response);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) throws IOException {
        TcpEchoClient client = new TcpEchoClient("127.0.0.1",9090);
        client.start();
    }
}

分析:

客户端退出之后,服务器就能感知到“客户端下线”操作。

        客户端退出的时候,就会触发tcp的“断开连接”,服务器这边的代码能感知到,对应的Scanner能够在hasNext中返回false。

        writer.println(request):IO操作都是比较低效的操作,希望能够让低效操作进行的尽量少一些。引入缓冲区(内存)先把要写入网卡的数据放到内存缓冲区中,等到攒一波之后,再统一进行发送(把多次IO合并成一次)

        但是存在问题,如果发送的数据很少,由于缓冲区还没满,数据就呆在缓冲区里。

        手动刷新缓冲区:flush()方法

步骤:

                                                                               

                                                                 

                                                            

                                                                                            

        System.out.println("服务器启动!");
        while (true){
            //通过accept方法来“接听电话”,然后才能通信
            Socket clientSocket = serverSocket.accept();
            processConnection(clientSocket);
        }

        第一个客户端连上服务器之后,服务器就会从accept这里返回。(解除阻塞)进入到processConnection中。接下来就会在scanner.hasNext这里阻塞等待客户端的请求。客户端请求到了之后,scanner.hasNext返回,继续执行,读取请求。根据请求计算相应,返回响应给客户端.....执行完上述一轮操作之后,循环回来再次继续在hasNext阻塞,等待下一个请求

        直到客户端退出之后,连接结束,此时循环才会退出。

while (true){
    Scanner scanner = new Scanner(inputStream);
    if(!scanner.hasNext()){
        //读取完毕,客户端断开连接,就会产生读取完毕
        System.out.printf("[%s:%d]客户端下线!",clientSocket.getInetAddress(),
                   clientSocket.getPort());
        break;
    }

服务器代码在执行里层循环的时候无法执行到第二次accept。

        虽然第二个客户端和服务器在内核层面上建立了连接,是但是应用程序这里无法把连接拿到应用程序处理

        如果第一个客户端退出了,第二个客户端之前发的请求啥的就立即被处理,没被丢掉。

        当前TCP在内核中,每个socket都是有缓冲区的。客户端发送的数据确实发了,服务器也收到了,只不过数据在服务器的接收缓冲区。一旦第一个客户端退出了,回到第一层循环,继续执行第二次accept,继续执行next就能把之前缓冲区的内容给读出来。

流程:

        主循环:通过accept获取到连接,得到clientSocket。针对这个连接再进行一次循环,读取请求并解析,根据请求计算响应,把响应写回客户端。

长连接:每个客户端和服务器之间进行了多次的交互操作。

短连接:一个连接只进行一次请求响应交互。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值