Java Socket 使用

使用Socket进行网络编程时,本质上就是两个进程之间的网络通信。

其中一个进程必须充当服务器端,它会主动监听某个指定的端口;另一个进程必须充当客户端,它必须主动连接服务器的IP地址和指定端口,如果连接成功,服务器端和客户端就成功地建立了一个TCP连接,双方后续就可以随时发送和接收数据。

因此,当Socket连接成功地在服务器端和客户端之间建立后:

  • 对服务器端来说,它的Socket是指定的IP地址和指定的端口号;
  • 对客户端来说,它的Socket是它所在计算机的IP地址和一个由操作系统分配的随机端口号。

accept()
accept() 表示每当有新的客户端连接进来后,就返回一个Socket实例,这个Socket实例就是用来和刚连接的客户端进行通信的。

如果没有客户端连接进来,accept()方法会阻塞并一直等待。如果有多个客户端同时连接进来,ServerSocket 会把连接扔到队列里,然后一个一个处理。对于Java程序而言,只需要通过循环不断调用 accept() 就可以获取新的连接。

这里线程池中固定线程3条,能处理3个客户端的连接。未连接上的会被 ServerSocket 扔到队列中,等待一个一个处理。

flush()
当Socket连接创建成功后,无论是服务器端,还是客户端,我们都使用Socket实例进行网络通信。因为TCP是一种基于流的协议,因此,Java标准库使用InputStream和OutputStream来封装Socket的数据流,这样我们使用Socket的流,和普通IO流类似。

如果不调用flush(),我们很可能会发现,客户端和服务器都收不到数据,这并不是Java标准库的设计问题,而是我们以流的形式写入数据的时候,并不是一写入就立刻发送到网络,而是先写入内存缓冲区,直到缓冲区满了以后,才会一次性真正发送到网络,这样设计的目的是为了提高传输效率。如果缓冲区的数据很少,而我们又想强制把这些数据发送到网络,就必须调用flush()强制把缓冲区数据发送出去。

public class ServerByThreadPool {
    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = new ServerSocket(10003);
        System.out.println("ServerSocket 正在运行...");

        ExecutorService executorService = Executors.newFixedThreadPool(3);
        while(true) {
            final Socket socket;
            final SocketAddress socketAddress;
            try {
                // 阻塞并一直等待客户端连接
                socket = serverSocket.accept();
                socketAddress = socket.getRemoteSocketAddress();
            } catch (IOException e) {
                e.printStackTrace();
                break;
            }

            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try (
                            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
                            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
                    ){
                        // 换行符 \n 标识告诉流已经输出完毕
                        writer.write("已成功连接!\n");
                        // 发送给客户端
                        writer.flush();

                        String line = "";
                        // readLine() IO阻塞
                        while ((line = reader.readLine()) != null) {
                            System.out.println(">>>>>>>>>>");
                            System.out.println("客户端 " + socketAddress +" 说:" + line);
                            System.out.println("为客户端 " +  socketAddress +" 服务的线程:" + Thread.currentThread().getName());
                            System.out.println("<<<<<<<<<<<");

                            // 客户端发送bye,则退出并关闭socket
                            if (line.equals("bye")) {
                                writer.write("bye\n");
                                writer.flush();
                                break;
                            } else {
                                writer.write("已接收!\n");
                                writer.flush();
                            }
                        }
                    }catch (Exception e) {
                        e.printStackTrace();
                    }finally {
                        try {
                            socket.close();
                        } catch (IOException ioe) {
                            ioe.printStackTrace();
                        }
                    }
                }
            });
        }

        executorService.shutdown();
        serverSocket.close();
    }
}

客户端

这里等待用户输入信息,然后发送给服务端。

public class Client {
    public static void main(String[] args) throws Exception {
        Socket socket = new Socket("localhost", 10003);
        SocketAddress socketAddress = socket.getRemoteSocketAddress();

        try (
                BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8));
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8));
        ){

            System.out.println("服务端 " + socketAddress + " 说 : " + reader.readLine());
            
            Scanner scanner = new Scanner(System.in);
            while(true) {
                System.out.println(">>>>>>>>>>");
                // 等待用户输入
                String line = scanner.nextLine();

                writer.write(line);
                // 写一个行分隔符,标识告诉流已经输出完毕
                writer.newLine();
                writer.flush();

                String response = reader.readLine();
                System.out.println("服务端 " + socketAddress + " 说 : " + response);
                System.out.println("<<<<<<<<<<<");
                if (response.equals("bye")) {
                    break;
                }
            }
        }finally {
            socket.close();
        }
    }
}

测试
启动三个客户端
在这里插入图片描述
再启动一个客户端,线程池满了,在 ServerSocket 中等待被处理
在这里插入图片描述
关闭客户端1,客户端4就连上了
在这里插入图片描述
在这里插入图片描述

参考:
网络编程 教程

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值