Java网络编程

目录

一. Socket 编程

二. 基于Udp的回显程序

1.服务器端

2. 客户端

三. 基于Tcp的回显程序

1. 服务器端

2. 客户端


一. Socket 编程

    Socket套接字,是由系统提供用于网络通信的技术,是基于TCP/IP协议的网络通信的基本操作单元。基于Socket套接字的网络程序开发就是网络编程;

    java.net 包中提供了两种常见的网络协议的支持:

  • TCP:TCP(英语:Transmission Control Protocol,传输控制协议) 是一种面向连接的、可靠的、基于字节流的传输层通信协议,TCP 层是位于 IP 层之上,应用层之下的中间层。TCP 保障了两个应用程序之间的可靠通信。通常用于互联网协议,被称 TCP / IP。

  • UDP:UDP (英语:User Datagram Protocol,用户数据报协议),位于 OSI 模型的传输层,一个无连接的协议,提供了应用程序之间要发送数据的数据报。由于UDP缺乏可靠性且属于无连接协议,所以应用程序通常必须容许一些丢失、错误或重复的数据包。


二. 基于Udp的回显程序

1.服务器端

public class UdpServer {

    // 定义一个 soctet 对象
    private DatagramSocket socket = null;

    public UdpServer(int port) throws SocketException {

        //构造 socket ,要绑定相关的端口号
        socket = new DatagramSocket(port);
    }

    //启动服务器
    public void start() throws IOException {
        System.out.println("服务器启动!");
        while (true) {

            // 1.读取请求并解析
            // 构造DatagramPacket包,用来接收
            DatagramPacket requestPacket = new DatagramPacket(new byte[10000], 10000);
            socket.receive(requestPacket);

            //方便处理这个请求,把数据包转成String(这个操作不是非必须得)
            String request = new String(requestPacket.getData(), 0, requestPacket.getLength());
            String response = process(request);

            // 2.把响应结果写到客户端
            DatagramPacket responsePacket = new DatagramPacket(response.getBytes(),
                    response.getBytes().length,
                    requestPacket.getSocketAddress());
            socket.send(responsePacket);
            System.out.printf("[%s:%d] req: %s,resp: %s\n", requestPacket.getAddress().toString(),
                    requestPacket.getPort(), request, response);
        }
    }

    public String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        UdpServer udpServer = new UdpServer(9090);
        udpServer.start();
    }
}

2. 客户端

public class UdpClient {
    private DatagramSocket socket = null;
    private String serverIP;
    private int serverPort;

    public UdpClient(String serverIP, int serverPort) throws SocketException {

        // 客户端不需要显示关联端口,系统自动分配空闲端口
        socket = new DatagramSocket();
        this.serverIP = serverIP;
        this.serverPort = serverPort;
    }

    Scanner scanner = new Scanner(System.in);

    // 客户端和服务器进行多次交互
    public void start() throws IOException {
        while (true) {

            // 1.先从控制读取字符串
            System.out.println("请输入: ");
            String request = scanner.next();

            // 2.把字符串构造DatagramPacket包,用来存储要发送的信息
            DatagramPacket datagramPacket = new DatagramPacket(request.getBytes(), request.getBytes().length,
                    InetAddress.getByName(serverIP), serverPort);

            socket.send(datagramPacket);

            // 3.客户端读取服务器返回的响应
            DatagramPacket responsePacket = new DatagramPacket(new byte[10000], 10000);
            socket.receive(responsePacket);

            // 4.把响应数据转化成String显示出来
            String response = new String(responsePacket.getData(), 0, responsePacket.getLength());
            System.out.printf("req: %s, resp: %s\n", request, response);


        }
    }

    public static void main(String[] args) throws IOException {
        UdpClient udpClient = new UdpClient("127.0.0.1", 9090);
        udpClient.start();

    }
}

步骤:

1.服务器先启动, 等待客户端发送数据,执行到receive,此时服务端进入一个阻塞状态;

2.客户端开始输入操作,并进行send;

3.客户端send之后,走到receive读取响应,会阻塞等待;同时服务器这边就从receive返回,走到process生成响应,再走到send;

4. 客户端收到服务器端send之后发来的数据后,会解除阻塞;服务器进入下一轮循环,走到receive,等待下一个请求;


三. 基于Tcp的回显程序

1. 服务器端

public class TcpServer {

    private ServerSocket serverSocket = null;

    public TcpServer(int port) throws IOException {
        serverSocket = new ServerSocket(port);
    }

    public void start() throws IOException {
        ExecutorService executorService = Executors.newCachedThreadPool();
        System.out.println("服务器启动!");
        while (true) {
            Socket clientSocket = serverSocket.accept();
            //写法1
            // 每次来一个新的客户端,都创建一个心得线程
            /*Thread thread = new Thread(()->{
                try {
                    processConnect(clientSocket);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });
            thread.start();*/

            //写法2,使用线程池
            executorService.submit(new Runnable() {
                @Override
                public void run() {
                    try {
                        processConnect(clientSocket);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            });

        }
    }

    private void processConnect(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d] req: 客户端上线\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        try (InputStream inputStream = clientSocket.getInputStream();
             OutputStream outputStream = clientSocket.getOutputStream()) {
            Scanner scanner = new Scanner(inputStream);
            PrintWriter printWriter = new PrintWriter(outputStream);

            while (true) {
                // 1.读取请求
                if (!scanner.hasNext()) {
                    // 读取的流到了结尾了
                    System.out.printf("[%s:%d] 客户端下线!", clientSocket.getInetAddress().toString(),clientSocket.getPort());
                    break;
                }
                String request = scanner.next();
                // 2.根据请求计算响应
                String response = process(request);
                // 3.把响应写回到客户端
                printWriter.println(response);
                System.out.printf("[%s:%d] req: %s;resp: %s\n",clientSocket.getInetAddress().toString(),clientSocket.getPort()
                ,request,response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            clientSocket.close();
        }

    }

    private String process(String request) {
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpServer tcpServer = new TcpServer(9090);
        tcpServer.start();
    }

}

2. 客户端

public class TcpClient {
    private Socket socket = null;

    public TcpClient(String serverIP, int port) throws IOException {
        //服务器和客户端建立连接
        socket = new Socket(serverIP, port);
    }

    public void start() {
        Scanner scanner = new Scanner(System.in);
        try (OutputStream outputStream = socket.getOutputStream();
             InputStream inputStream = socket.getInputStream()) {
            PrintWriter printWriter = new PrintWriter(outputStream);
            Scanner scannerFromSocket = new Scanner(inputStream);
            while (true) {

                // 1.从键盘上读取用户输入的内容
                System.out.println("请输入:");
                String request = scanner.next();

                // 2.读取的内容构造成请求,发送给服务器
                //这里只是把数据写到内存的缓存区,等到缓存区满了,才会写到网卡
                printWriter.println(request);
                //手动刷新缓冲区
                printWriter.flush();

                // 3.从服务器读取响应内容
                String response = scannerFromSocket.next();

                // 4.把响应结果显示到控制台上
                System.out.printf("req: %s;resp:%s\n", request, response);
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    public static void main(String[] args) throws IOException {
        TcpClient tcpClient = new TcpClient("127.0.0.1",9090);
        tcpClient.start();
    }

}

步骤:

1. 服务器先执行strat方法,执行到accept这里进入阻塞状态,等待客户端建立连接

2.客户端启动,和服务器建立连接,连接成功之后,服务器的accept就会返回;

3.服务器尝试从客户端读取请求,此时会进入阻塞状态

4.客户端从控制台读取用户输入,输入完之后,客户端开始发送请求出去,同时读取服务器响应,进入阻塞状态;

5.服务器收到客户端的请求之后,把响应写回到客户端;同时客户端收到服务器的响应,就可以处理数据了;

6.双方都进入下一次循环

你可能感兴趣的:(JAVA,网络,java)